第二章 性能度量与基准测试:关键性能指标、基准测试工具、负载模型设计、性能数据采集

性能优化这件事,说白了就是“先测量,再动手”。没有度量就没有优化——这句话我反复跟团队讲过。你连系统当前跑多快、瓶颈在哪都不知道,上来就改代码,那跟闭着眼开车没啥区别。

这一章,咱们就聊聊怎么给系统“体检”。我会把关键性能指标、基准测试工具、负载模型设计、数据采集这几个环节串起来讲。嗯,这里要注意:每个环节都有坑,我会把我在项目中踩过的雷也一并说出来。

2.1 关键性能指标(KPI)——你得知道看什么

性能指标不是越多越好。我见过有人把几十个指标堆在监控大屏上,结果出问题时根本不知道看哪个。我个人习惯,先盯住几个核心指标,其他的都是辅助。

2.1.1 响应时间(Latency)

用户发一个请求,到收到响应,花了多久。这个指标最直观。通常我们看三个值:

  • 平均响应时间:容易受极端值影响,比如偶尔一次超时能把平均值拉高很多。
  • 百分位响应时间:比如P99,意思是99%的请求都在这个时间内完成。这个比平均值更有参考价值。
  • 最大响应时间:看系统最差情况的表现。
我的经验: 有一次线上告警,平均响应时间才50ms,但P99已经飙到2秒了。如果只看平均值,你根本发现不了问题。所以,我建议重点盯P95和P99。

2.1.2 吞吐量(Throughput)

单位时间内系统能处理多少请求。常见单位:TPS(每秒事务数)、QPS(每秒查询数)。

吞吐量和响应时间其实是跷跷板关系。你压的请求越多,响应时间通常会变长。找到一个平衡点,才是关键。

2.1.3 资源利用率(Utilization)

CPU、内存、磁盘IO、网络带宽,这些资源用了多少?

  • CPU跑满100%不一定是坏事,但如果是IO等待导致的CPU空闲,那就有问题了。
  • 内存使用率过高,可能会触发Swap,性能直接跳水。
注意: 我曾经遇到一个案例,CPU利用率只有30%,但系统响应已经慢得不行。后来发现是磁盘IO队列深度太大,CPU都在等磁盘。所以,资源利用率要结合其他指标一起看。

2.1.4 错误率(Error Rate)

请求失败的占比。比如HTTP 5xx错误、超时、连接拒绝等。错误率突然升高,往往意味着系统有严重问题。

指标类别 典型指标 说明
响应时间 平均、P50、P95、P99 反映用户体验
吞吐量 TPS、QPS 反映系统处理能力
资源利用率 CPU、内存、磁盘、网络 反映资源瓶颈
错误率 5xx、超时、连接失败 反映系统稳定性

2.2 基准测试工具——选对工具,事半功倍

工具选不对,测试结果可能完全失真。我见过有人用单线程工具压测高并发系统,结果压测工具自己先成了瓶颈。下面是我常用的几款:

2.2.1 轻量级压测:wrk

wrk 是个命令行工具,基于事件驱动,单机就能压出很高的并发。适合快速验证接口性能。

# 用4个线程,保持100个连接,压测30秒
wrk -t4 -c100 -d30s http://your-api.com/endpoint
小技巧: wrk 的脚本功能很强大,可以自定义请求体、Header。我经常用它做简单的接口压测,几秒钟就能出结果。

2.2.2 企业级压测:JMeter

JMeter 功能全面,支持图形界面、分布式压测、丰富的报告。适合复杂的业务场景。

  • 可以录制脚本,模拟用户操作流程。
  • 支持参数化、断言、监听器。
  • 分布式部署时,一台控制机可以调度多台压力机。
避坑指南: 我曾经用JMeter压测一个高并发场景,结果压力机自己的CPU先跑满了。后来发现是JMeter的监听器(比如图形结果树)太耗资源。压测时,记得关掉不必要的监听器,或者用命令行模式运行。

2.2.3 数据库压测:sysbench

专门用来压测数据库的。支持MySQL、PostgreSQL等。可以测试OLTP(在线事务处理)和OLAP(在线分析处理)场景。

# 准备测试数据
sysbench --db-driver=mysql --mysql-user=root --mysql-password=xxx \
         --mysql-db=test --table-size=1000000 oltp_read_write prepare

# 运行压测
sysbench --db-driver=mysql --mysql-user=root --mysql-password=xxx \
         --mysql-db=test --threads=64 --time=60 oltp_read_write run

