压测 TPS 卡在 800CPU 只跑四成六步定位法

TPS 卡在 800 不是 CPU 的锅:Hikari 连接池只给了 50 个连接、超时还没配,几百个请求全堵在 getConnection()。改完 1600。

先看那条骗人的 CPU 曲线

场景没什么稀奇:核心接口单压,并发从 100 加到 200,TPS 涨到 800 就躺平。再加到 300,不涨反跌。

看监控,CPU 只跑到四成。第一反应自然是"机器还没吃满,加并发就完事了"。把线程数翻倍,TPS 掉到 700 出头。

CPU 不满,说明瓶颈根本不在计算层。计算层长什么样?CPU 打满、GC 频繁、上下文切换爆炸。CPU 闲着的卡顿,八成是在等------等锁、等连接、等 IO、等下游。

记住一句话:别盯计算层,分层往下摸。应用层、中间件层、数据库层,一层一层排。

六步,一步都别省

排查流程固定成六步,少讲一步面试官就当你没做过:

flowchart TD A[现象] -->|定位起点| B[工具] B -->|采集证据| C[分析] C -->|锁定层| D[根因] D -->|给出改法| E[方案] E -->|复测对比| F[数据] F -->|没解决| B

顺序不能乱。现象是"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。

顺手的赞,点一下就行。

相关推荐
吴声子夜歌4 分钟前
Nginx应用与运维——Nginx在Kubernetes中的应用(二)
运维·nginx·kubernetes
ShineWinsu13 分钟前
对于Redis:RDB持久化的解析
linux·数据库·redis·缓存·面试·持久化·rdb
丑陋小蚊子6 小时前
项目数据不能公开,就写清交付物
面试·求职招聘·大学生·简历·简历下载
Ruiery9 小时前
Linux 6.6内核 CPU 深度解析(七):调度器启动 — 从单核到多核,调度器分阶段点亮
linux·运维·服务器
50万马克的面包9 小时前
CSDN-栈队列数组-知识点整理
linux·运维·服务器
MicrosoftCloud9 小时前
用户权限 04|/etc/sudoers 安全配置:从最小授权到「别把 ALL 随便给人」
运维·安全·ubuntu·sudo·sudoers
2601_949950639 小时前
练题簿在线免费刷题 从资料整理到考前自测
面试·职场和发展·pdf·word·刷题
꯭自꯭闭꯭11 小时前
达梦事物特性及MVCC
linux·运维·数据库
时间的拾荒人11 小时前
Qt 多线程详解:从 QThread 到实战
开发语言·qt·面试
海绵宝宝转agent11 小时前
MySql高频面试八股开源笔记总结
mysql·面试·开源