Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • MySQL实战45讲学习笔记
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • MySQL实战45讲学习笔记
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL

    • MySQL 运维知识地图:从入门配置到高可用排障
    • MySQL8 配置文件 my.cnf 重要参数解读
    • MySQL 导出 CSV 中文乱码:字符集链路从头讲一遍
    • MySQL 角色管理
    • MySQL网络抓包审计
    • MySQL 性能压测:Sysbench 1.0 实战
      • 1. 网上大量教程还停在 sysbench 0.5
      • 2. 压测的意义在于「可比较」
      • 3. 安装与完整压测流程
        • 3.1 安装
        • 3.2 准备测试库与账号
        • 3.3 三个阶段:prepare / run / cleanup
        • 3.4 读懂结果
        • 3.5 做成可比较的对比测试
        • 3.6 常用测试模型的取舍
      • 4. 四个高频坑
        • 4.1 抄了 0.5 的命令,报 unknown option
        • 4.2 测出来的数字高得不真实
        • 4.3 prepare 阶段极慢
        • 4.4 结果每次跑都差很多
      • 5. 可复用要点
      • 6. 延伸阅读
    • MySQL Router 实现读写分离
    • Gh-ost重建表,清除表碎片率
    • MySQL MGR配合MySQL-router实现innodb-cluster
    • MySQL 快速分析binlog定位问题
    • MySQL执行计划分析
    • DBA常用SQL和命令整理备查
    • 单表数据同步方案选型:为什么不该用 mysqldump 做「实时同步」
    • MySQL的事务隔离级别
    • MySQL存储过程批量生成数据
    • MySQL insert on duplicate key update,replace into , insert ignore的理解
    • MySQL不同字符集之间的区别和选择
    • MySQL为什么有时候会选错索引
    • MySQL死锁问题
    • MySQL使用SQL语句查重去重
    • MySQLdump逻辑备份
    • MySQL 基于 GTID 主从复制:跳过异常事务的正确姿势
    • MySQL8快速克隆插件使用指南
    • MySQL8双1设置保障安全
    • MySQL锁
    • innodb cluster安装
    • OPTIMIZE TABLE 和 ANALYZE TABLE 的区别:用实测数据说话
    • MySQLReplicaSet 安装
    • 脚本实现MySQL ReplicaSet 高可用
    • MySQL 的 Left join、Right join 和 Inner join 的区别
    • ORDER BY 配合 LIMIT 触发的索引选择陷阱
  • Redis

  • Keydb

  • TiDB

  • MongoDB

  • Elasticsearch

  • Kafka

  • victoriametrics

  • BigData

  • Sqlserver

  • 数据库
  • MySQL
Carry の Blog
2026-07-29
目录

MySQL 性能压测:Sysbench 1.0 实战原创

# MySQL 性能压测:Sysbench 1.0 实战

# 1. 网上大量教程还停在 sysbench 0.5

搜「sysbench 压测 MySQL」,很容易抄到这样一段安装步骤:

git clone https://github.com/akopytov/sysbench.git
git checkout 0.5                       # 这里就错了
./autogen.sh && ./configure && make -j && make install
1
2
3

照着做会掉进一连串对不上的坑:脚本目录不是 /usr/local/share/sysbench,命令语法也不是 --test=/path/to/oltp.lua。sysbench 从 1.0 开始做了不兼容的重构,0.5 时代的用法几乎全部失效:

0.5(已淘汰) 1.0+(现行)
指定测试 --test=/usr/local/share/sysbench/oltp.lua 直接写测试名 oltp_read_write
测试脚本 oltp.lua、parallel_prepare.lua oltp_read_write.lua、oltp_read_only.lua 等一组
脚本路径 /usr/local/share/sysbench /usr/share/sysbench
线程数 --num-threads --threads
压测时长 --max-time --time
请求总数 --max-requests --events
表数量 --oltp-tables-count --tables
表行数 --oltp-table-size --table-size

所以看到教程里出现 --num-threads 或 --test=,基本可以判定它是 0.5 时代的内容,别再往下抄。

# 2. 压测的意义在于「可比较」

