面试追问地图

主问题必讲关键点下一层追问
通用排障影响、止损、分层、证据、复盘为什么先保现场、何时重启
CPU 高进程、线程、栈、代码热点GC 高还是业务计算高
线程池耗尽活跃数、队列、阻塞点扩大线程池为何可能更糟
内存上涨堆/非堆/native、引用链泄漏与正常缓存如何区分
Full GC分配、晋升、回收效果大对象、元空间、晋升失败
接口超时分位延迟、Trace、池化资源单实例/全局、重试放大
慢 SQL慢日志、计划、扫描、锁参数不同为何计划不同
Redis 延迟慢命令、大 Key、fork、网络单分片热点如何迁移
MQ 积压生产/消费速率、失败消息临时扩容后的顺序和幂等
发布故障变更对比、灰度、回滚数据库变更无法回滚怎么办
死锁排查线程 dump、锁顺序、等待图死锁 vs 活锁、jstack 分析

排障题必须给出“下一条命令或下一张图看什么”,避免只说笼统的检查日志和监控。


一、通用排障方法

线上问题的通用排查流程?

难度 🔴

确认现象 → 判断影响 → 先止损 → 分层定位 → 验证根因 → 修复与复盘
  1. 确认现象:时间范围、错误码、受影响接口、用户和机房。
  2. 判断影响:全部请求还是部分请求,单实例还是集群。
  3. 先止损:回滚、降级、限流、扩容、切流或关闭非核心功能。
  4. 分层定位:客户端、网关、应用、缓存、数据库、MQ、下游、基础设施。
  5. 验证根因:用日志、指标、Trace、复现或对照实验形成证据链。
  6. 修复复盘:区分临时恢复和长期治理。

排障时先保留现场,避免一开始就重启服务导致关键证据丢失。

如何快速判断问题在哪一层?

现象优先检查
所有接口都慢CPU、GC、线程池、网络、公共下游
单接口慢Trace、业务日志、SQL、远程调用
单实例异常实例日志、机器资源、配置差异
集群整体异常流量、依赖服务、数据库、缓存
错误率突然上涨发布变更、配置变更、下游故障
延迟上涨但错误率稳定慢 SQL、锁竞争、连接池、资源饱和

排障为什么要同时看日志、指标和 Trace?

  • 日志:解释具体请求发生了什么。
  • 指标:判断问题规模、趋势和资源瓶颈。
  • Trace:定位调用链中耗时或报错的节点。

三者结合才能从“哪里异常”走到“为什么异常”。


二、CPU 与线程问题

Java 进程 CPU 飙高怎么排查?

top 找进程

top -H -p <pid> 找高 CPU 线程

将线程 ID 转为十六进制

jstack <pid> 中匹配 nid

结合代码、火焰图和调用频率定位

常见原因:

  • 死循环或高频空轮询。
  • 正则表达式回溯。
  • 大量序列化、压缩或加密计算。
  • 频繁 GC。
  • 锁竞争导致线程自旋。
  • 流量突增或批处理任务同时执行。

线程池耗尽有什么表现?

  • 活跃线程数达到最大值。
  • 队列持续增长或拒绝任务。
  • 接口延迟上涨,CPU 不一定很高。
  • 大量线程停在远程调用、数据库或锁等待。

处理顺序:

  1. 找出线程在等待什么。
  2. 检查下游超时、连接池和慢 SQL。
  3. 必要时限流、降级或隔离故障依赖。
  4. 不要只通过扩大线程池掩盖阻塞问题。

如何排查死锁?

  • jstack 查看 Found one Java-level deadlock
  • 分析线程持有的锁和等待的锁。
  • 统一加锁顺序,缩小锁粒度。
  • 避免锁内执行网络调用或长耗时操作。
  • 必要时使用带超时的 tryLock

三、内存与 GC

内存持续上涨怎么排查?

先区分:

  • Java 堆。
  • 元空间。
  • 直接内存。
  • 线程栈。
  • native 内存或 mmap。

