TPS 卡在 800 不是 CPU 的锅:Hikari 连接池只给了 50 个连接、超时还没配,几百个请求全堵在 getConnection()。改完 1600。
先看那条骗人的 CPU 曲线
场景没什么稀奇:核心接口单压,并发从 100 加到 200,TPS 涨到 800 就躺平。再加到 300,不涨反跌。
看监控,CPU 只跑到四成。第一反应自然是"机器还没吃满,加并发就完事了"。把线程数翻倍,TPS 掉到 700 出头。
CPU 不满,说明瓶颈根本不在计算层。计算层长什么样?CPU 打满、GC 频繁、上下文切换爆炸。CPU 闲着的卡顿,八成是在等------等锁、等连接、等 IO、等下游。
记住一句话:别盯计算层,分层往下摸。应用层、中间件层、数据库层,一层一层排。
六步,一步都别省
排查流程固定成六步,少讲一步面试官就当你没做过:
顺序不能乱。现象是"TPS 卡 800、CPU 四成";工具拿来看证据;分析把证据收敛到某一层;根因是那一层里具体哪行配置;方案得可执行;数据是改完的对比。
面试里最容易漏掉的是最后一步,数据。说"我改了连接池"没说服力,说"TPS 从 800 到 1600"才叫做过。
为什么第一把工具是 netstat 而不是 jstack
先用 netstat(或 ss)看连接状态分布:
bash
netstat -n -p tcp | awk '{print $$6}' | sort | uniq -c | sort -rn
输出大概长这样:
text
812 TIME_WAIT
634 ESTABLISHED
287 CLOSE_WAIT
满屏 TIME_WAIT,大量连接挤在同一条道上排队。方向当场锁死:问题在连接层,不在计算层。
这里有个容易搞混的点。TIME_WAIT 多,说明连接反复建立销毁、没有复用;CLOSE_WAIT 多,是应用侧没关连接,通常意味着连接泄漏。两者指向的原因完全不同,别混着说。
根因:50 个连接接 200 个并发
顺着连接层往下,查数据库连接池配置:
yaml
hikari:
maximum-pool-size: 50
connection-timeout: 0 # 没配超时
最大连接数只给 50,超时也没配。并发爬到 200 以上,几百个请求全在池子外面排队等连接。每个请求平均等几十上百毫秒,TPS 上不去,CPU 在旁边闲着看戏。
这就是典型的"CPU 不满但吞吐上不去":线程全阻塞在 getConnection(),一点计算量都没有。
改法很直接:
yaml
spring:
datasource:
hikari:
maximum-pool-size: 200
minimum-idle: 50
connection-timeout: 3000
idle-timeout: 600000
max-lifetime: 1800000
connection-timeout 必须明确给值。给了超时,池子撑不住时会快速失败返回,而不是把请求无限挂在那儿------快速失败比慢慢等死好排查得多。
复测:800 → 1600
同一个脚本、同一台机器、同样并发 200,重压一次:
| 指标 | 修复前 | 修复后 |
|---|---|---|
| TPS | 800 | 1600 |
| P99 响应时间 | 480ms | 210ms |
| CPU 使用率 | 40% | 68% |
| 连接池等待 | 大量排队 | 基本为零 |
TPS 翻倍,CPU 从四成涨到接近七成。这时候 CPU 涨上来是好事,说明请求终于被真正处理,而不是堵在池子门口。
面试官想听的就是这组前后对比数字。
两个高频变体
变体一:响应时间从 200ms 飙到 800ms,TPS 却正常。
还是那套分层思路,但先上链路追踪,别急着改代码。查出来是一条慢 SQL 在 500 万行的表上做全表扫描,加个联合索引,响应时间降到 80ms 以内。
迷惑点在于 TPS 没掉。TPS 正常说明吞吐没受影响,慢的是单请求耗时,方向该往"单条查询效率"走,跟连接、并发没关系。
变体二:CPU 跑满 100%,接口超时。
top -Hp <pid> 找出吃 CPU 最高的线程 ID,转十六进制,再 jstack <pid> | grep -A 30 <hex> 定位栈帧。常见结果是一段复杂正则或弹性回缩逻辑在高并发下被反复打爆。优化那段正则,CPU 降到 30% 以下。
top + jstack 是 CPU 打满场景的核心工具链,配上线程 ID 转十六进制,基本能追到具体代码行。
三句话版本
现象定起点,工具取证,分析锁层,根因落到具体配置或代码,方案可执行,数据做对比。
面试回答六步一步别省。最值钱的永远是最后那步------用前后对比数据把"我真的做过"砸出来。
写在最后
压测调优拼的不是工具多,是分层排查的习惯。CPU 不满的时候,你第一反应是加机器还是查连接池?这两个方向之间往往差着整整一倍 TPS。
顺手的赞,点一下就行。