跑一次压测拿到一个 QPS 数字,本身没有价值。压测真正的用处是在两个变量之间做对比:换了参数前后、换了硬件前后、升级版本前后。

要让对比成立,有三个前提必须守住:

  • 数据量要超出缓冲池。如果测试表能被 innodb_buffer_pool_size 全部装下,测的就是内存性能,改任何磁盘相关参数都看不出差别。
  • 要有预热。InnoDB 冷启动时缓冲池是空的,前几十秒的数据严重偏低,必须丢弃。
  • 压测机与数据库分离。sysbench 本身吃 CPU,和 mysqld 抢资源会让结果失真,尤其在高并发档位。

另外要清楚 sysbench 测的是通用 OLTP 模型,不是你的业务。它适合回答「这台机器/这组参数的相对能力如何」,不适合回答「我的业务能扛多少 QPS」——后者只能用贴近真实的 SQL 去测。

# 3. 安装与完整压测流程

# 3.1 安装

优先用包管理器,别再从源码编译:

# RHEL / CentOS / Rocky
curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
sudo yum -y install sysbench

# Debian / Ubuntu
curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash
sudo apt -y install sysbench
1
2
3
4
5
6
7

确认版本,必须是 1.0 以上:

sysbench --version
1

预期输出:

sysbench 1.0.20
1

看看有哪些内置测试可用:

