韩老魔的博客0XHANNIBA1 · NOTES

性能测试

一、性能测试是什么

性能测试的核心目标是回答一个问题:系统能扛多大压力,瓶颈在哪里?

它不是简单地"压一下看看",而是通过科学的方法,找到系统的能力边界和优化方向。


二、测试类型(按目的分)

类型 目的 做法 典型产出
基准测试 摸清系统正常能力 单接口/单场景,逐步加压 最大 TPS、RT 基线
负载测试 验证能否满足预期目标 按目标值压(如 1000 TPS) 通过/不通过
压力测试 找系统极限,什么时候崩 持续加压直到崩溃 极限值、崩溃表现
稳定性测试 长时间运行有无问题 中等压力跑 2~24 小时 内存泄漏、GC 问题
容量测试 当前配置能支撑多少用户 阶梯加压 + 资源监控 容量规划建议
浪涌测试 突发流量能否扛住 瞬间拉高再降低 系统恢复能力

怎么选择测试类型?

1
2
3
4
5
新系统上线前 → 基准测试 + 负载测试
大促活动前 → 压力测试 + 容量测试
日常迭代 → 基准测试(回归)
核心系统 → 稳定性测试
秒杀场景 → 浪涌测试

三、测试场景(按业务分)

3.1 基础场景

场景 说明 适用情况
单接口测试 对单个 API 压测 性能摸底、问题定位
单业务流程 完整链路(如下单=查库存→创建订单→扣款) 链路性能验证

3.2 进阶场景

场景 说明 关键点
混合场景 模拟真实流量比例 接口比例要贴近生产
秒杀/抢购 瞬间高并发打同一资源 集合点、库存一致性、限流
大数据量 处理大量数据(导出、批量) 单请求处理能力、超时
长连接 WebSocket、消息推送 连接数上限、心跳、断连
文件上传下载 大文件传输 带宽、超时、断点续传

3.3 混合场景设计示例

1
2
3
4
5
6
7
电商网站真实流量比例:
├── 首页浏览 40%
├── 商品搜索 25%
├── 商品详情 20%
├── 加入购物车 8%
├── 下单支付 5%
└── 用户登录 2%

混合场景的价值:单接口都没问题,混合起来可能有资源竞争。


四、性能指标体系

4.1 业务指标(用户视角)

指标 全称 含义 关注点
RT Response Time 响应时间 P90/P99 比平均值重要
TPS Transactions Per Second 每秒事务数 业务处理能力
QPS Queries Per Second 每秒请求数 接口吞吐量
并发数 Concurrency 同时在处理的请求数 系统承载能力
错误率 Error Rate 失败请求占比 压力大了是否报错
吞吐量 Throughput 单位时间处理的数据量 网络/IO 能力

响应时间的正确理解

1
2
3
4
5
平均 RT = 100ms  ← 看起来不错?
P90 RT = 150ms ← 90% 的请求在 150ms 内
P99 RT = 800ms ← 有 1% 的请求要 800ms!

结论:平均值会掩盖长尾问题,要看分位数

TPS vs QPS

1
2
3
4
5
TPS:一个事务可能包含多个请求(下单=查库存+扣款+创建订单)
QPS:纯粹的请求数量

接口压测一般说 QPS
业务压测一般说 TPS

4.2 系统资源指标(服务器视角)

指标 监控命令 瓶颈信号 可能原因
CPU top, vmstat 持续 > 80% 计算密集、死循环、GC
内存 free, top 持续上涨不释放 内存泄漏、缓存过大
磁盘 I/O iostat, iotop iowait 高、util 100% 大量读写、日志过多
网络 iftop, netstat 带宽打满、连接数耗尽 数据量大、连接泄漏

CPU 指标详解

1
2
3
4
5
6
7
%user   - 用户态 CPU(应用代码)
%system - 内核态 CPU(系统调用)
%iowait - 等待 IO 的 CPU(磁盘慢)
%idle - 空闲 CPU

iowait 高 → 瓶颈在磁盘,不是 CPU
user 高 → 瓶颈在应用代码

内存指标详解

1
2
3
4
5
6
used     - 已使用内存
free - 完全空闲
buff/cache - 系统缓存(可回收)
available - 实际可用 = free + 可回收的 cache

看 available,不是 free

4.3 中间件指标(组件视角)

数据库(MySQL)

指标 含义 关注点
QPS/TPS 查询和事务数 数据库压力
慢查询数 超过阈值的 SQL 需要优化的 SQL
连接数 当前连接 / 最大连接 连接池是否够用
锁等待 行锁、表锁等待时间 并发冲突
缓冲池命中率 Buffer Pool Hit Ratio 内存是否够用

Redis

指标 含义 关注点
命中率 Hit / (Hit + Miss) 缓存有效性
内存使用 used_memory 是否接近上限
连接数 connected_clients 连接池配置
阻塞 Key blocked_clients 慢操作

消息队列(Kafka/RabbitMQ)

指标 含义 关注点
堆积量 未消费消息数 消费者是否跟得上
生产速率 每秒写入消息数 生产压力
消费速率 每秒消费消息数 消费能力
延迟 消息从生产到消费的时间 实时性

4.4 JVM 指标(Java 应用)

指标 含义 关注点
堆内存 Heap 使用量 是否频繁接近上限
GC 次数 Young GC / Full GC Full GC 频繁说明有问题
GC 时间 每次 GC 耗时 影响 RT
线程数 活跃线程数量 线程池是否够用

五、常用工具

5.1 压测工具