常用步骤:

  1. 查看堆、GC 和进程 RSS 趋势。
  2. 使用 jstat 判断各代增长和 GC 频率。
  3. 使用 jmap 或诊断工具导出堆快照。
  4. 用 MAT 分析大对象、引用链和支配树。
  5. 检查缓存、集合、ThreadLocal、监听器和类加载器。

频繁 Full GC 怎么排查?

常见原因:

  • 老年代空间不足。
  • 大对象直接进入老年代。
  • 元空间不足触发回收。
  • 内存泄漏导致对象无法释放。
  • 堆设置不合理或晋升失败。

不能只调大堆。应结合 GC 日志确认对象分配速率、晋升情况、停顿原因和回收效果。

OOM 发生后要保留什么信息?

  • OOM 类型和完整异常栈。
  • 堆转储文件。
  • GC 日志。
  • 当时的流量、发布和配置变更。
  • 进程内存、容器限制和系统日志。

建议提前配置 OOM 自动导出堆快照,但要预留磁盘空间并保护敏感数据。


四、接口超时与依赖故障

接口突然变慢怎么排查?

难度 🔴

  1. 查看延迟分位数、错误率和流量是否同时变化。
  2. 通过 Trace 拆分网关、应用、SQL、缓存和远程调用耗时。
  3. 检查线程池、连接池和队列是否饱和。
  4. 检查慢 SQL、锁等待、缓存未命中和下游超时。
  5. 核对近期发布、配置、数据量和流量变化。

重试为什么可能放大故障?

下游变慢时,如果每层都立即重试,会增加下游负载并占用更多线程,形成重试风暴。

治理方式:

  • 设置明确的连接和读取超时。
  • 只对可重试错误重试。
  • 限制次数,采用指数退避和随机抖动。
  • 保证写操作幂等。
  • 配合熔断、限流和隔离。

连接池耗尽怎么处理?

排查:

  • 活跃连接、空闲连接和等待线程数。
  • 是否存在连接泄漏。
  • SQL 是否变慢或事务持有连接过久。
  • 数据库最大连接数是否达到上限。

连接池大小不是越大越好,过大会把压力转移到数据库。HikariCP 的连接数公式、参数体系与 maxLifetime 陷阱见MySQL


五、数据库、缓存与消息队列

慢 SQL 的排查路径?

慢查询日志 → EXPLAIN → 扫描行数/索引 → 锁等待 → SQL 与表结构优化

重点检查:

  • 是否命中合适索引。
  • 是否出现全表扫描、回表过多或临时表。
  • 返回数据是否过大。
  • 是否存在大事务和锁等待。
  • 数据分布变化是否导致执行计划变化。

Redis 延迟突然上涨怎么排查?

  • 慢命令和大 Key。
  • 热 Key 导致单分片过载。
  • 持久化 fork 或磁盘抖动。
  • 网络和连接数。
  • 集中过期或缓存穿透。
  • 集群迁移、故障转移和客户端重试。

MQ 消息积压怎么处理?

  1. 判断生产速度、消费速度和积压增长趋势。
  2. 检查消费端错误、慢依赖、线程池和批量参数。
  3. 临时增加消费者或分区,但先确认顺序性和下游承载能力。
  4. 对失败消息隔离,避免单条坏消息阻塞。
  5. 消费端必须保证幂等,并监控消费延迟。

六、发布与复盘

发布后错误率上涨怎么办?

  • 立即对比发布前后指标。
  • 判断是否只影响新版本实例。
  • 满足回滚条件时优先回滚。
  • 检查数据库变更、配置兼容和缓存格式。
  • 修复后重新灰度,不直接全量发布。

什么是有效告警?

有效告警应做到:

  • 与用户影响或系统容量相关。
  • 有明确阈值、持续时间和告警级别。
  • 包含服务、实例、时间和排查入口。
  • 能聚合重复告警,避免告警风暴。
  • 有负责人和处理手册。

故障恢复后为什么还要复盘?

恢复只解决当前问题,复盘需要解决系统性缺陷:

  • 监控为什么没有提前发现。
  • 降级和回滚为什么没有自动生效。
  • 测试和压测为什么没有覆盖。
  • 相同模式是否存在于其他服务。