2. 性能基础

性能优化这件事,最怕的就是「凭感觉」。

你觉得自己优化了代码,系统应该快了 30%。结果上线后,业务方说没感觉。你说你优化了数据库,QPS 翻了一倍。结果运维说,CPU 反而更高了。

为什么会这样?因为没有基准。

基准测试,说白了就是给系统拍一张「体检 X 光片」。你得先知道它现在什么水平,才能判断你改完以后到底是进步了还是退步了。我见过太多团队,优化做了一堆,最后连个对比数据都拿不出来——那叫瞎忙活。

2.1 基准测试到底在测什么

基准测试不是压力测试,也不是功能测试。它的核心目标只有一个:在可控条件下,测量系统的某项性能指标。

我个人习惯把基准测试分成两类:

  • 微基准测试:针对单一组件或单一操作。比如「Redis 的 SET 命令每秒能跑多少次」、「MySQL 在 16 并发下的简单查询延迟」。
  • 宏基准测试:模拟真实业务场景。比如「模拟 1000 个用户同时浏览商品详情页,系统的吞吐量和响应时间」。

你想想看,如果你连微基准都没跑明白,就直接上宏基准,出了问题你根本不知道是网络瓶颈、磁盘瓶颈还是代码瓶颈。所以我的建议是:先微后宏,分层测试。

核心原则:基准测试不是为了证明系统有多快,而是为了建立一个可重复、可对比的「性能基线」。

2.2 常用工具:三把手术刀

工具不在多,在于会用。我这些年折腾下来,真正高频使用的基准测试工具就三个:sysbench、fio、iperf。它们分别对应 CPU/内存/数据库、磁盘 IO、网络带宽。

2.2.1 sysbench:CPU、内存、数据库一把抓

sysbench 是我用得最多的工具。它支持 CPU、内存、互斥锁、线程、甚至 MySQL 和 PostgreSQL 的基准测试。

先看一个最简单的 CPU 基准测试:

# 测试 CPU 素数计算性能,4 个线程跑 30 秒
sysbench cpu --threads=4 --time=30 run

输出里你会看到 events per second(每秒事件数)。这个值越高,说明 CPU 的计算能力越强。我在项目中遇到过一个问题:两台服务器 CPU 型号一样,但一台跑出来的 events 比另一台低了 20%。查了半天,发现是 BIOS 里关了超线程。嗯,这就是基准测试的价值——它能帮你发现「看起来一样,实际上不一样」的硬件差异。

再看内存测试:

# 测试内存顺序读写,总数据量 10GB
sysbench memory --memory-block-size=1M --memory-total-size=10G run

这里要注意,--memory-block-size 会影响结果。块越小,越考验内存延迟;块越大,越考验内存带宽。我一般会跑两个尺寸:4K 和 1M,分别看延迟和带宽。

数据库测试是 sysbench 的重头戏。以 MySQL 为例:

# 准备数据
sysbench oltp_read_write --table-size=1000000 --mysql-host=127.0.0.1 --mysql-user=root --mysql-password=yourpass prepare

# 运行测试,16 个线程跑 60 秒
sysbench oltp_read_write --threads=16 --time=60 --mysql-host=127.0.0.1 --mysql-user=root --mysql-password=yourpass run

# 清理
sysbench oltp_read_write cleanup

输出里的 tps(每秒事务数)和 qps(每秒查询数)是核心指标。我习惯把结果记录到表格里,方便对比不同参数下的表现。

2.2.2 fio:磁盘性能的照妖镜

磁盘性能是系统性能的常见瓶颈。fio 是业界标准,没有之一。

先看一个典型的随机读写测试:

# 4K 随机读,队列深度 32,直接 IO,测试 60 秒
fio --name=randread --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --direct=1 --size=1G --numjobs=1 --runtime=60 --group_reporting

关键参数解释:

参数 含义 我的建议
--rw 读写模式(randread/randwrite/read/write/rw) 至少跑 randread 和 randwrite
--bs 块大小 4K 模拟数据库,1M 模拟大文件
--iodepth IO 队列深度 NVMe 盘可以到 64,SATA SSD 建议 32
--direct=1 绕过文件系统缓存 必须开,否则测的是缓存不是磁盘

