4. 测试执行与监控:让系统在压力下“裸奔”

吞吐测试的执行,说白了就是给系统施加压力,然后看它怎么“扛”。但怎么加压、怎么观察、怎么判断系统快不行了——这些才是真正的技术活。我个人习惯把执行阶段分成三块:加压策略、稳态与峰值测试、以及全方位的监控体系。咱们一个一个聊。

核心观点: 测试执行不是“跑个脚本等结果”,而是通过阶梯加压找到系统的软肋,通过稳态测试验证系统的耐力,通过峰值测试摸清系统的天花板。监控则是你的“眼睛”,没有它,你就是在盲人摸象。

4.1 阶梯加压策略:别一上来就“满功率”

很多新手做压力测试,喜欢直接上 1000 并发。结果系统瞬间崩溃,日志里全是超时,你根本分不清是代码问题还是资源问题。我刚开始做性能测试时也犯过这个错,后来学乖了——阶梯加压才是正道。

阶梯加压的核心思想是:逐步增加负载,观察系统在每个阶段的反应。就像你开车,不会一脚油门踩到底,而是慢慢加速,感受发动机的反馈。

具体怎么做?我一般这样设计:

  1. 确定起始并发数:通常从 1 个并发开始,或者从系统预估的 10% 容量开始。
  2. 设定阶梯步长:每次增加 10-20% 的并发数,或者固定增加 50/100 个并发。
  3. 设定阶梯持续时间:每个阶梯持续 2-5 分钟,让系统有足够时间“反应”。
  4. 设定阶梯间隔:有些工具支持阶梯间的“思考时间”或“恢复时间”,我一般不加,保持连续加压。
  5. 设定终止条件:当错误率超过 5% 或响应时间超过阈值时,自动停止。

举个例子,用 JMeter 的 Stepping Thread Group 插件,配置起来很简单:

// 阶梯线程组配置示例
起始线程数: 10
每次增加: 10
每步持续: 60 秒
阶梯间隔: 0 秒
最大线程数: 200
终止条件: 错误率 > 5%

为什么这么做?因为阶梯加压能帮你画出系统的性能拐点。你会发现,在某个并发数之前,响应时间很平稳;超过这个数,响应时间突然飙升——这就是系统的“膝盖”。

我的经验: 我曾经在一个电商项目中,用阶梯加压发现系统的拐点在 500 并发。但开发团队坚持说系统能扛 1000。结果我们一查,是数据库连接池在 500 并发时刚好用完。如果没有阶梯加压,直接上 1000,你只会看到一堆超时,根本定位不到根因。

4.2 稳态测试与峰值测试:耐力与爆发力

阶梯加压找到了拐点,接下来要验证两件事:系统能不能长时间稳定运行?系统能不能扛住突发流量?

4.2.1 稳态测试

稳态测试,也叫耐久性测试或浸泡测试。它的目的是验证系统在持续负载下,会不会出现内存泄漏、连接池耗尽、GC 频繁等问题。

怎么做?很简单:

  • 负载水平:通常取阶梯加压中拐点之前的 70-80% 并发数。比如拐点是 500,稳态测试就用 350-400 并发。
  • 持续时间:至少 1 小时,我建议 4-8 小时。有些金融项目甚至跑 24 小时。
  • 观察指标:响应时间是否持续增长?错误率是否从 0 慢慢爬升?内存使用是否线性增长?

我记得有一次做稳态测试,跑了 3 小时后,响应时间从 50ms 慢慢涨到了 200ms。一查,是某个缓存没有设置过期时间,导致内存占用越来越高,GC 越来越频繁。这就是稳态测试的价值——发现那些“温水煮青蛙”式的问题。

4.2.2 峰值测试

峰值测试,也叫突发测试或尖峰测试。它模拟的是“双十一秒杀”、“微博热搜”这种瞬间流量暴增的场景。

做法和阶梯加压不同:

  • 基线负载:先让系统在正常负载下运行(比如 100 并发)。
  • 突发负载:瞬间将并发数提升到 2-5 倍(比如 500 并发),持续 30 秒到 2 分钟。
  • 恢复期:然后降回基线负载,观察系统能否恢复。
  • 重复:可以重复 3-5 次,看系统是否每次都能扛住。

峰值测试最常暴露的问题是:自动扩容来不及、连接池瞬间被占满、缓存雪崩。我曾经在一个项目中,峰值测试时系统直接挂了,原因是限流组件配置的阈值太低,突发流量一来,直接把正常请求也拦了。嗯,这就是“好心办坏事”的典型。

测试类型 目的 负载特征 持续时间 典型发现
阶梯加压 找拐点 逐步递增 每步 2-5 分钟 性能拐点、资源瓶颈
稳态测试 验耐力 70-80% 拐点负载 1-24 小时 内存泄漏、连接池耗尽
峰值测试 验爆发力 瞬间 2-5 倍负载 30 秒 - 2 分钟 自动扩容延迟、限流失效

4.3 系统资源监控:CPU、内存、IO、网络

测试跑起来了,你得知道系统内部发生了什么。系统资源监控是基础中的基础。我习惯用 top、vmstat、iostat、netstat 这些命令行工具,当然也会配合 Prometheus + Grafana 做可视化。

4.3.1 CPU

