资讯动态

2026.10.19面试题

发布时间:2026/10/27 18:47:08 来源:尧图企业网站定制
1、消息队列如何保证消息不丢生产者端关键业务同步发送并检查返回值失败重试。RabbitMQ 开 Publisher ConfirmKafka 设acksall。RocketMQ 用同步发送同步发送会阻塞等待 Broker 响应。兜底是本地消息表 定时补偿这是最终一致性的起点。Broker 端RabbitMQ 交换机、队列、消息三者持久化配合 confirm 确认落盘再用镜像或仲裁队列做冗余Kafka 靠多副本配replication.factor3、min.insync.replicas2、关掉 unclean 选举防止落后副本被选为主导致数据截断ISR 全写才算成功RocketMQ 核心业务同步刷盘 同步复制主从都落盘才返回这是用性能换可靠性。消费者端关自动 ack业务执行完再手动确认。可重试错误走重试队列耗尽进死信队列 告警 人工介入不可重试错误落库 告警不能只落库否则等于换个地方丢。手动 ack 必然带来重复消费所以消费端必须幂等用生产端生成的全局唯一 ID 配合 Redis SETNX 或数据库唯一索引去重。边界这套机制只能把丢失概率降到极低做不到绝对零丢失——副本全挂、磁盘损坏、误删都防不住。工程上追求的是可接受的低概率 业务兜底。2、什么是进程和线程进程和线程的区别进程是操作系统进行资源分配的基本单位。一个进程就是一段程序的一次运行实例它拥有独立的地址空间、文件描述符、内存等资源。进程之间是隔离的一个进程崩了通常不影响另一个。线程是CPU调度和执行的基本单位是进程内部的一条执行流。一个进程可以包含多个线程多个线程共享进程的地址空间和资源但各自有独立的程序计数器、栈和寄存器。区别第一进程有独立的地址空间线程共享所属进程的资源只独享栈和寄存器这类私有数据。第二创建和销毁进程开销大要分配地址空间、页表线程轻量得多。切换也一样进程切换要换页表、刷 TLB线程切换主要换栈和寄存器快很多。第三进程间通信要靠 IPC比如管道、消息队列、共享内存、socket因为地址空间隔离线程直接读写共享内存就行但正因如此要加锁保证同步否则会有竞态。第四进程隔离性好一个崩了不影响别人线程共享地址空间一个线程野指针可能把整个进程搞崩所以多线程程序对并发安全要求更高。3、进程间通信方式有哪些第一管道Pipe。分匿名管道和命名管道。匿名管道只能用于有亲缘关系的进程比如父子进程本质是内核里的一块缓冲区半双工数据读完就没了。命名管道FIFO有文件名可以用于无亲缘关系的进程。特点是简单但只能传字节流容量有限。第二消息队列Message Queue。内核维护的消息链表进程可以按类型收发消息。相比管道它能传结构化消息、支持优先级、生命周期随内核不随进程。缺点是数据要在内核和用户态之间拷贝大流量下性能一般。第三共享内存Shared Memory。多个进程映射同一块物理内存直接读写是最快的 IPC 方式因为省掉了拷贝。但共享内存本身不提供同步必须配合信号量或互斥锁使用否则会有竞态。第四信号量Semaphore。它主要不是传数据而是做同步和互斥控制多个进程对共享资源的访问。常和共享内存搭配用。第五信号Signal。一种异步通知机制比如SIGKILL、SIGTERM。它只能传一个信号编号不能传数据主要用于事件通知比如进程终止、定时器到期。第六Socket。最通用的一种既能本机通信Unix Domain Socket也能跨主机通信TCP/UDP Socket。跨机场景基本只能靠它。选型上我一般这么看传大量数据、追求性能用共享内存 信号量简单传字节流、有亲缘关系用管道要结构化消息、解耦用消息队列只是事件通知用信号跨机器用Socket。另外现代语言里很多用 Unix Domain Socket 做本机高性能通信比 TCP 回环还快。4、为什么 MySQL 采用 B 树作为索引MySQL 选 B 树本质上是因为数据在磁盘上磁盘 I/O 极慢B 树能把一次查询的磁盘 I/O 压到 3~4 次同时还支持范围查询和排序。先说为什么不用别的结构。哈希索引等值查询是 O(1)但数据是无序散列的范围查询、排序、前缀匹配都做不了只能全表扫。红黑树、AVL 树虽然是 O(log n)但每个节点只存一个键千万级数据树高会到二三十层每下一层基本就是一次磁盘 I/O太慢。B 树非叶子节点也存数据导致单页能放的键变少树更高而且数据散落在各层范围查询要来回回溯父节点效率差。B 树赢在两点。第一非叶子节点只存索引键和子节点指针不存真实数据一个 16KB 的页能塞下上千个键树被压得很矮千万级数据通常只要 3 层查询稳定 3 次 I/O。第二所有数据都在叶子节点且叶子之间用双向链表串起来范围查询定位到起点后顺着链表顺序扫就行天然契合 ORDER BY、GROUP BY、分页这些场景。5、如何评估 / 判断索引是否生效常见索引失效场景有哪些判断索引是否生效最直接的办法就是EXPLAIN看执行计划。先看key为 NULL 就是没走索引再看type理想状态是const、ref、range出现ALL就是全表扫描index是全索引扫描基本也没用好。rows和filtered能看出扫描代价Extra里出现Using index说明命中覆盖索引不用回表出现Using filesort或Using temporary说明排序分组没吃上索引。MySQL 8.0.18 可以用EXPLAIN ANALYZE直接看真实耗时和行数比估算值更准。常见失效场景主要有这些。对索引列套函数或做运算比如DATE(create_time) 2025-01-01破坏了 B 树的有序性改成范围查询就能解决。隐式类型转换varchar 字段传数字进去MySQL 会把索引列转数字等于对列做了运算索引直接废掉这是最隐蔽的坑。联合索引不遵循最左前缀跳了最左列或者中间用了范围查询后面的列就用不上。LIKE 左模糊%abc没法从 B 树前缀定位右模糊abc%没问题。OR 条件里只要有一列没索引优化器可能直接全表扫拆成UNION ALL各自走索引更稳。不等于、NOT IN、IS NOT NULL 这类反向条件如果匹配数据量太大优化器算下来觉得回表成本高于全表扫会主动放弃索引。索引选择性太低比如性别只有两个值查出来占全表 20%~30% 以上优化器也会放弃。最后大量增删改后统计信息过期优化器可能误判跑一下ANALYZE TABLE刷新就行。SELECT *本身不会让索引失效但如果回表成本太高优化器会权衡后选择全表扫所以尽量用覆盖索引减少回表。6、如何监控并优化慢 SQL监控定位主要靠慢查询日志和实时状态。生产环境开启slow_query_loglong_query_time一般设 1 秒核心链路可以压到 0.5 秒再配合min_examined_row_limit过滤小表查询。 日志分析用mysqldumpslow看概览真正排查用pt-query-digest按 SQL 指纹聚合优先盯总耗时最高、扫描行数远大于返回行数的那类 SQL。 线上突发时直接跑SHOW FULL PROCESSLIST看Threads_running是否飙升、有没有长事务或锁等待。定位到 SQL 后跑EXPLAIN先看type至少要到range核心业务争取ref出现ALL必须处理。key为空说明索引没生效rows很大说明扫描代价高Extra里Using filesort、Using temporary、Using index分别对应排序/临时表/覆盖索引能直接判断优化方向。 MySQL 8.0 还可以用EXPLAIN ANALYZE看真实耗时分布。优化时优先改 SQL 和索引。索引列不要套函数或做运算比如DATE(create_time) ?改成范围查询varchar 传参要和字段类型一致避免隐式转换联合索引遵循最左前缀等值列放前面范围列和排序列放后面。 深分页用游标分页或延迟关联替代大 OFFSETSELECT *改成明确字段尽量走覆盖索引减少回表子查询能改 JOIN 就改 JOIN大事务拆成小批次。 如果执行计划没问题但依然慢再看innodb_buffer_pool_size、缓冲池命中率、锁竞争和统计信息是否过期。上线前必须重新EXPLAIN确认执行计划改善再在测试环境压测对比耗时和扫描行数大表加索引用pt-osc或gh-ost避免阻塞优化后定期ANALYZE TABLE刷新统计信息。慢 SQL 治理不是加索引就完事核心是“少扫描、少回表、少排序、少锁等待”再配上持续的慢查询监控闭环。7、事务隔离级别有哪些四种隔离级别是读未提交、读已提交、可重复读、串行化。读未提交能读到别人没提交的数据脏读、不可重复读、幻读全可能发生生产基本不用。读已提交只能读到已提交的数据解决了脏读但同一事务里两次读同一行可能不一样也就是不可重复读Oracle 默认用这个级别。可重复读是 MySQL InnoDB 的默认级别事务内多次读结果一致解决了脏读和不可重复读理论上还可能有幻读但 InnoDB 靠 MVCC 加 Next-Key 锁在大部分场景下也挡住了幻读。串行化最严格所有读写都串行执行三种问题全解决但并发最差几乎没人用。关键区分点是脏读是读到未提交的修改不可重复读是同一行被改了幻读是范围内多了或少了行。实现上RC 每次查询都生成新的 ReadViewRR 只在事务第一次查询时生成一次并全程复用这就是两者在可重复读上的本质差异。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