本文目录导读:

排查线上服务突然变慢的性能问题,需要系统化、有步骤地进行,避免在慌乱中盲目操作,最有效的思路是遵循 “从外到内、自上而下、先排查关键指标后深入代码” 的原则。
以下是详细的排查步骤和工具指南,分为四个阶段:
第一阶段:快速定位“是谁”变慢(全局视角)
首先确认是整体系统都慢,还是某个接口、某台机器、某种类型用户慢。
-
查看监控大盘(黄金指标):
- 流量:QPS/TPS(每秒请求/事务数)是否突然飙升(被攻击、业务被“薅羊毛”)或暴跌(服务不可用)。
- 延迟:P50、P95、P99(第50、95、99百分位响应时间)的延迟曲线,如果P99飙升但P50正常,说明少数请求异常慢(可能被阻塞、长尾请求);如果P50也飙升,说明整体负载高。
- 错误率:HTTP 5xx(服务端错误)、超时、业务异常码是否增加。
- 饱和度:CPU、内存、磁盘I/O、网络带宽的使用率是否接近100%。
-
确认变更时间线:
- 立即回看最近的代码发布、配置变更、数据库DDL(数据定义语言,如加索引)、第三方依赖升级、流量切换,90%的性能问题源于变更。
- 检查上下游依赖服务是否正常(如调用外部API、Redis、MySQL、消息队列),如果下游变慢,你的服务也会“被变慢”。
第二阶段:深入查找“资源瓶颈”(系统层面)
如果确认是服务自身变慢,登录一台有问题的实例,检查操作系统和中间件。
CPU 使用率过高
- 现象:
top命令显示 CPU 的us(用户态)或sy(内核态)接近100%。 - 排查工具:
top/htop:找到占用CPU最高的进程PID。top -H -p <PID>:查看该进程内最耗CPU的线程TID。printf "%x\n" <TID>:将线程ID转换为十六进制(nid)。jstack <PID> | grep -A20 <nid>:在Java线程堆栈中定位到具体代码行。
- 常见原因:死循环、过度的GC(垃圾回收)、正则表达式回溯、序列化/反序列化瓶颈。
内存问题(GC频繁 / OOM)
- 现象:应用响应变慢,
top看到 CPU 的si(软中断)或sy较高(GC线程占用),或者直接OOM(内存溢出)。 - 排查工具:
jstat -gcutil <PID> 1000:每秒查看GC情况,关注 YGC(年轻代GC)/ FGC(完全GC)频率 和耗时,如果FGC频繁且耗时长,STW(Stop-The-World,暂停所有用户线程)会导致严重停顿。jmap -heap <PID>:查看堆内存配置和占用。jmap -dump:live,format=b,file=heap.hprof <PID>:导出堆转储文件(注意会暂停服务,慎用,建议在备用机或低峰期执行)。
- 常见原因:内存泄漏、缓存设置过大、大对象分配过多。
I/O 瓶颈(磁盘或网络)
-
现象:
top命令中wa(CPU等待I/O完成的时间)很高;iostat -x 1显示%util(设备利用率)接近100%或await(平均I/O请求处理时间)很大。 -
排查工具:
iostat -x 1:监控磁盘读写延迟和队列长度。dstat:综合查看CPU、磁盘、网络、系统负载。netstat -s:查看网络丢包、重传率。
-
常见原因:
- 数据库:慢SQL(结构化查询语言)、未命中索引、锁等待。
- 日志:短时间内疯狂打印错误日志(Log4j/SLF4J)。
- 磁盘:磁盘空间满(
df -h)、文件句柄耗尽(lsof -p <PID> | wc -l)。
第三阶段:深入代码逻辑(应用层面)
当系统资源正常但依然慢时,问题出在业务代码逻辑或锁。
-
抓取慢请求的调用链:
- 使用APM(应用性能监控)系统(如SkyWalking、Pinpoint、Jaeger、Datadog APM)查看慢请求的完整调用链路,哪一步(RPC调用、数据库查询、缓存查询)耗时最长?
- 如果没有APM,在关键代码入口手动增加日志耗时统计(打印当前时间戳),分段排查。
-
数据库层(最常见的瓶颈):
- 慢查询日志:开启数据库的慢查询日志(
slow_query_log),抓到执行时间超过阈值的SQL语句。 EXPLAIN分析:对慢SQL执行EXPLAIN,检查type(访问类型,如ALL全表扫描)、key(使用的索引)、rows(扫描行数)。- 锁竞争:查看数据库是否有死锁、行锁等待。
SHOW PROCESSLIST查看是否有大量Waiting状态的线程。 - 连接池:应用连接池是否已耗尽(如HikariCP的
Active连接数=MaximumPoolSize),导致请求排队等连接。
- 慢查询日志:开启数据库的慢查询日志(
-
锁竞争(多线程):
- 同步锁:
synchronized、ReentrantLock被高并发访问导致阻塞,堆栈中常见parking to wait for - 分布式锁:Redis、ZooKeeper的锁竞争。
- 使用
jstack多次(间隔1秒)查看线程状态,如果有大量线程处于BLOCKED或WAITING状态,并且都等待同一个锁对象,那就是锁热点。
- 同步锁:
第四阶段:快速定位的“紧急止血”措施
如果系统正在严重故障,无法从容排查,可以尝试以下操作:
- 限流/降级:
- 对非核心业务进行降级(返回默认值或缓存数据)。
- 在网关层(如Nginx、Spring Cloud Gateway)对异常流量进行限流(QPS限流)。
- 扩容/重启:
- 快速增加Pod实例或虚拟机(水平扩容)。
- 紧急重启应用(能临时解决内存泄漏、死锁等“重启可恢复”问题,但需警惕重启可能导致数据丢失或雪崩)。
- 回滚:如果怀疑是最近一次发布导致,立即执行代码或配置回滚。
一张排查流程图
graph TD
A[用户反馈/告警:系统变慢] --> B{查看监控大盘:CPU/内存/I/O/延迟/错误率?}
B -- “CPU高” --> C[top -> jstack 抓线程堆栈]
B -- “内存高/GC频繁” --> D[ jstat/jmap 分析堆栈]
B -- “磁盘I/O高” --> E[ iostat -> 定位是日志还是数据库]
B -- “网络/连接数高” --> F[ netstat/APM 调用链]
B -- “所有指标正常” --> G[深入应用层]
G --> G1[抓慢查询日志 -> EXPLAIN SQL]
G --> G2[抓线程堆栈 -> 查锁竞争/死锁]
G --> G3[检查日志打印频率]
C --> H[定位到具体代码行/线程]
D --> H
E --> I[数据库慢SQL优化/日志降级]
F --> J[检查依赖服务/第三方API超时]
G1 --> I
G2 --> K[优化锁粒度/使用无锁结构]
H --> L[修复/优化代码]
I --> L
J --> L
K --> L
L --> M[观察监控,确认恢复]
关键心法:
- 先看变化,再分析状态:性能问题90%由“变化”引起(发布、流量、依赖方异常),不要一开始就深钻代码。
- 数据驱动:不要猜测,用
top、jstack、慢查询日志的数据说话。 - 一个点一个点排除:从系统层面(CPU/内存) -> 中间件层面(数据库/缓存) -> 代码层面,逐层深入。
希望这份指南能帮你系统化地解决线上性能问题,如果有具体的报错信息或监控截图,也可以发出来,我可以帮你进一步分析。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播