用 AI 分析压测结果:曲线、拐点与可疑指标

把 wrk、k6、ghz 的原始输出整段丢给 AI,通常只换回「性能良好,建议优化数据库」这类没有信息量的话。问题不在模型,而在于你把一堆数字当成了一次完整任务:压测结论的价值藏在指标之间的关系里,先把关系组织好,AI 才能给出可被验证的判断。

原始数据要凑齐四类

类别具体内容缺了它会怎样
延迟分位(percentile)P50、P90、P95、P99、P99.9、最大值、平均值只看平均值,长尾被抹平
吞吐曲线各并发或到达率档位下的 QPS 与对应延迟找不到拐点,只能报一个孤立峰值
错误分布各错误码计数与占比、一个完整错误样本把失败请求算进成功,吞吐虚高
系统指标CPU 及其时间分布、内存、GC 停顿、load、上下文切换(context switch)、连接数、下游指标无法区分「服务慢」与「机器已经满了」

再加上两项元信息:压测机的自身水位,以及数据量、缓存状态与预热情况。没有这两项,后面几乎必然误判。

分析提示词模板

你是性能工程师。下面是一次压测的原始数据。请只基于我给的数据下结论,
不要补充任何我没提供的数字,也不要用「可能」「建议进一步排查」这类无证据措辞。

【环境】服务:Go 1.22,8 核 16G 单实例;DB:MySQL 8.0 单机;Redis 单节点。
        压测机:4 核 8G,与目标同机房,压测机 CPU 峰值 55%(未饱和)。
【场景】wrk2 定速压测 /api/order/detail,连接复用,预热 60s,每档稳定 300s。
【数据】
档位(QPS) 实测QPS  P50   P90   P99   P99.9  最大值  错误率  CPU   GC_CPU  cs/s
  500      500     4ms   8ms   12ms  20ms   45ms   0%     22%   1%      21k
 1000     1000     5ms   11ms  15ms  30ms   60ms   0%     41%   1%      23k
 2000     1998     7ms   20ms  38ms  90ms   210ms  0%     76%   2%      31k
 3000     2890    12ms   90ms  260ms 700ms  1.5s   1.2%   88%   8%      96k
 4000     2950    40ms   600ms 1.8s  3.2s   6.1s   9.0%   91%   14%    185k
【错误码分布】3000 档:503 占 78%,499 占 22%;4000 档:503 占 65%,超时(read timeout) 35%。
【任务】输出 5 条以内的结论,每条按「结论 / 证据 / 反例」三段式给出,并给出下一步要采的两个数据点。

模板里有三处关键约束:档位至少三档、每档时长写清、压测机水位必须给出。三档以下无法判断趋势,时长不明则无法区分拐点与噪声。

判读要点一:吞吐曲线上找拐点(knee)

拐点的定义是:再增加负载,吞吐几乎不再增长,而延迟开始明显上升。

现象判断需要补充的证据
拐点处服务端 CPU 已过 85%容量型瓶颈,服务端资源打满确认是业务 CPU 还是 GC、系统态 CPU
拐点处 CPU 只有 60%~70%排队型瓶颈:锁竞争、连接池、线程数、下游等待阻塞剖析、连接池 active、下游延迟
越过拐点后吞吐反而下降排队崩溃:超时、重试、GC 陷入恶性循环超时计数、重试放大倍数
曲线平滑无拐点压测机或客户端先到极限压测机 CPU、网卡、端口耗尽

上表例子里,拐点落在 2000 与 3000 档之间:3000 档实测只有 2890,P99 从 38ms 跳到 260ms,CPU 88% 且 GC 占用从 2% 涨到 8%——这是典型的「资源接近饱和 + 长尾开始失控」。

判读要点二:平均值与分位的背离

组合含义顺着查什么
平均值正常、P99 异常少数请求被偶发阻塞GC 停顿、锁等待、连接池取连接、下游毛刺
平均值与 P99 同步恶化整体变慢,通常是资源饱和CPU、磁盘 IO、网络带宽
P50 稳定、P99 波动大尾部随机性,可能是重试或缓存击穿缓存命中率、慢日志按时间聚合
平均值远低于 P50数据统计有问题(如把超时请求剔除了)重新核对统计口径与错误码计数

