1、先排掉"假问题"(30% 的坑在这)
很多所谓"性能上不去",其实是压测本身的问题。这一步不先做,后面全白干。
|
压测机自身瓶颈 |
top、CPU、内存、网络 |
压测机 CPU 打满 → TPS 是压测机的上限,不是服务端的 |
|
端口耗尽 |
ss -s、netstat |
TIME_WAIT 暴涨,Cannot assign requested address |
|
网络带宽 |
iftop、sar -n DEV |
带宽跑满,RT 全线拉长 |
|
脚本问题 |
看请求是否真发出去 |
think time 设错、断言太重、CSV 读取慢 |
|
连接池/客户端限制 |
JMeter 的 httpclient 连接数 |
并发设了 500,实际连接数只有 20 |
判据黄金口诀:
TPS 上不去,但服务端资源(CPU/内存/IO)都很闲 → 大概率是压测端或链路阻塞,不是服务端性能问题。
2、建立"三要素"关联视图
任何性能问题,都要同时看这三个指标的关系,缺一不可:
TPS(吞吐量) ↔ RT(响应时间) ↔ 资源利用率(CPU/内存/IO/网络)
核心定律:
- CPU 涨,TPS 涨 → 正常,还没到瓶颈
- CPU 涨,TPS 不涨,RT 涨 → 快到瓶颈了,开始排队
- CPU 不涨,TPS 不涨,RT 涨 → 有阻塞(锁、IO 等待、外部依赖、连接池不够)
- CPU 涨,TPS 反降 → 线程上下文切换严重,或 GC 频繁
第二和第三种是最常见的两类问题,后面分开讲。
3、分层定位漏斗(从外到内)
按这个顺序往下钻,每层都有明确的"证据"决定是否下钻:
① 网络/负载均衡 → ② 应用服务器 → ③ JVM → ④ 中间件/外部依赖 → ⑤ 数据库 → ⑥ 代码
① 网络 & 负载均衡
- 看:带宽、丢包率、LB 连接数、DNS 解析
- 工具:iftop、sar -n DEV、ping、mtr
- 典型问题:带宽打满、SLB 连接数限制、跨可用区调用
② 应用服务器(系统层)
- 看:CPU、内存、磁盘 IO、上下文切换、打开文件数
- 工具:top、vmstat、iostat、pidstat、dstat
- 关键指标:
- us(用户态CPU)高 → 业务代码在算,往下钻代码
- sy(内核态CPU)高 → 系统调用频繁(大量 IO/网络/锁竞争)
- wa(IO等待)高 → 磁盘或外部 IO 慢
- cs(上下文切换)暴涨 → 线程数过多,在疯狂切换
③ JVM 层
- 看:GC 频率/耗时、堆内存、线程状态
- 工具:jstat -gcutil、jmap、jstack、Arthas dashboard
- 典型问题:
- Full GC 频繁 → 内存泄漏或堆太小 → jmap dump + MAT 分析
- Young GC 耗时高 → 对象创建过快,看 jstat 各区回收情况
- 大量线程 BLOCKED → 锁竞争 → jstack 或 Arthas thread -b
④ 中间件 / 外部依赖
- 看:Redis、MQ、第三方接口、连接池
- 典型问题:
- 连接池打满(Druid/HikariCP 等待数)→ 慢 SQL 拖住连接
- Redis 大 key、热 key、连接池不够
- 第三方接口 RT 长 → 串行调用放大 RT
⑤ 数据库(最常见的终极瓶颈)
- 看:慢 SQL、锁等待、连接数、Buffer Pool 命中率
- 工具:慢查询日志、show processlist、explain、Arthas trace 定位到 SQL
- 典型问题:
- 没走索引、索引失效
- 大表 JOIN、深分页
- 行锁/表锁等待
- 连接数打满
⑥ 代码层
- 到这一层就是最后一步了,靠 Arthas / APM / profile 火焰图
- 典型问题:循环里查数据库、同步锁范围过大、序列化开销、日志打太多
4、两大经典场景的排查路径
场景 A:CPU 高、TPS 上不去
top → 找到 CPU 高的进程
top -Hp <pid> → 找到 CPU 高的线程
printf %x <tid> → 转 16 进制
jstack <pid> | grep -A20 <hex> → 看这个线程在干嘛
或者 Arthas 一步到位:
thread -n 3
往下判断:
- 栈在业务方法 → 算法/循环问题,用 profiler 火焰图找热点方法
- 栈在 GC 线程 → 内存问题,转 JVM 排查
- 栈在序列化/JSON → 数据量太大或序列化框架慢
场景 B:CPU 不高、但 RT 很长、TPS 上不去 ← 面试最爱考
这是阻塞型问题,排查思路完全不同:
1. jstack / Arthas thread 看线程状态
→ 大量 WAITING/BLOCKED
2. 看在等什么:
– 等数据库连接池 → 连接数不够 或 慢 SQL 占着连接
– 等 Redis/HTTP 连接 → 外部依赖慢
– 等 synchronized 锁 → 锁竞争激烈(thread -b 直接找)
– 等线程池队列 → 线程池核心数/队列配置不合理
3. Arthas trace 看方法内部耗时分布
→ 定位到底卡在哪一跳
关键洞察:
CPU 低 + RT 高 = 系统在"等",不是在"算"。要找"等什么",不是找"算什么"。
五、一个实战排查模板(可直接套)
# === 第 0 步:确认压测端没问题 ===
# 压测机 CPU/网络是否正常
# === 第 1 步:系统层 ===
top # 看整体负载、CPU 分布
vmstat 1 # 看 cs(上下文切换)、wa(IO等待)
pidstat -u -p <pid> 1 # 进程级 CPU
# === 第 2 步:JVM 层 ===
jstat -gcutil <pid> 1000 # 看 GC 频率和耗时
jstack <pid> > /tmp/stack.txt # 抓线程栈(多抓几次)
# === 第 3 步: Arthas 精准定位 ===
dashboard # 整体面板
thread -n 3 # CPU Top3
thread -b # 找死锁/阻塞源
trace <class> <method> '#cost>200' # 只看耗时>200ms 的调用
watch <class> <method> '{params, returnObj}' -x 2
# === 第 4 步:数据库 ===
# 开慢查询日志 / show processlist / explain
线程栈抓下来后,重点看大多数线程停在哪一个栈帧——那个就是瓶颈。
六、排查心法(比工具更重要)
七、记忆锚点
一看压测端,二看三要素(TPS/RT/资源),三分层下钻,四分 CPU 高还是等阻塞。
CPU 高往下找"算什么",CPU 低往下找"等什么"。
网硕互联帮助中心





评论前必须登录!
注册