我曾经踩过的坑:用 fio 测试时没加 --direct=1,结果 IOPS 跑到了 50 万,高兴了半天。后来发现数据全在 Page Cache 里,根本没落到磁盘上。加了 --direct=1 之后,真实 IOPS 只有 8 万。所以记住:测磁盘,一定要绕过缓存。

2.2.3 iperf:网络带宽的试金石

网络问题往往最隐蔽。iperf 可以帮你快速确认两台机器之间的实际带宽。

服务端:

iperf3 -s

客户端:

iperf3 -c 192.168.1.100 -t 30 -P 4

-P 4 表示 4 个并行流。我一般会跑三次:单流、多流、反向流。为什么?因为很多网络瓶颈只在多流或反向传输时才暴露出来。比如有一次,客户说两台服务器之间带宽只有 200Mbps,但网卡明明是万兆的。我用 iperf 一测,单流确实只有 200Mbps,但 4 个并行流能跑到 9.2Gbps。最后发现是 TCP 窗口大小没调,单流被限制了。

2.3 如何设计基准测试场景

工具学会了,但场景设计才是真正的功夫。我见过有人拿着 sysbench 默认参数跑一遍,然后说「我的数据库性能很好」——这其实没什么意义。因为你跑的默认场景,跟你的业务场景可能完全不搭。

设计基准测试场景,我总结了四个步骤:

  1. 明确被测对象和指标:你要测什么?CPU、内存、磁盘、网络还是数据库?指标是什么?TPS、延迟、带宽还是 IOPS?
  2. 确定负载模型:你的业务是读多写少还是写多读少?是顺序访问还是随机访问?峰值并发是多少?
  3. 设置测试参数:线程数、数据量、运行时长、队列深度。这些参数要尽量贴近生产环境。
  4. 执行并记录基线:至少跑 3 次,取中位数或平均值。记录所有环境信息(内核版本、硬件配置、驱动版本)。

举个例子。假设你要为 MySQL 做基准测试:

  • 指标:TPS 和 P99 延迟
  • 负载模型:70% 读、30% 写,数据量 1000 万行
  • 参数:并发从 1 开始,逐步增加到 128,每次跑 5 分钟
  • 基线:记录默认配置下的 TPS 和延迟曲线

这样你后续做任何优化——调整 buffer pool、修改刷盘策略、升级硬件——都能拿这个基线来对比。没有基线,优化就是盲人摸象。

2.4 知识体系:基准测试全景图

下面这张图是我自己整理的基准测试知识体系,你可以把它当作一个检查清单。每次做基准测试前,对着这张图过一遍,基本不会漏东西。

基准测试知识体系全景图 基准测试 微基准测试 宏基准测试 压力基准测试 sysbench fio iperf3 wrk / ab 更多 CPU events/s IOPS / 延迟 带宽 / 吞吐 TPS / QPS P99延迟 场景设计四步法:明确指标 → 确定负载 → 设置参数 → 记录基线

2.5 避坑指南与最佳实践

最后,分享几个我这些年总结出来的经验。每一个都是用真金白银换来的教训。

每次测试前,先确认系统状态:用 top、iostat、free -h 看一眼。确保没有其他进程在抢资源。我曾经在跑 sysbench 的时候,后台正好在跑 crontab 备份任务,结果数据全废了。

多次运行,取中位数:单次测试结果不可信。我一般跑 5 次,去掉最高和最低,取中间 3 次的平均值。如果波动超过 10%,说明环境不稳定,先排查问题再继续。

记录一切:内核版本、驱动版本、BIOS 设置、文件系统类型、挂载参数、甚至室温。你永远不知道哪个细节会影响结果。有一次我对比两次测试数据,发现磁盘 IOPS 差了 15%,查了两天,最后发现是第一次测试时磁盘的固件版本不同。从那以后,我每次测试前都会用 dmesg | grep -i firmware 看一眼。

基准测试不是一次性工作。它应该成为你日常运维的一部分。每次系统变更——升级内核、调整参数、更换硬件——都跑一遍基准测试,把结果记录下来。时间长了,你手里就有一份完整的性能基线库。到那时候,任何性能问题在你面前都藏不住。