2.3 负载模型设计——别让测试脱离现实

负载模型设计,说白了就是模拟真实用户的行为。你想想看,如果真实场景是“用户登录后浏览商品再下单”,但你只压测一个“查询商品列表”的接口,那结果能准吗?

2.3.1 确定业务场景

先梳理出核心业务流程。比如电商系统:

  1. 用户登录(10%的请求)
  2. 搜索商品(30%的请求)
  3. 查看商品详情(40%的请求)
  4. 加入购物车(10%的请求)
  5. 提交订单(10%的请求)

这个比例不是拍脑袋定的,最好从生产环境的日志里统计出来。

2.3.2 设计并发模型

并发用户数不是越多越好。我建议分几个阶段:

  • 基准测试:低并发,比如10个用户,看看系统基线性能。
  • 负载测试:逐步增加并发,比如从10到100、200、500,观察性能变化。
  • 压力测试:持续增加并发,直到系统出现瓶颈或崩溃,找到系统的极限。
  • 稳定性测试:在某个并发下持续运行几小时甚至几天,看系统会不会内存泄漏、性能衰减。
核心思路: 负载模型要尽量贴近真实。我曾经帮一个客户做压测,他们只压了“查询”接口,结果上线后“下单”接口直接被打挂了。因为下单涉及写操作和事务,性能差很多。

2.3.3 数据准备

测试数据也要模拟真实情况。比如:

  • 用户数据要有不同的等级、不同的历史订单量。
  • 商品数据要有热门商品和冷门商品。
  • 数据库里要有足够多的数据,不能只有几十条记录。
注意: 我曾经犯过一个错,测试数据只有100条,结果压测时所有请求都命中缓存,性能看起来特别好。上线后数据量到了100万,缓存失效,性能直接崩了。所以,数据量要跟生产环境接近。

2.4 性能数据采集——把数据捞出来

压测跑起来了,数据怎么收?光看压测工具的报告是不够的,你得从系统层面、应用层面、数据库层面全方位采集。

2.4.1 系统层面

topvmstatiostatnetstat 这些命令,采集CPU、内存、磁盘、网络的数据。

# 每2秒采集一次CPU和内存数据
vmstat 2

# 采集磁盘IO数据
iostat -x 2

# 采集网络连接数
netstat -an | grep ESTABLISHED | wc -l

2.4.2 应用层面

应用日志里要打印关键信息:每个请求的处理时间、SQL执行时间、外部调用时间。我习惯用APM工具(比如SkyWalking、Pinpoint)来采集,它们能自动生成调用链,一眼就能看出慢在哪。

2.4.3 数据库层面

数据库的慢查询日志一定要开。还有 show processlistshow engine innodb status 这些命令,能帮你看到当前数据库在干什么。

-- 查看当前正在执行的SQL
SHOW FULL PROCESSLIST;

-- 查看InnoDB引擎状态(重点关注死锁、事务)
SHOW ENGINE INNODB STATUS\G

2.4.4 数据采集的注意事项

  • 采样频率:别太高,否则采集工具本身会消耗资源。一般1-5秒一次就够了。
  • 时间对齐:所有采集的数据要能对齐到同一个时间点,方便分析关联关系。
  • 持久化:把数据存到时序数据库(比如Prometheus、InfluxDB)里,方便后续做趋势分析。

总结一下: 性能度量与基准测试,核心就是“选对指标、用对工具、建对模型、收对数据”。这四个环节环环相扣,缺一个都不行。

我个人习惯,每次压测前先画一个数据采集清单,把要看的指标、工具、命令都列出来。这样跑起来才不会手忙脚乱。

性能度量与基准测试知识体系 性能度量与基准测试 关键性能指标(KPI) 响应时间(Latency) 吞吐量(Throughput) 资源利用率 错误率 基准测试工具 wrk (轻量级) JMeter (企业级) sysbench (数据库) 负载模型设计 业务场景确定 并发模型设计 测试数据准备 性能数据采集 系统层面 (top/vmstat) 应用层面 (APM/日志) 数据库层面 (慢查询) 选对指标 → 用对工具 → 建对模型 → 收对数据
最后说一句: 性能测试不是一次性工作。系统在变,业务在变,负载模型也要跟着变。我建议每个大版本上线前,都跑一轮完整的基准测试,把数据存下来做对比。这样系统性能是变好了还是变差了,一目了然。
专注资料整理