并发不高但经常卡顿一般不是并发压力问题,而是延迟高、阻塞、排队、停顿。排查思路是先定界,再抓现场,后分层下钻。不要急着重启,除非已经影响生产;尽量保留线程栈、GC、慢SQL、监控快照。
1. 先定义卡顿
先弄清楚这些:
是前端页面卡,还是接口慢,还是整个系统无响应?
哪些功能、哪些接口?所有实例还是某个实例?
随机卡,还是周期性卡?比如整点、每 5 分钟、每天凌晨。
P95、P99、错误率、超时率、QPS 分别是多少?
卡的时候 CPU、内存、磁盘 IO、网络、GC、数据库是什么状态?
标准看:P99 响应时间、最慢 span、线程池活跃数和队列、数据库连接池active和pending、GC 停顿、慢 SQL、下游超时。
2. 快速抓现场
Java 应用常用命令:
bash
top -Hp <pid>
printf "%x\n" <tid>
jstack -l <pid> > jstack1.txt
jstat -gcutil <pid> 1000
jmap -histo:live <pid>
jstack 建议间隔 5 秒抓 3 次,重点看有没有大量 BLOCKED、WAITING,或者都卡在同一个方法上。
Arthas 常用:
bash
dashboard
thread -n 10
thread -b
trace 类 方法
profiler start --event cpu
火焰图:
bash
./profiler.sh -d 30 -f flamegraph.html <pid>
系统层:
bash
vmstat 1
iostat -x 1
pidstat -u -d -w -p <pid> 1
ss -s
free -h
df -h
数据库:
sql
show full processlist;
show engine innodb status;
explain ...;
同时看慢查询日志、锁等待、长事务、连接数。
缓存和中间件:
Redis看slowlog get 100、--bigkeys、info latency。
MQ 看堆积、消费慢、重试。
ES 看慢查询、GC。
3. 分层排查
前端:看 F12 的 Network 和 Performance,排查大 JSON、未分页、长任务、资源加载。
网关和 Nginx:看连接数、超时、重试、TLS、DNS、带宽。
应用:看线程池、连接池、锁、GC、日志、序列化、同步调用。
缓存:看大 key、热 key、慢命令、持久化 fork、缓存击穿。
数据库:看慢 SQL、缺索引、N+1、锁等待、死锁、长事务、主从延迟。
外部依赖:看 HTTP、RPC 超时、重试、熔断、DNS、TCP 重传。
操作系统和容器:看 CPU throttling、内存 limit、swap、磁盘 IO、网络丢包。
定时任务:看整点跑批、备份、统计、日志切割、缓存刷新。
4. 常见原因和特征
慢SQL或锁等待:QPS不高,但请求几秒;数据库CPU不高,show processlist有大量Waiting for lock。
Full GC或内存泄漏:周期性卡顿,jstat看 FGC频繁,FGCT很长。
线程池或连接池耗尽:请求排队,pending 高;下游一慢,线程全挂住。
锁竞争:jstack 大量 BLOCKED,thread -b 能找到。
外部依赖超时:线程都在 WAITING 等 HTTP 或 RPC,超时设置过大,重试放大。
定时任务:整点卡,查 cron、xxl-job、Quartz、备份、日志切割。
日志或磁盘 IO:同步写大日志、磁盘满、iowait 高。
容器限制:CPU 被 throttle,内存 limit 导致 OOM 或 swap。
网络问题:DNS 慢、TCP 重传、丢包,表现为随机卡。
前端问题:接口不慢但页面卡,可能是大 JSON、渲染、内存泄漏。
5. 查找清单
加traceId,看一次慢请求的完整链路,找最慢span。
卡的时候抓 jstack 3 次、jstat、top -Hp。
查慢 SQL、锁等待、连接池 active 和 pending。
查 GC 日志和 Full GC 频率。
查定时任务是不是和卡顿时间重合。
查外部依赖超时、重试、熔断配置。
查容器CPU throttling、内存、磁盘 IO、网络重传。
对比正常和异常实例,隔离证实:切流量、停任务、重启单实例、降级下游。
优化后用 P95、P99 和压测证实。
并发不高还卡,优先怀疑慢 SQL 或锁、GC、线程池或连接池、外部依赖、定时任务、日志或 IO、容器限制。先用监控和 trace 找到卡在哪个步骤,再用线程栈、火焰图、慢查询日志定位具体代码或资源。