基于 MySQL 8.0.35 GTID 主从架构,sysbench 1.0.20 全场景压测
- 主库:192.168.195.141
- 从库:192.168.195.142
- 测试环境:虚拟机(4线程,5张表,每张10000行,压测30秒)
1. 环境信息
| 项目 | 主库 (Master) | 从库 (Slave) |
|---|---|---|
| IP | 192.168.195.141 | 192.168.195.142 |
| MySQL版本 | 8.0.35(二进制包,glibc2.17) | 8.0.35(二进制包,glibc2.17) |
| server-id | 1 | 2 |
| gtid_mode | ON | ON |
| sysbench版本 | 1.0.20 | --- |
1.1 MySQL 关键参数
| 参数 | 值 | 说明 |
|---|---|---|
| gtid_mode | ON | 开启GTID复制 |
| enforce_gtid_consistency | ON | 强制GTID一致性 |
| innodb_buffer_pool_size | 134217728 (128M) | InnoDB缓冲池大小 |
| sync_binlog | 1 | 每次事务提交同步binlog |
| innodb_flush_log_at_trx_commit | 1 | 每次事务提交刷redo log |
| max_connections | 151 | 最大连接数 |
2. 环境搭建
2.1 清理MySQL环境(141和142均执行)
bash
# 停止MySQL
systemctl stop mysqld
pkill -9 mysqld
# 清理数据目录
rm -rf /data/mysql/3306/data/*
mkdir -p /data/mysql/3306/data
2.2 初始化MySQL实例(141和142均执行)
bash
/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --initialize
# 获取临时密码
grep "temporary password" /data/mysql/3306/data/mysqld.err
# 主库临时密码示例:lkJ>)E#?i4Fg
# 从库临时密码示例:v,#3/eohrfiO
2.3 启动MySQL并修改密码(141和142均执行)
bash
systemctl start mysqld
# 修改root密码(使用--connect-expired-password选项)
/usr/local/mysql/bin/mysql -uroot -S /data/mysql/3306/data/mysql.sock \
-p'临时密码' --connect-expired-password \
-e "alter user user() identified by 'Root@123456';"
2.4 搭建GTID主从复制
主库(141)创建复制用户:
sql
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
从库(142)建立GTID复制:
sql
CHANGE MASTER TO
MASTER_HOST='192.168.195.141',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_AUTO_POSITION=1,
GET_MASTER_PUBLIC_KEY=1;
START SLAVE;
验证主从状态:
sql
SHOW SLAVE STATUS\G
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- Seconds_Behind_Master: 0
-- Auto_Position: 1
3. 安装 sysbench
3.1 安装依赖
bash
yum -y install make automake libtool pkgconfig libaio-devel openssl-devel
注意: ky10系统上
mysql-devel包不可用,sysbench通过RPM方式安装,MySQL连接使用MySQL自带的客户端库。
3.2 安装sysbench RPM
bash
# 下载sysbench 1.0.20 RPM(从packagecloud.io下载)
cd /tmp
curl -L -o sysbench-1.0.20-1.el8.x86_64.rpm \
"https://packagecloud.io/akopytov/sysbench/packages/el/8/sysbench-1.0.20-1.el8.x86_64.rpm/download.rpm"
# 安装PostgreSQL依赖(sysbench编译时链接了libpq)
yum install -y postgresql
# 安装sysbench(跳过依赖检查,libpq由postgresql-libs提供)
rpm -ivh --nodeps sysbench-1.0.20-1.el8.x86_64.rpm
说明: sysbench 1.0.20 RPM编译时链接了PostgreSQL的libpq库,需要安装
postgresql-libs包提供libpq.so.5。启动时会有no version information available警告,不影响MySQL压测功能。
3.3 验证安装
bash
sysbench --version
# sysbench 1.0.20
# 查看压测脚本
ls /usr/share/sysbench/
# bulk_insert.lua oltp_insert.lua oltp_read_write.lua oltp_update_non_index.lua select_random_ranges.lua
# oltp_common.lua oltp_delete.lua oltp_point_select.lua oltp_write_only.lua
# oltp_common.lua oltp_read_only.lua oltp_update_index.lua select_random_points.lua tests
说明:
oltp_common.lua是公共模块,其他每个lua脚本对应一个测试场景,共10个场景(不含公共模块)。
3.4 创建sysbench测试用户
sql
-- 在主库(141)执行
CREATE DATABASE IF NOT EXISTS sbtest;
CREATE USER 'sbtest'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Sbtest@123';
GRANT ALL PRIVILEGES ON sbtest.* TO 'sbtest'@'localhost';
FLUSH PRIVILEGES;
注意: 必须使用
mysql_native_password认证插件,sysbench不支持caching_sha2_password(MySQL 8.0默认插件)。
4. sysbench 基准测试四步骤
sysbench对MySQL进行基准测试的标准流程为四个步骤:
- prepare --- 生成压测数据
- prewarm --- 预热,将磁盘数据加载到内存
- run --- 执行压测
- cleanup --- 清理数据
4.1 公共参数说明
| 参数 | 含义 | 默认值 | 本次测试值 |
|---|---|---|---|
| --mysql-host | MySQL主机 | localhost | 127.0.0.1 |
| --mysql-port | MySQL端口 | 3306 | 3306 |
| --mysql-user | MySQL用户 | sbtest | sbtest |
| --mysql-password | MySQL密码 | Sbtest@123 | |
| --mysql-db | 数据库名 | sbtest | sbtest |
| --tables | 表数量 | 1 | 5 |
| --table-size | 单表行数 | 10000 | 10000 |
| --threads | 并发线程数 | 1 | 4 |
| --time | 压测时间(秒) | 10 | 30 |
| --report-interval | 中间报告间隔(秒) | 0 | 10 |
虚拟机线程调整说明: 生产环境通常使用64线程,本次测试环境为虚拟机,调整为4线程。
4.2 测试表结构
OLTP场景通用表结构(除bulk_insert外):
sql
SHOW CREATE TABLE sbtest.sbtest1\G
*************************** 1. row ***************************
Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
`id` int NOT NULL AUTO_INCREMENT,
`k` int NOT NULL DEFAULT '0',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
字段说明:
id:自增主键k:整数列,有索引(k_1),用于范围查询和随机点查询c:120字符定长字符串,无索引,用于模拟数据载荷pad:60字符定长字符串,无索引,用于模拟数据载荷
bulk_insert场景专用表结构:
sql
SHOW CREATE TABLE sbtest.sbtest1\G
*************************** 1. row ***************************
Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
`id` int NOT NULL,
`k` int NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
与OLTP表的区别: bulk_insert表只有
id和k两个字段,id不是自增的,没有c和pad字段。
5. 场景一:oltp_point_select(基于主键的点查询)
5.1 场景说明
基于主键进行单行查询,是最简单的只读场景,测试主键查询性能。
对应SQL语句:
sql
SELECT c FROM sbtest1 WHERE id=?
5.2 执行步骤
bash
# 定义公共参数
SB_COMMON="--mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=Sbtest@123 --mysql-db=sbtest --tables=5 --table-size=10000 --threads=4 --time=30 --report-interval=10"
# Step 1: prepare(生成压测数据)
sysbench oltp_point_select $SB_COMMON prepare
# Step 2: prewarm(预热)
sysbench oltp_point_select $SB_COMMON prewarm
# Step 3: run(压测)
sysbench oltp_point_select $SB_COMMON run
# Step 4: cleanup(清理数据)
sysbench oltp_point_select $SB_COMMON cleanup
5.3 压测结果
Running the test with following options:
Number of threads: 4
Report intermediate results every 10 second(s)
Threads started!
[ 10s ] thds: 4 tps: 51871.19 qps: 51871.19 (r/w/o: 51871.19/0.00/0.00) lat (ms,95%): 0.12 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 52135.87 qps: 52135.87 (r/w/o: 52135.87/0.00/0.00) lat (ms,95%): 0.14 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 55931.10 qps: 55931.10 (r/w/o: 55931.10/0.00/0.00) lat (ms,95%): 0.11 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 1599436
write: 0
other: 0
total: 1599436
transactions: 1599436 (53310.47 per sec.) -- TPS: 53310
queries: 1599436 (53310.47 per sec.) -- QPS: 53310
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0016s
total number of events: 1599436
Latency (ms):
min: 0.01
avg: 0.07
max: 21.98
95th percentile: 0.12 -- 95%延迟: 0.12ms
sum: 119408.46
Threads fairness:
events (avg/stddev): 399859.0000/10441.84
execution time (avg/stddev): 29.8521/0.01
5.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 53310.47 | 每秒事务数 |
| QPS | 53310.47 | 每秒查询数(纯读) |
| 95%延迟 | 0.12ms | 95%的查询在0.12ms内完成 |
| 平均延迟 | 0.07ms | 平均查询耗时 |
分析: 点查询是最轻量的操作,直接通过主键索引定位,无需回表(索引覆盖查询),TPS/QPS最高,延迟最低。
6. 场景二:oltp_read_only(只读测试)
6.1 场景说明
只读测试,包含多种类型的读操作。
对应SQL语句:
sql
SELECT c FROM sbtest1 WHERE id=? -- 默认执行10次,由--point_selects选项控制
SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? -- 范围查询
SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ? -- 范围聚合
SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c -- 范围排序
SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c -- 去重排序
6.2 执行步骤
bash
sysbench oltp_read_only $SB_COMMON prepare
sysbench oltp_read_only $SB_COMMON prewarm
sysbench oltp_read_only $SB_COMMON run
6.3 压测结果
[ 10s ] thds: 4 tps: 2880.89 qps: 46098.20 (r/w/o: 40336.02/0.00/5762.19) lat (ms,95%): 2.07 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 2889.87 qps: 46237.47 (r/w/o: 40457.73/0.00/5779.75) lat (ms,95%): 2.03 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 3764.70 qps: 60233.57 (r/w/o: 52704.16/0.00/7529.41) lat (ms,95%): 1.89 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 1335054
write: 0
other: 190722
total: 1525776
transactions: 95361 (3178.38 per sec.) -- TPS: 3178
queries: 1525776 (50854.14 per sec.) -- QPS: 50854
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0023s
total number of events: 95361
Latency (ms):
min: 0.39
avg: 1.26
max: 28.76
95th percentile: 2.00 -- 95%延迟: 2.00ms
sum: 119910.56
6.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 3178.38 | 每秒事务数 |
| QPS | 50854.14 | 每秒查询数(纯读+其他) |
| 95%延迟 | 2.00ms | 95%的查询在2.00ms内完成 |
| 平均延迟 | 1.26ms | 平均查询耗时 |
分析: 只读场景包含范围查询、聚合、排序等操作,比点查询复杂,TPS降低但QPS仍然较高。
other190722次是BEGIN/COMMIT操作(每个事务包含一次BEGIN和一次COMMIT)。
7. 场景三:oltp_read_write(读写测试)
7.1 场景说明
读写混合测试,是最常用的OLTP基准测试场景,模拟真实业务负载。
对应SQL语句:
sql
-- 读操作
SELECT c FROM sbtest1 WHERE id=? -- 默认执行10次
SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?
SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ?
SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c
SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c
-- 写操作
UPDATE sbtest1 SET k=k+1 WHERE id=? -- 更新索引字段
UPDATE sbtest1 SET c=? WHERE id=? -- 更新非索引字段
DELETE FROM sbtest1 WHERE id=? -- 删除
INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?) -- 插入
7.2 执行步骤
bash
sysbench oltp_read_write $SB_COMMON prepare
sysbench oltp_read_write $SB_COMMON prewarm
sysbench oltp_read_write $SB_COMMON run
7.3 压测结果
[ 10s ] thds: 4 tps: 1112.69 qps: 22261.51 (r/w/o: 15583.80/4451.84/2225.87) lat (ms,95%): 6.32 err/s: 0.10 reconn/s: 0.00
[ 20s ] thds: 4 tps: 1221.32 qps: 24421.84 (r/w/o: 17094.91/4884.29/2442.64) lat (ms,95%): 4.91 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 1078.77 qps: 21579.60 (r/w/o: 15105.78/4316.28/2157.54) lat (ms,95%): 6.79 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 477876
write: 136533
other: 68267
total: 682676
transactions: 34133 (1137.51 per sec.) -- TPS: 1137
queries: 682676 (22750.76 per sec.) -- QPS: 22750
ignored errors: 1 (0.03 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0060s
total number of events: 34133
Latency (ms):
min: 0.93
avg: 3.51
max: 37.56
95th percentile: 5.99 -- 95%延迟: 5.99ms
sum: 119934.51
7.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 1137.51 | 每秒事务数 |
| QPS | 22750.76 | 每秒查询数 |
| 95%延迟 | 5.99ms | 95%的查询在5.99ms内完成 |
| 平均延迟 | 3.51ms | 平均查询耗时 |
| 读写比 | r:w:o = 15583:4451:2225 | 约7:2:1 |
分析: 读写混合场景是最接近真实业务负载的测试。每个事务包含14条读SQL、4条写SQL和2条其他SQL(BEGIN+COMMIT),读写比约为7:2:1。由于涉及写操作,需要获取行锁和刷新redo log/binlog,TPS和延迟都明显劣于纯读场景。
8. 场景四:oltp_write_only(只写测试)
8.1 场景说明
只写测试,包含更新、删除和插入操作。
对应SQL语句:
sql
UPDATE sbtest1 SET k=k+1 WHERE id=? -- 更新索引字段
UPDATE sbtest1 SET c=? WHERE id=? -- 更新非索引字段
DELETE FROM sbtest1 WHERE id=? -- 删除
INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?) -- 插入
8.2 执行步骤
bash
sysbench oltp_write_only $SB_COMMON prepare
sysbench oltp_write_only $SB_COMMON prewarm
sysbench oltp_write_only $SB_COMMON run
8.3 压测结果
[ 10s ] thds: 4 tps: 2277.29 qps: 13664.75 (r/w/o: 0.00/9109.87/4554.88) lat (ms,95%): 3.49 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 2814.02 qps: 16884.41 (r/w/o: 0.00/11256.27/5628.14) lat (ms,95%): 2.22 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 2778.43 qps: 16669.39 (r/w/o: 0.00/11112.83/5556.56) lat (ms,95%): 2.22 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 0
write: 314804
other: 157402
total: 472206
transactions: 78701 (2623.09 per sec.) -- TPS: 2623
queries: 472206 (15738.52 per sec.) -- QPS: 15738
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0025s
total number of events: 78701
Latency (ms):
min: 0.38
avg: 1.52
max: 45.02
95th percentile: 2.76 -- 95%延迟: 2.76ms
sum: 119862.90
8.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 2623.09 | 每秒事务数 |
| QPS | 15738.52 | 每秒查询数(纯写+其他) |
| 95%延迟 | 2.76ms | 95%的查询在2.76ms内完成 |
| 平均延迟 | 1.52ms | 平均查询耗时 |
分析: 只写场景每个事务包含2条UPDATE、1条DELETE、1条INSERT和2条其他(BEGIN+COMMIT),共6条SQL。TPS比读写混合高,因为不包含耗时的范围查询和排序操作。
9. 场景五:oltp_update_index(基于主键更新索引字段)
9.1 场景说明
基于主键进行更新,更新的是索引字段 k。由于 k 列有索引(k_1),更新会导致索引变更。
对应SQL语句:
sql
UPDATE sbtest1 SET k=k+1 WHERE id=?
9.2 执行步骤
bash
sysbench oltp_update_index $SB_COMMON prepare
sysbench oltp_update_index $SB_COMMON prewarm
sysbench oltp_update_index $SB_COMMON run
9.3 压测结果
[ 10s ] thds: 4 tps: 5629.54 qps: 5629.54 (r/w/o: 0.00/5629.54/0.00) lat (ms,95%): 1.03 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 5653.31 qps: 5653.31 (r/w/o: 0.00/5653.31/0.00) lat (ms,95%): 0.99 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 5616.07 qps: 5616.07 (r/w/o: 0.00/5616.07/0.00) lat (ms,95%): 1.03 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 0
write: 168998
other: 0
total: 168998
transactions: 168998 (5632.55 per sec.) -- TPS: 5632
queries: 168998 (5632.55 per sec.) -- QPS: 5632
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0031s
total number of events: 168998
Latency (ms):
min: 0.28
avg: 0.71
max: 24.76
95th percentile: 1.01 -- 95%延迟: 1.01ms
sum: 119843.68
9.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 5632.55 | 每秒事务数 |
| QPS | 5632.55 | 每秒查询数(纯写) |
| 95%延迟 | 1.01ms | 95%的查询在1.01ms内完成 |
| 平均延迟 | 0.71ms | 平均查询耗时 |
分析: 更新索引字段需要同时修改聚簇索引和二级索引(k_1),但由于是基于主键定位,且每次只更新一行,性能仍然较高。TPS明显高于oltp_write_only场景,因为单条SQL事务更轻量。
10. 场景六:oltp_update_non_index(基于主键更新非索引字段)
10.1 场景说明
基于主键进行更新,更新的是非索引字段 c。由于 c 列没有索引,更新不会导致索引变更。
对应SQL语句:
sql
UPDATE sbtest1 SET c=? WHERE id=?
10.2 执行步骤
bash
sysbench oltp_update_non_index $SB_COMMON prepare
sysbench oltp_update_non_index $SB_COMMON prewarm
sysbench oltp_update_non_index $SB_COMMON run
10.3 压测结果
[ 10s ] thds: 4 tps: 5954.78 qps: 5954.78 (r/w/o: 0.00/5954.78/0.00) lat (ms,95%): 0.95 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 5820.91 qps: 5820.91 (r/w/o: 0.00/5820.91/0.00) lat (ms,95%): 0.97 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 5831.15 qps: 5831.15 (r/w/o: 0.00/5831.15/0.00) lat (ms,95%): 0.99 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 0
write: 176078
other: 0
total: 176078
transactions: 176078 (5868.72 per sec.) -- TPS: 5868
queries: 176078 (5868.72 per sec.) -- QPS: 5868
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0020s
total number of events: 176078
Latency (ms):
min: 0.23
avg: 0.68
max: 17.69
95th percentile: 0.97 -- 95%延迟: 0.97ms
sum: 119823.84
10.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 5868.72 | 每秒事务数 |
| QPS | 5868.72 | 每秒查询数(纯写) |
| 95%延迟 | 0.97ms | 95%的查询在0.97ms内完成 |
| 平均延迟 | 0.68ms | 平均查询耗时 |
分析: 更新非索引字段的TPS(5868)高于更新索引字段(5632),因为不需要维护二级索引。这是InnoDB的一个重要特性:更新非索引列只需修改聚簇索引,而更新索引列需要同时修改聚簇索引和二级索引,后者开销更大。
11. 场景七:oltp_insert(插入测试)
11.1 场景说明
纯插入测试,向表中插入新行。
对应SQL语句:
sql
INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?)
11.2 执行步骤
bash
sysbench oltp_insert $SB_COMMON prepare
sysbench oltp_insert $SB_COMMON prewarm
sysbench oltp_insert $SB_COMMON run
11.3 压测结果
[ 10s ] thds: 4 tps: 5843.18 qps: 5843.18 (r/w/o: 0.00/5843.18/0.00) lat (ms,95%): 0.97 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 5721.51 qps: 5721.51 (r/w/o: 0.00/5721.51/0.00) lat (ms,95%): 0.99 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 5797.20 qps: 5797.20 (r/w/o: 0.00/5797.20/0.00) lat (ms,95%): 0.99 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 0
write: 173627
other: 0
total: 173627
transactions: 173627 (5787.07 per sec.) -- TPS: 5787
queries: 173627 (5787.07 per sec.) -- QPS: 5787
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0018s
total number of events: 173627
Latency (ms):
min: 0.18
avg: 0.69
max: 34.53
95th percentile: 0.97 -- 95%延迟: 0.97ms
sum: 119592.69
11.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 5787.07 | 每秒事务数 |
| QPS | 5787.07 | 每秒查询数(纯写) |
| 95%延迟 | 0.97ms | 95%的查询在0.97ms内完成 |
| 平均延迟 | 0.69ms | 平均查询耗时 |
分析: 插入操作需要向聚簇索引和二级索引(k_1)中插入新记录,同时维护自增主键。TPS与update_non_index接近,略高于update_index,因为插入时索引维护的开销与更新索引字段类似。
12. 场景八:oltp_delete(删除测试)
12.1 场景说明
基于主键进行删除操作。
对应SQL语句:
sql
DELETE FROM sbtest1 WHERE id=?
12.2 执行步骤
bash
sysbench oltp_delete $SB_COMMON prepare
sysbench oltp_delete $SB_COMMON prewarm
sysbench oltp_delete $SB_COMMON run
12.3 压测结果
[ 10s ] thds: 4 tps: 38203.10 qps: 38203.10 (r/w/o: 0.00/1906.59/36296.51) lat (ms,95%): 0.41 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 56650.04 qps: 56650.04 (r/w/o: 0.00/307.11/56342.94) lat (ms,95%): 0.13 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 52707.72 qps: 52707.72 (r/w/o: 0.00/127.10/52580.63) lat (ms,95%): 0.13 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 0
write: 23410
other: 1452236
total: 1475646
transactions: 1475646 (49184.64 per sec.) -- TPS: 49184
queries: 1475646 (49184.64 per sec.) -- QPS: 49184
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0015s
total number of events: 1475646
Latency (ms):
min: 0.01
avg: 0.08
max: 22.60
95th percentile: 0.16 -- 95%延迟: 0.16ms
sum: 119399.88
12.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 49184.64 | 每秒事务数 |
| QPS | 49184.64 | 每秒查询数 |
| 95%延迟 | 0.16ms | 95%的查询在0.16ms内完成 |
| 平均延迟 | 0.08ms | 平均查询耗时 |
分析: 删除场景的TPS异常高(49184),这是因为sysbench的oltp_delete场景采用了"先删后插"的策略:删除一行后立即插入相同id的行,保证表中数据量不变。前10秒TPS较低(38203),是因为数据还在预热阶段;后20秒TPS稳定在5万+,说明删除+插入操作在Buffer Pool命中的情况下非常快。
other1452236次包含了大量的COMMIT操作。
13. 场景九:bulk_insert(批量插入测试)
13.1 场景说明
批量插入测试,使用多行INSERT语句一次性插入多条记录。
对应SQL语句:
sql
INSERT INTO sbtest1 VALUES(?, ?),(?, ?),(?, ?),(?, ?)...
注意: bulk_insert场景使用独立的表结构(只有id和k两个字段),与其他OLTP场景不同。需要单独prepare和cleanup。
13.2 执行步骤
bash
# bulk_insert需要单独prepare(表结构不同)
sysbench bulk_insert $SB_COMMON prepare
# bulk_insert不支持prewarm
# sysbench bulk_insert $SB_COMMON prewarm # 会报错:Unknown command: prewarm
# run
sysbench bulk_insert $SB_COMMON run
# cleanup
sysbench bulk_insert $SB_COMMON cleanup
13.3 压测结果
Running the test with following options:
Number of threads: 4
Report intermediate results every 10 second(s)
Threads started!
[ 10s ] thds: 4 tps: 546335.90 qps: 16.67 (r/w/o: 0.00/16.67/0.00) lat (ms,95%): 0.00 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 589229.81 qps: 20.23 (r/w/o: 0.00/20.23/0.00) lat (ms,95%): 0.00 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 600174.33 qps: 20.61 (r/w/o: 0.00/20.61/0.00) lat (ms,95%): 0.00 err/s: 0.00 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 0
write: 583
other: 0
total: 583
transactions: 17357243 (576387.48 per sec.) -- TPS: 576387
queries: 583 (19.36 per sec.) -- QPS: 19
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.1131s
total number of events: 17357243
Latency (ms):
min: 0.00
avg: 0.01
max: 904.19
95th percentile: 0.00 -- 95%延迟: 0.00ms
sum: 118287.27
13.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 576387.48 | 每秒事务数(极高) |
| QPS | 19.36 | 每秒SQL语句数 |
| 95%延迟 | 0.00ms | 95%的查询在0.00ms内完成 |
| 平均延迟 | 0.01ms | 平均查询耗时 |
分析: bulk_insert的TPS数值极高(57万+),但这里的"事务"定义与其他场景不同。bulk_insert中每个event是插入一行记录(通过多行INSERT批量提交),而QPS只有19是因为每条INSERT语句包含大量行(一条INSERT插入多行),所以SQL语句数很少。bulk_insert不支持prewarm命令。
14. 场景十:select_random_points(基于索引的随机点查询)
14.1 场景说明
基于二级索引(k_1)进行随机查询,每次查询10个随机k值对应的记录。
对应SQL语句:
sql
SELECT id, k, c, pad
FROM sbtest1
WHERE k IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
14.2 执行步骤
bash
sysbench select_random_points $SB_COMMON prepare
sysbench select_random_points $SB_COMMON prewarm
sysbench select_random_points $SB_COMMON run
14.3 压测结果
[ 10s ] thds: 4 tps: 44917.79 qps: 44917.79 (r/w/o: 44917.79/0.00/0.00) lat (ms,95%): 0.13 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 45129.21 qps: 45129.21 (r/w/o: 45129.21/0.00/0.00) lat (ms,95%): 0.13 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 34519.47 qps: 34519.47 (r/w/o: 34519.47/0.00/0.00) lat (ms,95%): 0.20 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 1245720
write: 0
other: 0
total: 1245720
transactions: 1245720 (41520.36 per sec.) -- TPS: 41520
queries: 1245720 (41520.36 per sec.) -- QPS: 41520
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0019s
total number of events: 1245720
Latency (ms):
min: 0.03
avg: 0.10
max: 35.56
95th percentile: 0.16 -- 95%延迟: 0.16ms
sum: 119525.43
14.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 41520.36 | 每秒事务数 |
| QPS | 41520.36 | 每秒查询数(纯读) |
| 95%延迟 | 0.16ms | 95%的查询在0.16ms内完成 |
| 平均延迟 | 0.10ms | 平均查询耗时 |
分析: 基于索引的随机点查询性能很高,TPS达到41520。虽然使用了IN子句查询10个随机值,但由于k列有索引且数据在Buffer Pool中,查询效率很高。TPS低于oltp_point_select(53310),因为IN查询涉及多次索引查找和回表操作。
15. 场景十一:select_random_ranges(基于索引的随机范围查询)
15.1 场景说明
基于二级索引(k_1)进行随机范围查询,每次查询10个随机范围。
对应SQL语句:
sql
SELECT count(k)
FROM sbtest1
WHERE k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ?
OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ?
OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ?
OR k BETWEEN ? AND ?
15.2 执行步骤
bash
sysbench select_random_ranges $SB_COMMON prepare
sysbench select_random_ranges $SB_COMMON prewarm
sysbench select_random_ranges $SB_COMMON run
15.3 压测结果
[ 10s ] thds: 4 tps: 31794.03 qps: 31794.03 (r/w/o: 31794.03/0.00/0.00) lat (ms,95%): 0.19 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 4 tps: 33094.35 qps: 33094.35 (r/w/o: 33094.35/0.00/0.00) lat (ms,95%): 0.19 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 4 tps: 32532.03 qps: 32532.03 (r/w/o: 32532.03/0.00/0.00) lat (ms,95%): 0.18 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 974242
write: 0
other: 0
total: 974242
transactions: 974242 (32472.23 per sec.) -- TPS: 32472
queries: 974242 (32472.23 per sec.) -- QPS: 32472
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 30.0016s
total number of events: 974242
Latency (ms):
min: 0.03
avg: 0.12
max: 22.71
95th percentile: 0.19 -- 95%延迟: 0.19ms
sum: 119514.77
15.4 结果分析
| 指标 | 值 | 说明 |
|---|---|---|
| TPS | 32472.23 | 每秒事务数 |
| QPS | 32472.23 | 每秒查询数(纯读) |
| 95%延迟 | 0.19ms | 95%的查询在0.19ms内完成 |
| 平均延迟 | 0.12ms | 平均查询耗时 |
分析: 随机范围查询使用OR连接10个BETWEEN范围,需要扫描索引的多个区间。TPS(32472)低于select_random_points(41520),因为范围扫描比点查询需要遍历更多索引条目。但仍然保持了较高的性能,因为查询只返回count值,不需要回表获取完整行数据。
16. 全场景性能汇总
16.1 TPS/QPS/延迟对比表
| 场景 | 类型 | TPS | QPS | 95%延迟(ms) | 平均延迟(ms) | 对应SQL |
|---|---|---|---|---|---|---|
| oltp_point_select | 只读 | 53310 | 53310 | 0.12 | 0.07 | SELECT c FROM sbtest1 WHERE id=? |
| oltp_read_only | 只读 | 3178 | 50854 | 2.00 | 1.26 | 5种读操作+BEGIN/COMMIT |
| oltp_read_write | 读写 | 1137 | 22750 | 5.99 | 3.51 | 5种读+4种写+BEGIN/COMMIT |
| oltp_write_only | 只写 | 2623 | 15738 | 2.76 | 1.52 | 2种UPDATE+DELETE+INSERT+BEGIN/COMMIT |
| oltp_update_index | 只写 | 5632 | 5632 | 1.01 | 0.71 | UPDATE sbtest1 SET k=k+1 WHERE id=? |
| oltp_update_non_index | 只写 | 5868 | 5868 | 0.97 | 0.68 | UPDATE sbtest1 SET c=? WHERE id=? |
| oltp_insert | 只写 | 5787 | 5787 | 0.97 | 0.69 | INSERT INTO sbtest1 VALUES(...) |
| oltp_delete | 只写 | 49184 | 49184 | 0.16 | 0.08 | DELETE FROM sbtest1 WHERE id=? |
| bulk_insert | 只写 | 576387 | 19 | 0.00 | 0.01 | INSERT INTO sbtest1 VALUES(...),(...) |
| select_random_points | 只读 | 41520 | 41520 | 0.16 | 0.10 | SELECT ... WHERE k IN(10个值) |
| select_random_ranges | 只读 | 32472 | 32472 | 0.19 | 0.12 | SELECT count(k) WHERE k BETWEEN...OR... |
16.2 性能排序(TPS从高到低)
bulk_insert 576387 ★★★★★ 批量插入(事务定义不同,不可直接比较)
oltp_point_select 53310 ★★★★☆ 主键点查
oltp_delete 49184 ★★★★☆ 删除(先删后插策略)
select_random_points 41520 ★★★★☆ 索引随机点查
select_random_ranges 32472 ★★★☆☆ 索引随机范围查
oltp_update_non_index 5868 ★★☆☆☆ 更新非索引列
oltp_insert 5787 ★★☆☆☆ 单行插入
oltp_update_index 5632 ★★☆☆☆ 更新索引列
oltp_write_only 2623 ★☆☆☆☆ 复合写操作
oltp_read_only 3178 ★☆☆☆☆ 复合读操作
oltp_read_write 1137 ☆☆☆☆☆ 读写混合
16.3 关键结论
-
纯读操作性能最高: oltp_point_select的TPS达到53310,是最基本的性能基准。基于主键的点查询利用了聚簇索引的直接定位能力。
-
更新非索引列 > 更新索引列: oltp_update_non_index(5868 TPS)比oltp_update_index(5632 TPS)高约4%,因为更新非索引列不需要维护二级索引。
-
读写混合性能最低: oltp_read_write的TPS仅1137,因为每个事务包含14条读SQL+4条写SQL+2条其他SQL,事务粒度最大,锁竞争和日志刷新开销最大。
-
索引随机查询性能优秀: select_random_points和select_random_ranges的TPS分别达到41520和32472,说明InnoDB的二级索引在Buffer Pool命中时性能极佳。
-
bulk_insert的TPS不可直接比较: bulk_insert的"事务"定义与其他场景不同,每个event是插入一行记录(通过多行INSERT批量提交),TPS数值不能与其他场景直接对比。
-
oltp_delete的TPS异常高: 因为sysbench的delete场景采用"先删后插"策略,保证数据量不变,实际是轻量级操作。
17. 如何分析sysbench基准测试结果
17.1 重点关注三个指标
- TPS(每秒事务数) --- 反映系统的事务吞吐量,越大越好
- QPS(每秒操作数) --- 反映系统的查询吞吐量,越大越好
- 95%延迟 --- 反映事务的执行时长,越小越好
17.2 中间报告解读
[ 10s ] thds: 4 tps: 51871.19 qps: 51871.19 (r/w/o: 51871.19/0.00/0.00) lat (ms,95%): 0.12 err/s: 0.00 reconn/s: 0.00
| 字段 | 含义 |
|---|---|
| thds | 并发线程数 |
| tps | 每秒事务数 |
| qps | 每秒操作数,等于r(读)+w(写)+o(其他,主要是BEGIN和COMMIT) |
| lat (ms,95%) | 95%的查询时间小于或等于该值,单位毫秒 |
| err/s | 每秒错误数 |
| reconn/s | 每秒重试次数 |
17.3 最终报告解读
SQL statistics:
queries performed:
read: 1599436 # 读操作数量
write: 0 # 写操作数量
other: 0 # 其他操作数量(BEGIN/COMMIT)
total: 1599436 # 总操作数量 = read + write + other
transactions: 1599436 (53310.47 per sec.) # 总事务数(每秒事务数)
queries: 1599436 (53310.47 per sec.) # 总操作数(每秒操作数)
Latency (ms):
min: 0.01 # 最小耗时
avg: 0.07 # 平均耗时
max: 21.98 # 最大耗时
95th percentile: 0.12 # 95% event的执行耗时
Threads fairness:
events (avg/stddev): 399859.0000/10441.84 # 平均每个线程执行event数量,stddev越小越稳定
execution time (avg/stddev): 29.8521/0.01 # 平均每个线程执行时间
18. 从库同步验证
18.1 从库数据一致性
压测完成后,验证从库数据同步:
sql
-- 从库(142)执行
SHOW TABLES FROM sbtest;
-- +------------------+
-- | Tables_in_sbtest |
-- +------------------+
-- | sbtest1 |
-- | sbtest2 |
-- | sbtest3 |
-- | sbtest4 |
-- | sbtest5 |
-- +------------------+
SELECT COUNT(*) FROM sbtest.sbtest1;
-- +----------+
-- | COUNT(*) |
-- +----------+
-- | 10000 |
-- +----------+
18.2 从库复制状态
sql
SHOW SLAVE STATUS\G
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- Seconds_Behind_Master: 0
-- Auto_Position: 1
说明: 压测期间主库产生的大量binlog通过GTID复制同步到从库,从库IO和SQL线程均正常运行,数据一致。
19. 清理环境
bash
# 清理sysbench测试数据
sysbench oltp_read_write --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=Sbtest@123 --mysql-db=sbtest --tables=5 cleanup
# 删除测试用户和数据库(可选)
# DROP USER 'sbtest'@'localhost';
# DROP DATABASE sbtest;
20. 注意事项与最佳实践
-
认证插件: sysbench不支持MySQL 8.0默认的
caching_sha2_password,必须使用mysql_native_password创建测试用户。 -
prewarm的重要性: 压测前务必执行prewarm,将数据加载到Buffer Pool中,否则冷启动的IO开销会严重影响测试结果。
-
bulk_insert的特殊性: bulk_insert使用独立的表结构,需要单独prepare/cleanup,且不支持prewarm命令。
-
线程数选择: 生产环境通常使用64线程,虚拟机环境建议2-8线程。线程数不是越多越好,超过CPU核心数后上下文切换开销会增加。
-
压测时间: 建议至少60秒,30秒的测试结果可能不够稳定。本次测试使用30秒是为了在虚拟机环境下快速完成全场景测试。
-
双1标准的影响: 本次测试使用
sync_binlog=1和innodb_flush_log_at_trx_commit=1(双1标准),这是最安全的配置但性能最低。如果追求极致性能,可以调整这两个参数。 -
oltp_read_write是最重要的场景: 它最接近真实业务负载,建议作为日常基准测试的首选场景。
-
sysbench 1.0 vs 旧版本: sysbench 1.0之后,OLTP场景使用
oltp_read_write替代了旧版的oltp.lua,两者压测内容完全一致。