工具 特点 适用场景
JMeter GUI + 脚本,功能全 复杂业务场景、协议多
Locust Python 编写脚本 开发友好、灵活
wrk 命令行,性能极高 简单接口、极限压测
ab Apache 自带,简单 快速验证
k6 JS 脚本,现代化 CI/CD 集成
Gatling Scala,报告漂亮 自动化、报告要求高

5.2 监控工具

工具 用途
Prometheus + Grafana 指标采集 + 可视化
node_exporter 主机资源监控
cAdvisor 容器监控
Arthas Java 应用诊断
perf / FlameGraph CPU 火焰图

5.3 分析工具

工具 用途
慢查询日志 定位慢 SQL
Explain 分析 SQL 执行计划
jstack Java 线程 dump
jmap Java 内存 dump
MAT 内存泄漏分析

六、性能测试流程

6.1 标准流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1. 需求分析
├── 测试目标是什么?(TPS 达到 1000?RT < 200ms?)
├── 测试哪些场景?
└── 测试环境要求?

2. 环境准备
├── 测试环境搭建(尽量接近生产)
├── 监控部署(Prometheus + Grafana)
├── 数据准备(测试数据量级)
└── 压测工具准备

3. 脚本开发
├── 接口脚本编写
├── 参数化配置
├── 关联处理
└── 脚本调试验证

4. 执行测试
├── 基准测试(摸底)
├── 负载测试(验证目标)
├── 压力测试(找极限)
└── 稳定性测试(长时间)

5. 结果分析
├── 指标是否达标
├── 瓶颈在哪里
└── 优化建议

6. 测试报告
├── 测试结论
├── 数据图表
└── 问题和建议

6.2 瓶颈定位思路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
RT 变长 / TPS 上不去

├─ CPU 高?
│ ├─ user 高 → 代码问题(算法、死循环)
│ └─ iowait 高 → 磁盘问题

├─ 内存高?
│ ├─ 持续上涨 → 内存泄漏
│ └─ GC 频繁 → 堆内存不够

├─ CPU/内存都不高?
│ ├─ 数据库慢查询?
│ ├─ 连接池打满?
│ ├─ 锁竞争?
│ └─ 外部依赖慢?

└─ 网络?
├─ 带宽打满
└─ 连接数耗尽

七、Q&A

7.1 基础问题

Q:你们性能测试关注哪些指标?

三层:业务指标(RT、TPS、错误率)、系统资源(CPU、内存、IO、网络)、中间件指标(数据库、缓存)。重点是把指标放在同一时间轴上看,找到瓶颈。

Q:RT 看平均值还是 P99?

P99 更重要。平均值会被大量正常请求拉低,掩盖长尾问题。比如平均 100ms,但 P99 是 2s,说明有 1% 用户体验很差。

Q:TPS 和 QPS 的区别?

TPS 是事务,一个事务可能包含多个请求;QPS 是纯请求数。接口压测一般说 QPS,业务压测说 TPS。

7.2 场景问题

Q:你们预估的 QPS 是怎么得出的?

两种方法:1)看生产监控历史峰值;2)业务推算:日活 × 人均请求数 ÷ 集中时段秒数,再乘 2~3 倍余量。

Q:混合场景怎么设计?

分析生产日志或埋点数据,统计各接口调用比例,按比例配置并发。比如浏览 60%、搜索 25%、下单 5%。

Q:秒杀场景怎么测?

用集合点让请求同时发出,关注:1)限流是否生效;2)库存一致性;3)系统是否雪崩。

Q:稳定性测试发现过什么问题?

内存泄漏(内存持续上涨不释放)、连接泄漏(连接数持续增长)、GC 时间变长、RT 逐渐上涨。

7.3 定位问题

Q:TPS 上不去,怎么排查?

先看资源:CPU、内存、IO 哪个高。如果都不高,看数据库慢查询、连接池、锁竞争、外部依赖。

Q:CPU 高怎么定位?

看是 user 高还是 iowait 高。user 高用火焰图找热点代码;iowait 高说明磁盘是瓶颈。

Q:内存泄漏怎么定位?

多次 dump 内存快照,用 MAT 对比,看哪些对象持续增长。


八、实战检查清单

测试前

  • 明确测试目标(TPS、RT、错误率要求)
  • 测试环境配置记录(CPU、内存、带宽)
  • 监控部署完成(能看到实时数据)
  • 测试数据准备(数量级合理)
  • 脚本调试通过(单次请求正常)

测试中

  • 逐步加压,不要一上来就拉满
  • 实时观察监控,发现异常及时记录
  • 每轮测试记录:并发数、TPS、RT、错误率、资源使用
  • 出现拐点时停下来分析

测试后

  • 整理各轮数据,画趋势图
  • 定位瓶颈点
  • 输出测试报告
  • 提出优化建议

九、附录:常用命令速查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# CPU
top # 整体情况
vmstat 1 # 每秒刷新
mpstat -P ALL 1 # 每个核心

# 内存
free -h # 内存概况
top -o %MEM # 按内存排序

# 磁盘
iostat -x 1 # IO 详情
iotop # IO 排行

# 网络
iftop # 带宽监控
netstat -ant | wc -l # 连接数
ss -s # 连接统计

# 进程
ps aux --sort=-%cpu # CPU 排行
ps aux --sort=-%mem # 内存排行

# Java
jstat -gc <pid> 1000 # GC 监控
jstack <pid> # 线程 dump
jmap -heap <pid> # 堆内存概况

总结

性能测试的本质是:给系统施加压力,观察表现,找到瓶颈,指导优化。

记住这个思考框架:

1
目标 → 场景 → 指标 → 执行 → 分析 → 优化

不是为了压测而压测,而是为了回答业务问题:系统能不能扛住?扛不住的话问题在哪?

Tweaks