CPU 监控主要看两个指标:使用率和负载。

  • 用户态 CPU:应用代码在跑,正常。
  • 系统态 CPU:内核在干活,比如系统调用、中断。如果这个值高,说明应用在内核层面有瓶颈。
  • I/O 等待:CPU 在等磁盘或网络。如果这个值高,说明 IO 是瓶颈。
  • 空闲 CPU:如果空闲 CPU 很多,但响应时间已经很高了,说明瓶颈不在 CPU,而在锁、连接池等地方。

我常用的命令:top -H 可以看每个线程的 CPU 占用,配合 jstack 能定位到具体代码行。

4.3.2 内存

内存监控要关注:物理内存使用、Swap 使用、缓存/缓冲区。

  • 物理内存:如果持续增长,大概率是内存泄漏。
  • Swap:如果 Swap 使用量 > 0,说明物理内存不够了。Swap 会导致性能急剧下降,因为磁盘比内存慢几个数量级。
  • 缓存/缓冲区:Linux 会用空闲内存做文件缓存,这是正常的。但如果缓存占用过高,说明 IO 操作频繁。

避坑指南: 我曾经遇到一个项目,内存监控显示物理内存只用了 60%,但系统已经卡得不行。一查,是 JVM 的堆外内存(Direct Buffer)泄漏了。物理内存监控看不到堆外内存,必须用 pmap 或 /proc/meminfo 才能发现。所以,别只看表面指标。

4.3.3 IO

IO 监控包括磁盘 IO和网络 IO。

  • 磁盘 IO:关注 iowait、r/s(读请求数)、w/s(写请求数)、await(平均 IO 等待时间)。如果 await 超过 10ms,说明磁盘性能不够。
  • 网络 IO:关注 rx/s(接收速率)、tx/s(发送速率)、丢包率。如果网络带宽打满,响应时间会直线上升。

我常用的命令:iostat -x 1 看磁盘,sar -n DEV 1 看网络。

4.3.4 网络

网络层面除了带宽,还要关注TCP 连接状态。用 netstat -s 可以看 TCP 重传率、连接超时等。如果重传率超过 1%,说明网络质量有问题,或者应用层有大量小包导致拥塞。

4.4 应用层监控:GC、线程池、连接池

系统资源监控告诉你“机器怎么了”,应用层监控告诉你“应用怎么了”。这两者结合,才能定位问题。

4.4.1 GC 监控

Java 应用最怕 GC 停顿。我主要看这几个指标:

  • GC 频率:Young GC 每秒几次?Full GC 几分钟一次?
  • GC 耗时:每次 GC 停顿多久?如果 Full GC 超过 1 秒,系统肯定会有明显卡顿。
  • 堆内存使用:老年代是否持续增长?如果每次 Full GC 后老年代使用率不下降,说明有内存泄漏。

我习惯用 jstat -gcutil 实时查看,或者用 GC 日志配合 GCeasy 分析。

// jstat 输出示例
 S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
 0.00   0.00  45.23  78.12  92.34  88.56  1234   12.345   5      3.456   15.801

你看,YGC 1234 次,总耗时 12.345 秒,平均每次 10ms,还行。但 FGC 5 次,总耗时 3.456 秒,平均每次 691ms——这个就有点高了,需要关注。

4.4.2 线程池监控

线程池是并发问题的重灾区。我主要看:

  • 活跃线程数:是否接近最大线程数?如果长期接近,说明线程池太小。
  • 队列大小:任务队列是否在增长?如果队列一直增长,说明处理速度跟不上请求速度。
  • 拒绝任务数:如果出现拒绝任务,说明线程池和队列都满了,系统已经过载。

我记得有一次,线程池监控显示活跃线程数只有 10,但队列已经积压了 5000 个任务。一查,是业务代码里有个同步调用,把线程都阻塞住了。这就是“线程池看起来空闲,但实际已经瘫痪”的典型场景。

4.4.3 连接池监控

数据库连接池、HTTP 连接池、Redis 连接池……连接池耗尽是最常见的性能瓶颈之一。我主要看:

  • 活跃连接数:是否接近最大连接数?
  • 等待连接数:如果有线程在等待连接,说明连接池不够用。
  • 连接超时次数:如果出现连接超时,说明连接池配置不合理,或者数据库/下游服务响应太慢。

我的建议: 连接池的最大值不是越大越好。比如数据库连接池,超过一定数量后,数据库本身会成为瓶颈(上下文切换、锁竞争)。我一般建议最大连接数不超过 (CPU 核心数 * 2 + 有效磁盘数)。当然,具体值要通过测试来调整。

4.5 本章知识体系总览

说了这么多,咱们用一张图来总结一下测试执行与监控的核心逻辑:

测试执行与监控知识体系 测试执行与监控核心逻辑 测试执行策略 阶梯加压 稳态测试 峰值测试 监控体系 系统资源监控 应用层监控 CPU 内存 IO 网络 GC 线程池 连接池 输出:性能拐点 / 瓶颈定位 / 优化建议 核心原则 先阶梯加压找拐点 → 稳态测试验耐力 → 峰值测试验爆发力 系统资源监控 + 应用层监控 = 完整的问题定位能力

这张图把整个测试执行与监控的逻辑串起来了。左边是测试执行策略,右边是监控体系,最终汇聚到输出——性能拐点、瓶颈定位、优化建议。你想想看,如果没有阶梯加压,你找不到拐点;没有稳态测试,你发现不了内存泄漏;没有应用层监控,你只能看到“系统慢”,却不知道是 GC 停顿还是线程池阻塞。