基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

假设一个平时响应很快的接口突然偶尔出现几秒钟的严重卡顿,但随后又恢复正常,排查方向有哪些?

知识点图片

这种“平时很快,偶尔极慢,随后又自动恢复”的现象在系统排查中非常经典,通常被称为“毛刺现象”(Spike)或间歇性延迟。

排查这类问题,核心思路是寻找“周期性触发的事件”“资源争抢造成的排队”“特定极端数据的请求”。以下是全方位的排查方向:

一、 应用层(代码与运行环境)

这是最常见、也最容易排查的区域。

  1. 垃圾回收(GC)停顿(Stop-The-World)
    • 现象:Java、Go、Node.js 等带有自动内存管理的语言,在进行垃圾回收(尤其是 Full GC)时会暂停所有业务线程,导致请求被挂起数秒,GC 完成后瞬间恢复。
    • 排查:查看监控系统的 JVM/Go Runtime 监控,对比接口卡顿时间点与 GC 耗时峰值是否重合。
  2. 连接池/线程池耗尽(排队等待)
    • 现象:并发量突然出现一个极短的波峰,导致 HTTP 线程池、数据库连接池或 Redis 连接池被借空。后续请求需要等待其他请求释放连接,造成几秒的延迟。一旦波峰过去,池子有了空余,立马恢复。
    • 排查:查看 APM(应用性能监控)中各类池子的活跃连接数指标,看是否在卡顿时间点触顶。
  3. 日志阻塞(异步变同步)
    • 现象:平时使用异步日志打印,但突然产生大量日志(如抛出大量异常堆栈),导致异步日志队列(Buffer)被打满,日志框架降级为同步刷盘。此时磁盘 I/O 成为瓶颈,阻塞业务线程。
    • 排查:检查卡顿时间点是否有大量的 Error 日志或异常的大报文日志打印。
  4. 特定请求参数(数据倾斜)
    • 现象:99% 的请求只查询 10 条数据(极快),但偶尔有 1% 的请求命中了极其庞大的层级关系或全量数据,导致业务逻辑处理极慢。
    • 排查:在日志中对比“慢请求”的具体入参,确认是否是特定用户或特定参数触发的。

二、 缓存与数据库层

数据层是产生“毛刺”的重灾区。

  1. 缓存失效(缓存击穿/雪崩)
    • 现象:某个热点数据的缓存恰好在此时过期。多个并发请求同时发现缓存没命中,一起去查询数据库(重建缓存需要几秒钟)。这几秒内的所有请求都会卡顿,一旦第一个请求把缓存重建写回 Redis,后续请求瞬间恢复正常。
    • 排查:查看慢请求发生时,Redis 是否有该 Key 的过期日志,或者数据库此时是否有相同的突然增高的查询 SQL。
  2. 数据库锁等待(Lock Contention)
    • 现象:该接口在执行更新/插入时,恰好与其他慢事务冲突,正在等待行锁甚至表锁。等待了几秒钟后,另一个事务提交了,该接口获取到锁并瞬间执行完毕。
    • 排查:排查慢请求发生时,数据库层面是否有死锁日志(Deadlock)或长时间的锁等待记录(如 MySQL 的 innodb_lock_waits)。
  3. 数据库后台定期任务
    • 现象:数据库正在进行后台的自动操作,例如 PostgreSQL 的 Auto-vacuum(自动清理)、MySQL 的刷脏页(Buffer Pool Flush)、或是 Elasticsearch 的 Segment Merge。这些操作会瞬时消耗大量磁盘 I/O,导致正常 SQL 变慢。
    • 排查:查看数据库监控底层的磁盘 IOPS 和 CPU 突增情况。
  4. 慢 SQL 偶发
    • 现象:SQL 执行计划偶尔走错(没走索引),或者 MySQL 的查询缓存/Buffer Pool 恰好把这块数据淘汰了,导致发生了一次物理磁盘读(较慢),读入内存后,后续又变快了。

三、 外部依赖与网络层

如果是微服务架构,问题往往在“外面”。

  1. 下游服务偶尔超时/抖动
    • 现象:该接口调用了第三方 API 或内部其他微服务,下游服务由于自身原因卡顿了几秒。当前接口同步等待,自然也表现为卡顿。
    • 排查:使用分布式链路追踪系统(如 SkyWalking、Jaeger、Pinpoint),查看耗时具体是花在了当前节点,还是下游的 RPC/HTTP 调用上。
  2. DNS 解析超时
    • 现象:调用外部域名时,本地 DNS 缓存正好失效,去向上级 DNS 服务器查询。如果此时网络轻微抖动,DNS UDP 包丢失,操作系统默认的 DNS 超时重试时间通常是 1秒、2秒、5秒,会导致请求莫名其妙卡顿几秒。
    • 排查:在请求外部服务时,改用 IP 测试,或开启 DNS 解析耗时监控。
  3. 网络丢包与 TCP 重传
    • 现象:机房网络偶尔抖动,发生丢包。TCP 协议为了保证可靠性会进行超时重传(RTO),首次重传通常是 200ms,后续成倍增加(1s, 3s, 7s...)。这会导致处于该 TCP 连接上的请求突然卡顿几秒。
    • 排查:查看操作系统监控(如 netstat -s),关注 TCP 重传率(Retransmission rate)是否在特定时间点飙升。

四、 基础设施与操作系统

“隐形杀手”通常藏在这里。

  1. 宿主机定时任务(Cron Jobs)
    • 现象:每小时的第 0 分钟,或者每天半夜,服务器上有定时脚本在跑(如备份日志、打包文件、监控数据上报)。瞬间吸干了 CPU 或 磁盘 I/O,导致业务进程得不到时间片。任务跑完,立马恢复。
    • 排查:核对卡顿出现的时间点是否有规律(比如总是逢整点、半点),检查 crontab -l
  2. 云环境的“吵闹的邻居”(Noisy Neighbor)
    • 现象:如果你的服务部署在公有云的虚拟机上,和你同一台物理机的其他租户突然占用了大量的共享资源(如网络带宽、底层存储 IOPS),会导致你的虚拟机性能瞬间下降。
    • 排查:查看云监控中的 CPU Steal Time(被 Hypervisor 偷走的 CPU 时间)和磁盘 IO Wait 指标。
  3. 内存 Swap(交换区)读写
    • 现象:服务器物理内存不足,操作系统将部分应用内存页 Swap 到了磁盘上。当该接口需要使用这些内存时,触发缺页中断,必须从磁盘重新读回内存,极其缓慢。
    • 排查:查看系统监控中的 Swap In/Out 速率。强烈建议线上关键服务直接关闭 Swap。

💡 推荐排查标准动作(SOP)

遇到这种问题,光靠猜是很难定位的,建议按照以下顺序固化证据:

  1. 看链路(Tracing):看这几秒钟的耗时到底在哪个组件(自己代码、DB、Redis 还是下游 HTTP)。
  2. 看监控(Metrics):对照卡顿发生的精确时间点(秒级),去大盘看 CPU、内存、网络IO、磁盘IO、GC 次数、连接池使用率,寻找同步突增的指标。
  3. 看日志(Logging):把慢请求的整个 Trace ID 拿出来,看入参是不是特别大?有没有打印出 Warning 或 Error?
  4. 抓现场:如果是高频偶现(比如一天出现几次),可以写一个脚本,每秒检测该接口耗时,一旦超过 2 秒,立刻触发抓取堆栈(jstack / pprof)和网络包(tcpdump),保留案发现场。
00:00
00:00