ls /usr/share/sysbench/*.lua
1

预期输出:

/usr/share/sysbench/bulk_insert.lua        /usr/share/sysbench/oltp_read_write.lua
/usr/share/sysbench/oltp_delete.lua        /usr/share/sysbench/oltp_update_index.lua
/usr/share/sysbench/oltp_insert.lua        /usr/share/sysbench/oltp_update_non_index.lua
/usr/share/sysbench/oltp_point_select.lua  /usr/share/sysbench/oltp_write_only.lua
/usr/share/sysbench/oltp_read_only.lua     /usr/share/sysbench/select_random_points.lua
1
2
3
4
5

# 3.2 准备测试库与账号

CREATE DATABASE sbtest;
CREATE USER 'sbtest'@'%' IDENTIFIED BY '<password>';
GRANT ALL PRIVILEGES ON sbtest.* TO 'sbtest'@'%';
FLUSH PRIVILEGES;
1
2
3
4

把连接参数抽成变量,避免每条命令重复一长串:

SB_CONN="--mysql-host=192.0.2.10 --mysql-port=3306 \
         --mysql-user=sbtest --mysql-password=<password> --mysql-db=sbtest"
1
2

# 3.3 三个阶段:prepare / run / cleanup

sysbench 的每个测试都遵循这三步。

准备数据——--tables × --table-size 决定数据量。10 张表 × 100 万行大约 2.5GB,务必确保它大于缓冲池:

sysbench oltp_read_write $SB_CONN \
  --tables=10 --table-size=1000000 \
  --threads=8 \
  prepare
1
2
3
4

执行压测:

sysbench oltp_read_write $SB_CONN \
  --tables=10 --table-size=1000000 \
  --threads=64 \
  --time=300 \
  --warmup-time=60 \
  --report-interval=10 \
  --rand-type=uniform \
  --db-ps-mode=disable \
  run
1
2
3
4
5
6
7
8
9

关键参数:

  • --warmup-time=60:预热 60 秒且不计入统计,这是 1.0 才有的参数,比手工丢弃前几十秒可靠
  • --report-interval=10:每 10 秒打一行中间结果,用来观察是否平稳;抖动大说明有检查点或刷脏干扰
  • --rand-type=uniform:默认是 special(热点集中),会让缓存命中率虚高。想测真实磁盘能力就用 uniform
  • --db-ps-mode=disable:关闭预处理语句,更接近多数应用的行为
  • --time=300:至少 5 分钟,太短测不到检查点行为

清理:

sysbench oltp_read_write $SB_CONN --tables=10 cleanup
1

# 3.4 读懂结果

预期输出(节选):

SQL statistics:
    queries performed:
        read:                            1120504
        write:                           320144
        other:                           160072
        total:                           1600720
    transactions:                        80036  (266.75 per sec.)
    queries:                             1600720 (5335.02 per sec.)

Latency (ms):
         min:                                    2.14
         avg:                                   59.87
         max:                                  892.31
         95th percentile:                      142.39
         sum:                              4791024.55

Threads fairness:
    events (avg/stddev):           1250.5625/12.35
    execution time (avg/stddev):   299.4390/0.11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

看结果的顺序建议是:

  1. 95th percentile 优先于 avg。平均延迟会被大量快请求拉低,真正影响用户体验的是长尾。
  2. max 与 95th 的差距。差一个数量级通常意味着有周期性停顿——检查点、刷脏页、或 binlog 落盘。
  3. transactions per sec 才是 OLTP 场景的核心指标,queries per sec 会随测试模型的语句构成变化而变化,跨模型不可比。
  4. Threads fairness 的 stddev。偏大说明线程间调度不均,可能是压测机资源不足。

# 3.5 做成可比较的对比测试

单点数字没意义,要跑一组。典型做法是固定其他条件、只变并发数:

for t in 8 16 32 64 128 256; do
  echo "=== threads=$t ==="
  sysbench oltp_read_write $SB_CONN \
    --tables=10 --table-size=1000000 \
    --threads=$t --time=180 --warmup-time=30 \
    --rand-type=uniform --db-ps-mode=disable \
    run | grep -E "transactions:|95th percentile:"
done
1
2
3
4
5
6
7
8

把结果画成「并发数 → TPS」曲线,能看到明显的拐点:TPS 到顶后不再上升、而延迟继续攀升的那个并发数,就是这套配置的实际承载上限。超过该点继续加并发只会恶化延迟。

# 3.6 常用测试模型的取舍

测试 读写比 用途
oltp_read_only 纯读 测缓冲池与 CPU 上限
oltp_write_only 纯写 测 redo/binlog 落盘与 IO 能力
oltp_read_write 约 7:3 综合场景,最常用
oltp_point_select 纯主键点查 测极限 QPS 与网络往返开销
bulk_insert 批量插入 测导入吞吐

调 innodb_flush_log_at_trx_commit、sync_binlog 这类持久性参数时,用 oltp_write_only 差异最明显;调缓冲池大小则用 oltp_read_only。相关参数见MySQL8 配置文件 my.cnf 重要参数解读。

# 4. 四个高频坑

# 4.1 抄了 0.5 的命令,报 unknown option

症状:sysbench: unrecognized option '--num-threads',或 --test=... 提示找不到文件。

原因:这些都是 0.5 的参数名,1.0 已重命名(见第 1 节对照表)。

解药:按对照表逐个替换,测试名直接写 oltp_read_write,不要写 .lua 路径。

# 4.2 测出来的数字高得不真实

症状:几十万 QPS,改什么参数都不变。

原因:两种可能——测试数据集小于缓冲池,全部命中内存;或者用了默认的 --rand-type=special,访问高度集中在热点区。

解药:把 --tables × --table-size 放大到缓冲池的 2 倍以上,并显式指定 --rand-type=uniform。

# 4.3 prepare 阶段极慢

症状:准备 1000 万行数据要跑几十分钟。

原因:prepare 默认单线程建数据。

解药:给 prepare 也加并发,--threads 设为表数量即可(每张表一个线程):

sysbench oltp_read_write $SB_CONN --tables=10 --table-size=1000000 --threads=10 prepare
1

注意并发数超过表数量不会更快,因为 sysbench 按表切分任务。

# 4.4 结果每次跑都差很多

症状:同样的命令,两次 TPS 相差 30% 以上。

原因:常见于三点——没有预热、压测时长太短没跨过检查点、或压测机与数据库同机互抢资源。

解药:固定 --warmup-time=60 --time=300,压测端独立部署,并且每轮之间让数据库空转一会儿再开始下一轮。测完记得对比 --report-interval 打出的中间行是否平稳,不平稳的结果不要采信。

# 5. 可复用要点

  1. 先确认版本再抄命令。出现 --num-threads / --test= 就是 0.5 的过时内容,1.0 的参数名完全不同。
  2. 数据量必须大于缓冲池,否则测的是内存不是数据库。
  3. 看 95 分位而不是平均值,并关注 max 与 95 分位的差距来发现周期性停顿。
  4. 压测的产出是曲线不是数字。跑一组并发档位找到 TPS 拐点,才能说明系统的实际承载上限。
  5. 按调优目标选测试模型:调持久性参数用 oltp_write_only,调缓冲池用 oltp_read_only。

# 6. 延伸阅读

  • MySQL8 配置文件 my.cnf 重要参数解读——压测时最常调整的那些参数
  • MySQL执行计划——单条 SQL 慢的分析方法
  • MySQL8设置slowlog记录所有语句——压测期间抓取全量 SQL
{
  "topic": "使用 Sysbench 1.0 对 MySQL 做性能压测",
  "tool": {"name": "sysbench", "required_version": ">=1.0", "obsolete_version": "0.5"},
  "option_migration_0_5_to_1_0": {
    "--test=<path.lua>": "直接写测试名,如 oltp_read_write",
    "--num-threads": "--threads",
    "--max-time": "--time",
    "--max-requests": "--events",
    "--oltp-tables-count": "--tables",
    "--oltp-table-size": "--table-size",
    "script_dir": {"old": "/usr/local/share/sysbench", "new": "/usr/share/sysbench"}
  },
  "install": {
    "rpm": "curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash && sudo yum -y install sysbench",
    "deb": "curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash && sudo apt -y install sysbench"
  },
  "phases": ["prepare", "run", "cleanup"],
  "recommended_run_flags": {
    "--threads": "按档位扫描 8/16/32/64/128/256",
    "--time": 300,
    "--warmup-time": 60,
    "--report-interval": 10,
    "--rand-type": "uniform",
    "--db-ps-mode": "disable"
  },
  "validity_preconditions": [
    "数据量(tables × table-size)需大于 innodb_buffer_pool_size 的 2 倍",
    "必须预热并丢弃预热期数据",
    "压测端与数据库实例分机部署"
  ],
  "test_models": {
    "oltp_read_only": "测缓冲池与 CPU 上限",
    "oltp_write_only": "测 redo/binlog 落盘与 IO,调持久性参数时用",
    "oltp_read_write": "约 7:3 综合场景,最常用",
    "oltp_point_select": "测极限 QPS 与网络往返",
    "bulk_insert": "测导入吞吐"
  },
  "result_reading_order": [
    "95th percentile 优先于 avg",
    "max 与 95th 差一个数量级 => 存在周期性停顿(检查点/刷脏/binlog 落盘)",
    "transactions per sec 为 OLTP 核心指标,queries per sec 跨模型不可比",
    "Threads fairness stddev 偏大 => 压测机资源不足"
  ],
  "pitfalls": [
    {"symptom": "unrecognized option --num-threads", "cause": "抄了 0.5 的参数名", "fix": "按迁移表替换为 1.0 参数"},
    {"symptom": "QPS 高得不真实且调参无变化", "cause": "数据集小于缓冲池,或使用默认 rand-type=special 热点集中", "fix": "放大数据量并指定 --rand-type=uniform"},
    {"symptom": "prepare 极慢", "cause": "默认单线程建数据", "fix": "prepare 阶段加 --threads,设为表数量"},
    {"symptom": "多次结果波动超过 30%", "cause": "无预热 / 时长过短 / 压测端与数据库同机", "fix": "固定 warmup-time 与 time,压测端独立部署"}
  ]
}
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#MySQL#性能测试#Sysbench
上次更新: 8/7/2026

← MySQL网络抓包审计 MySQL Router 实现读写分离→

最近更新
01
Browserless 使用笔记:把 Chrome 变成一个可以被并发调用的网络服务
08-07
02
ORDER BY 配合 LIMIT 触发的索引选择陷阱 原创
08-07
03
Nginx 运维知识地图:从配置基础到反向代理实战 原创
07-29
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式