在例子里,3000 档的平均值约 30ms 而 P99 为 260ms,差了近 9 倍:只报平均值会得出「延迟良好」的错误结论。凡是平均值与 P99 相差超过 3 倍,就必须单独解释长尾。

判读要点三:队列堆积特征

队列堆积在数据上的指纹很规整:吞吐不再增长,延迟却随并发近似线性上升。

按利特尔法则(Little's Law),在途请求数 ≈ 到达率 × 平均延迟。若 3000 档的平均延迟是 30ms,在途请求约 2890 × 0.03 ≈ 87;4000 档延迟涨到 1.8s,在途请求变成 2950 × 1.8 ≈ 5310——数量级跳变说明请求根本没被处理,而是堆在了队列、连接池或 socket 缓冲区里。此时排查方向不是优化单次请求耗时,而是找出队列的容量上限与消费者数量。

堆积位置旁证指标采集方式
应用线程池或 goroutine 队列队列长度、活跃线程数、goroutine 数应用指标、goroutine 剖析
数据库连接池active 顶到上限、等待获取连接时长连接池指标、连接数统计
内核 socket 队列Recv-Q 非零、连接建立失败ss -lnt、ss -s
下游服务排队下游自身 P99 同步抬头下游大盘、客户端超时计数

判读要点四:GC 与上下文切换旁证

上下文切换(context switch)从 23k/s 涨到 185k/s,通常意味着大量线程在锁或 IO 上被唤醒又挂起;GC CPU 占比从 1% 涨到 14%,说明对象分配速率随压力放大。这两项都能推翻「CPU 不够用,加机器就行」的结论:加机器不会降低单实例的切换频率,也不会减少分配。

系统指标可疑阈值旁证方向
用户态 CPU 高持续 > 80%计算密集、序列化、编解码
系统态 CPU 高持续 > 20%大量 syscall、网络收发、锁系统调用
GC CPU 占比> 10%分配热点、缓冲区过小、响应体过大
上下文切换与 QPS 增长不成比例锁竞争、线程数过多、IO 阻塞
load 高于核数持续大于核数排队而非并行

要求 AI 给「结论 + 证据 + 反例」

改写以下每条结论:
结论:一句话,带数字,可证伪。
证据:引用我提供数据中的具体行与列(如「3000 档 P99 260ms」),不许引用未提供的数据。
反例:写出这条结论在什么情况下不成立,以及需要什么数据才能排除该情况。
禁止:出现「建议优化」「可能存在」「需要注意」等无法验证的措辞。
AI 的初稿合格的写法
系统存在性能瓶颈,建议优化数据库结论:拐点在 2000~3000 QPS,安全容量取 1200 QPS/实例。证据:3000 档 CPU 88%、GC 8%、P99 260ms。反例:若 3000 档的下游 Redis 同时被其他业务压满,则拐点由下游引起,需补测下游独占时的曲线
可能存在内存泄漏结论:本轮数据无法判断内存泄漏。证据:仅给了 GC CPU 占比,没有堆大小随时间的变化。反例:给出 300s 内 inuse_space 斜率即可判定

反例这一段最容易被省略,但它是整条结论的价值所在:写不出反例,说明这条结论只是在复述数字。

收尾两件事

  • 每个可疑指标都要有明确的「下一个数据点」:这次没采到的,写进下一轮压测的采集清单,而不是靠推测补全。
  • 把 AI 的结论与原始输出一起归档,标注哪些是观测事实、哪些是推断,便于后续压测做对比。

小结:先把分位、曲线、错误码、系统指标四类原始数据凑齐并约束档位与时长,再让 AI 按「结论 / 证据 / 反例」三段式输出;分析时重点盯四点——吞吐曲线的拐点、平均值与 P99 的背离、队列堆积的延迟指纹、GC 与上下文切换的旁证。

笔记加载中…