开篇引入
"这个服务器能扛多少QPS?" "我们打算上8.0版本,性能会提升还是下降?" "换了SSD后,性能能提升多少?"
面对这些问题,你能给出一个准确的答案吗?如果不能,说明你需要一个基准测试。
基准测试不是"跑个SQL看看多快"那么简单。一套科学的基准测试能帮你:
- 在上线前发现性能瓶颈
- 量化系统容量
- 对比不同配置的差异
- 验证优化效果
《高性能MySQL》第3章花了不少篇幅讲基准测试,这篇文章帮你把方法论和实践结合起来。
基准测试的两种类型
全栈测试(Full-Stack Testing)
测试整个应用栈,从前端到数据库。优点是能发现各层之间的问题,缺点是需要完整的测试环境。
适用场景:
- 评估整体性能
- 测试新版本升级
- 容量规划
单组件测试(Single-Component Testing)
只测试MySQL本身。优点是环境简单,容易复现问题,缺点是忽略应用层的影响。
适用场景:
- 对比不同MySQL版本
- 测试特定查询性能
- 硬件选型对比
基准测试的设计原则
1. 使用真实数据
测试数据必须接近生产环境:
- 数据量要相当(至少是生产环境的10%)
- 数据分布要真实(不要全是测试数据)
- 查询要真实(不要简化查询)
2. 使用真实查询
-- 错误示范:简化查询
SELECT * FROM users WHERE id = 1;
-- 正确做法:使用实际业务查询
SELECT u.*, o.*
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
AND u.created_at > '2024-01-01'
ORDER BY u.last_login DESC
LIMIT 100;
3. 预热(Warm-up)
测试前必须预热:
-- 执行典型的预热查询
SELECT COUNT(*) FROM large_table;
SELECT * FROM users WHERE id BETWEEN 1 AND 1000;
SELECT * FROM orders WHERE date >= CURDATE() - INTERVAL 30 DAY;
4. 多轮测试取平均
单次测试结果不可靠,至少跑3-5轮:
# 跑5轮,取平均值
for i in 1 2 3 4 5; do
sysbench oltp_read_write run --threads=16 | grep -E 'queries:|tps:|latency:'
done
sysbench:最流行的MySQL基准测试工具
安装
# Ubuntu/Debian
apt-get install sysbench
# macOS
brew install sysbench
# 或者从源码编译
git clone https://github.com/akopytov/sysbench.git
./autogen.sh
./configure
make -j$(nproc)
make install
准备测试数据
# 创建10张表,每张表100万行数据
sysbench oltp_read_write \
--db-driver=mysql \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-user=sbtest \
--mysql-password=password \
--mysql-db=sbtest \
--tables=10 \
--table-size=1000000 \
--threads=16 \
prepare
执行测试
# OLTP读写混合测试(模拟真实业务)
sysbench oltp_read_write \
--db-driver=mysql \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-user=sbtest \
--mysql-password=password \
--mysql-db=sbtest \
--tables=10 \
--table-size=1000000 \
--threads=16 \ # 16个并发线程
--time=60 \ # 测试60秒
--rate=0 \ # 0表示不限速,按最大能力跑
run
# 只读测试(模拟报表查询)
sysbench oltp_read_only \
--threads=32 \
--time=60 \
run
# 只写测试(模拟写入压力)
sysbench oltp_write_only \
--threads=16 \
--time=60 \
run
解读测试结果
SQL statistics:
queries performed: 1256847 # 总查询数
reads: 8797931 # 读操作数
writes: 2094755 # 写操作数
other: 1675804 # 其他操作(COMMIT等)
transactions: 104672 (1744.44 per sec.) # TPS
queries: 1256847 (20953.12 per sec.) # QPS
latency events: 104672
Avg: 9.17ms # 平均延迟
95th percentile: 15.23ms # 95百分位延迟
max: 89.45ms # 最大延迟
关键指标解读:
| 指标 | 含义 | 关注点 |
|---|---|---|
| TPS | 每秒事务数 | 越高越好 |
| QPS | 每秒查询数 | 越高越好 |
| Avg latency | 平均延迟 | 越低越好 |
| 95th percentile | 95%请求的延迟 | 决定用户体验 |
| max latency | 最大延迟 | 关注异常值 |
清理测试数据
sysbench oltp_read_write \
--db-driver=mysql \
--mysql-db=sbtest \
cleanup
不同场景的基准测试
场景1:评估服务器容量
# 从单线程开始,逐步增加并发
for threads in 1 2 4 8 16 32 64 128; do
echo "=== Testing with $threads threads ==="
sysbench oltp_read_write \
--threads=$threads \
--time=60 \
--report-interval=5 \
run | grep -E 'transactions:|queries:|latency:'
done
绘制并发数vs吞吐量的曲线,找到系统的拐点。
场景2:对比InnoDB配置
# 测试前:innodb_buffer_pool_size = 1G
sysbench oltp_read_write --threads=16 run
# 修改配置后:innodb_buffer_pool_size = 4G
# 需要重启MySQL
sudo systemctl restart mysql
# 重新预热和测试
sysbench ... prepare
sleep 60 # 预热
sysbench oltp_read_write --threads=16 run
场景3:验证优化效果
-- 优化前:没有索引
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'paid';
-- 创建索引
CREATE INDEX idx_user_status ON orders(user_id, status);
-- 再次测试
场景4:压测极限
# 持续加压直到系统崩溃,记录临界点
sysbench oltp_read_write \
--threads=256 \
--time=300 \
--forced-shutdown=5 \ # 测试结束后强制关闭
run
# 观察:
# - 系统是否OOM
# - 连接数是否打满
# - 响应时间是否急剧上升
tpcc-mysql:TPC-C标准测试
TPC-C是OLTP领域的行业标准测试。
安装
git clone https://github.com/Percona-Lab/tpcc-mysql.git
cd tpcc-mysql/src
make
创建表结构
mysqladmin create tpcc1000
mysql -u root -p tpcc1000 < create_table.sql
mysql -u root -p tpcc1000 < add_fkey_idx.sql
加载数据
# 加载1000个仓库的数据(数据量较大,需要较长时间)
./tpcc_load localhost tpcc1000 root password 1000 10 10
# 参数说明:
# 1000: 仓库数(每个仓库约70MB数据)
# 10: 加载线程数
# 10: 预加载的数据
执行测试
./tpcc_start -h localhost -d tpcc1000 -u root -p password \
-w 1000 -c 32 -r 300 -l 600 \
-i 10 -f tpcc_result.txt
# 参数说明:
# -w 1000: 1000个仓库
# -c 32: 32个并发客户端
# -r 300: 预热300秒
# -l 600: 测试持续600秒
# -i 10: 每10秒报告一次
# -f: 结果输出到文件
TPC-C结果解读
TERMINATING 10, 000SCALE: 1000
Warmup: 300 sec
Measuring: 600 sec
90% response time: XX.XX ms
Around 10% response time: XX.XX ms
TpmC (NewOrders): XXXXX.XX
TpmC是TPC-C的核心指标,表示每分钟处理的新订单数。TpmC越高,系统处理OLTP事务的能力越强。
基准测试的常见误区
误区1:测试时间太短
# 错误:只跑10秒
--time=10
# 正确:至少跑60秒,足够系统稳定
--time=60
误区2:不预热就测试
冷缓存下的测试结果没有参考价值。
误区3:只看平均值
平均值会掩盖问题。一定要看百分位数:
- 50百分位:中位数用户体验
- 95百分位:大多数用户的体验
- 99百分位:最差1%用户
误区4:忽略网络延迟
如果应用和数据库不在同一台机器,测试时也要考虑网络开销。
误区5:单点测试
至少测试3次取平均值,剔除异常值。
基准测试 checklist
测试前检查清单:
- MySQL配置已经过优化
- 测试数据量接近生产
- 已执行预热
- 测试时间足够长(≥60秒)
- 记录测试开始时的系统状态
- 测试后确认无残留连接/进程
测试中监控:
- CPU使用率
- 内存使用
- 磁盘I/O
- 网络流量
- MySQL连接数
小结
- 基准测试是科学,不是玄学:用真实数据、真实查询、多轮测试取平均
- sysbench是最常用的MySQL基准测试工具:适合快速验证
- TPC-C是OLTP标准测试:适合评估真实业务处理能力
- 关注百分位数:平均值会掩盖问题,95th percentile更能反映用户体验
- 找到系统拐点:并发数增加到一定程度后,吞吐量不再增加甚至下降,这就是拐点
- 记录一切:每次测试都要记录配置、数据量、结果,便于对比
基准测试的目的是回答"系统能做什么",而不是"系统做什么最快"。明确测试目标,选择合适的工具,设计合理的场景——这是性能优化的基本功。
延伸阅读
- sysbench官方文档:github.com/akopytov/sy…
- TPC-C规范:www.tpc.org/tpcc/
- 《高性能MySQL》第3章 Performance Schema部分