版本号:sysbench1.1
简介
sysbench是一个基于LuaJIT的可脚本多线程基准测试工具,最常用于数据库基准测试,支持单点读写、随机读写、混合读写等各种测试类型。
sysbench并非通过JDBC的方式连接数据库,而是通过专门的客户端依赖进行。比如 MySQL 通过 libmysqlclient 或 MySQL Connector/C 来建立与数据库的连接;PG 通过 libpq 来与 PostgreSQL 服务器进行通信。这些库提供了执行 SQL 查询和管理数据库连接的功能,sysbench 测试数据库时就是利用这些客户端库来执行预定义的数据库操作,以便测量数据库的性能和稳定性。
文章目录如下
1. 语法说明
sysbench测试数据库主要由 "插入数据"、"运行测试"、"清理数据" 三部分组成,语法如下:
插入数据(prepare)
sysbench <参数选项> <测试用例> prepare
运行测试(run)
sysbench <参数选项> <测试用例> run
清理数据(cleanup)
sysbench <参数选项> <测试用例> cleanup
2. 参数说明
- 注释内容中花括号{ }表示选项,方括号[ ]表示默认值
2.1. 常用参数(可选)
测试参数
--tables # 设置表数量 [1]
--table-size # 设置表行数 [10000]
--time=N # 设置测试时间(秒) [10]
--threads=N # 设置线程数 [1]
--report-interval=N # 设置实时报告间隔时间(秒) [0]
--db-ps-mode=STRING # 是否开启预处理语句 {auto 开启, disable 禁用} [auto]
--forced-shutdown=STRING # 测试结束后等待n秒强制关闭 [off]
--config-file=FILENAME # 读取包含命令行的文件
特别说明:--db-ps-mode 参数用于是否使用预处理方式(prepared statements)。如果开启后sysbench会自动检测数据库是否支持,如果不支持则自动使用普通语句。例如MySQL和PostgreSQL都支持使用预处理语句来优化查询性能,它们在执行过程中会将符合预期的预处理语句缓存到本地,而在后续复用语句时能够节约语法分析、查询优化和计划生成时间,整体提高性能。
事务控制参数
--events=N # 限制总事务 [0] 0表示无限制
--rate=N # 限制平均事务 [0] 0表示无限制
--thread-stack-size=SIZE # 设置每个线程的栈大小 [64K]
等待参数
--warmup-time=N # 设置预热时间(秒) [0] (预热时间是指在实际性能测试之前,系统被暴露于负载下的时间段,这段时间用来让系统达到稳定状态,确保测试结果更加准确和可靠)
--thread-init-timeout=N # 工作线程初始化的等待时间(秒) [30]
2.2. 用例参数(必选)
测试用例配置(不需要 -- 符号)
oltp_read_only # 测试随机读性能
oltp_write_only # 测试随机写性能
oltp_read_write # 测试混合读写性能
oltp_point_select # 测试单点查询
select_random_points # 测试随机点查询
select_random_ranges # 测试随机范围查询
bulk_insert # 测试批量插入性能
oltp_insert # 测试持续插入性能
oltp_delete # 测试删除性能
oltp_update_index # 测试更新操作时数据库的索引性能
oltp_update_non_index # 测试更新操作时数据库在非索引字段上的性能
2.3. 数据库参数(必选)
MySQL参数
--db-driver=mysql # 指定数据库驱动{mysql, mysql} [mysql]
--mysql-host=STRING # 数据库IP [localhost]
--mysql-port=N # 数据库端口号 [3306]
--mysql-user=STRING # 数据库用户名[root]
--mysql-password=STRING # 数据库密码 []
--mysql-db=STRING # 数据库库名 [sysbench]
--mysql-sslmode=STRING # SSL模式 {disable, allow, prefer, require, verify-ca, verify-full} [disable]
PostgreSQL参数
--db-driver=pgsql # 指定数据库驱动{pgsql, mysql} [mysql]
--pgsql-host=STRING # 数据库IP [localhost]
--pgsql-port=N # 数据库端口号 [5432]
--pgsql-user=STRING # 数据库用户名[sbtest]
--pgsql-password=STRING # 数据库密码 []
--pgsql-db=STRING # 数据库库名 [sbtest]
--pgsql-sslmode=STRING # SSL模式 (disable, allow, prefer, require, verify-ca, verify-full) [prefer]
--pgsql-sslmode 参数选项说明(与 --mysql-sslmode 相同)
- disable:表示禁用 SSL 连接。使用普通的非加密连接进行通信。
- allow:表示允许 SSL 连接,但是如果服务器不支持 SSL,则会回退到普通的非加密连接。
- prefer:表示优先选择 SSL 连接,但是如果服务器不支持 SSL,则会回退到普通的非加密连接。
- require:表示要求使用 SSL 连接,如果服务器不支持 SSL,则连接失败。
- verify-ca:表示要求使用 SSL 连接,并要求服务器证书的有效性。客户端会验证服务器证书是否由可信的证书颁发机构(CA)签署。
- verify-full:表示要求使用 SSL 连接,并对服务器证书进行严格验证。除了验证证书的有效性外,还会验证服务器证书中的主机名是否与连接的主机名匹配。
2.4. 日志参数(可选)
--debug[=on|off] # 输出调试信息 [off]
--verbosity=N # 设置日志级别 {5:debug信息, 0:只输出重要信息} [3]
--percentile=N # 设置延迟响应的百分位 [95]
--histogram[=on|off] # 输出直方图 [off]
2.5. 伪随机数生成器参数(可选)
--rand-type=STRING # 随机数字分布{uniform, gaussian, pareto, zipfian} [uniform]
--rand-seed=N # 随机数生成器种子(0表表示当前时间) [0]
--rand-pareto-h=N # 指定Pareto分布的h值,用于生成 Pareto 分布的随机数 [0.2]
--rand-zipfian-exp=N # 指定 Zipfian 分布的参数,用于生成 Zipfian 分布的随机数 [0.8]
3. 测试示例
3.1. 插入数据
以PostgreSQL编译的为例:插入5张表,每张表10w行数据
sysbench \
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=5 \
--table-size=100000 \
--threads=5 \
oltp_read_write \
prepare
插入过程
从截图可以看到插入数据由4个步骤组成
- 初始化线程:由 --threads 控制(默认1),一般调整为与表数量相同
- 创建表:由 --tables 控制(默认1)
- 插数据:由 --table-size 控制(默认10000)
- 创索引:统一创建k列索引(表中存在2列索引,id列(主键)和k列)
注意:插入数据时,使用任何用例插入的数据都是相同的,例如
sysbench <参数选项> oltp_read_write prepare sysbench <参数选项> oltp_read_only prepare
使用两种不同的用例插入数据,实际的表结构、数据都是一样的。
插入完成后可以通过数据库查看实际结果(生成 sbtest 开头的表)
每张表行数与插入一致(10w)
表属性(共4列,id主键索引,k普通索引)
3.2. 运行测试
运行测试的命令也非常简单,在插入数据命令的基础上增加一些测试时间、实时报告间隔、线程数、测试模式等即可。
sysbench \
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=5 \
--table-size=100000 \
--threads=100 \
--time=5 \
--report-interval=1 \
--db-ps-mode=disable \
oltp_read_write \
run
3.3. 清理数据
清理数据只需要在插入数据命令的基础上,将 prepare 改为 cleanup 即可
sysbench \
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=5 \
--table-size=100000 \
--threads=5 \
oltp_read_write \
cleanup
3.4. 结果解读
sysbench自带报告分为2部分,一部分为实时报告、另一部分为最终结果
【第一部分】实时报告
[ 1s ] thds: 100 tps: 0.00 qps: 1116.89 (r/w/o: 1017.26/0.00/99.63) lat (ms,95%): 0.00 err/s: 0.00 reconn/s: 0.00
[ 2s ] thds: 100 tps: 56.10 qps: 986.71 (r/w/o: 595.03/285.49/106.18) lat (ms,95%): 1973.38 err/s: 0.00 reconn/s: 0.00
[ 3s ] thds: 100 tps: 57.97 qps: 1460.23 (r/w/o: 1111.42/227.88/120.94) lat (ms,95%): 2009.23 err/s: 0.00 reconn/s: 0.00
[ 4s ] thds: 100 tps: 77.74 qps: 1638.61 (r/w/o: 1132.27/350.85/155.49) lat (ms,95%): 1376.60 err/s: 0.00 reconn/s: 0.00
[ 5s ] thds: 100 tps: 111.39 qps: 1844.43 (r/w/o: 1217.24/405.41/221.77) lat (ms,95%): 4943.53 err/s: 0.00 reconn/s: 0.00
- [ 3s ]: 表示报告中的数据是在过去3秒钟内收集的。
- thds: 100: 当前测试使用了100个线程。
- tps: 57.97: 每秒钟执行的事务数为57.97。这表示数据库在每秒处理的事务数量。
- qps: 1460.23: 每秒钟执行的查询数为1460.23。这个值包括了读取、写入和其他类型的操作。
- (r/w/o: 1111.42/227.88/120.94): 显示了查询的详细分布情况。有1111.42个读取操作(r),227.88个写入操作(w),以及120.94个其他操作(o)。
- lat (ms,95%): 2009.23: 在95%的查询中,最大延迟为2009.23毫秒。这个报告可以通过 --percentile 来设置百分位
- err/s: 0.00: 没有错误发生,错误率为0。
- reconn/s: 0.00: 没有重新连接发生,重新连接率为0。
【第二部分】最终结果
# SQL统计部分
SQL statistics:
queries performed:
read: 5642 # 共执行了5642次读取操作
write: 1612 # 共执行了1612次写入操作
other: 806 # 共执行了806次其他操作
total: 8060 # 总共执行了8060次操作
transactions: 403 (67.59 per sec.) # 执行了403个事务,平均每秒执行了67.59个事务
queries: 8060 (1351.90 per sec.) # 执行了8060次查询操作,平均每秒执行了1351.90次查询
ignored errors: 0 (0.00 per sec.) # 忽略了0个错误,平均每秒发生了0.00次错误
reconnects: 0 (0.00 per sec.) # 重新连接次数为0,平均每秒重新连接次数为0.00次
# 事务统计部分
Throughput:
events/s (eps): 67.5948 # 每秒事务数
time elapsed: 5.9620s # 测试时间
total number of events: 403 # 事务总数
# 延迟统计部分
Latency (ms):
min: 352.81 # 最小延迟
avg: 1375.90 # 平均延迟
max: 5408.28 # 最大延迟
95th percentile: 4943.53 # 第95百分位延迟
sum: 554486.87 # 总延迟
# 偏差部分(当偏差过大,意味着各个线程的事件执行量差异较大;当偏差较低,则表示各个线程的执行量相对均匀)
Threads fairness:
events (avg/stddev): 4.0300/1.82 # 平均每个线程执行了4.0300个事件,标准偏差为1.82
execution time (avg/stddev): 5.5449/0.15 # 平均执行时间为5.5449秒,标准偏差为0.15秒
3.5. 命令技巧
命令行中有一个非常好用的参数(--config-file),这个参数是用于指定配置文件的路径和名称,它可以加载预先定义好的配置文件,避免在命令行中重复输入大量的参数选项。举个例子:
这是一条运行测试的命令(命令很长)
sysbench --db-driver=pgsql --pgsql-host=localhost --pgsql-password=123456 --pgsql-port=54321 --pgsql-db=kingbase --pgsql-user=system --tables=10 --table-size=10000 --threads=10 --report-interval=1 --time=5 oltp_read_write run
一般数据库配置和数据配置我们都固定,所以可以将这些参数放到文件中
vim test.conf
db-driver=pgsql
pgsql-host=localhost
pgsql-password=123456
pgsql-port=54321
pgsql-db=kingbase
pgsql-user=system
在执行命令时直接读取这个文件,其他灵活配置的参数放在外面会更方便
sysbench --config-file=./test.conf --time=5 oltp_read_write run
注意:不确定是兼容性问题还是bug,文件中配置的 tables 和 table-size 参数无法生效
4. 用例类型汇总
4.1. 读性能测试
① 随机读性能
测试命令(oltp_read_only)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
oltp_read_only \
run
源码
if not sysbench.opt.skip_trx then
begin()
end
execute_point_selects() // 条件查询(1个where)
if sysbench.opt.range_selects then
execute_simple_ranges() // 范围查询
execute_sum_ranges() // 范围查询+求和
execute_order_ranges() // 范围查询+排序
execute_distinct_ranges() // 范围查询+排序+去重
end
if not sysbench.opt.skip_trx then
commit()
end
测试语句
BEGIN;
SELECT c FROM sbtest1 WHERE id=$1;
SELECT c FROM sbtest1 WHERE id BETWEEN $1 AND $2;
SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN $1 AND $2;
SELECT c FROM sbtest1 WHERE id BETWEEN $1 AND $2 ORDER BY c;
SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN $1 AND $2 ORDER BY;
COMMIT;
② 单点查询
测试命令(oltp_point_select)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
oltp_point_select \
run
源码
function event()
execute_point_selects() // 条件查询
end
测试语句
SELECT c FROM sbtest1 WHERE id=$1;
③ 随机点查询
测试命令(select_random_points)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
select_random_points \
run
源码
// k列in随机匹配10个值
for i = 1, sysbench.opt.random_points do
local rmin = rlen * thread_id
local rmax = rmin + rlen
params[i]:set(sysbench.rand.default(rmin, rmax))
end
测试语句
SELECT
id, k, c, pad
FROM
sbtest1
WHERE
k IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
④ 随机范围查询
测试命令(select_random_ranges)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
select_random_ranges \
run
源码
// 10个随机BETWEEN范围查询
for i = 1, sysbench.opt.number_of_ranges*2, 2 do
local rmin = rlen * thread_id
local rmax = rmin + rlen
local val = sysbench.rand.default(rmin, rmax)
params[i]:set(val)
params[i+1]:set(val + sysbench.opt.delta)
end
测试语句
SELECT
count(k)
FROM
sbtest1
WHERE
k BETWEEN $1 AND $2
OR
k BETWEEN $3 AND $4
OR
k BETWEEN $5 AND $6
OR
k BETWEEN $7 AND $8
OR
k BETWEEN $9 AND $10
OR
k BETWEEN $11 AND $12
OR
k BETWEEN $13 AND $14
OR
k BETWEEN $15 AND $16
OR
k BETWEEN $17 AND $18
OR
k BETWEEN $19 AND $20;
4.2. 写性能测试
① 随机写性能
测试命令(oltp_write_only)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
oltp_write_only \
run
源码
if not sysbench.opt.skip_trx then
begin()
end
execute_index_updates() // 更新索引列
execute_non_index_updates() // 更新非索引列
execute_delete_inserts() // 先delete,再insert
if not sysbench.opt.skip_trx then
commit()
end
测试语句
BEGIN;
UPDATE sbtest1 SET k=k+1 WHERE id=$1;
UPDATE sbtest1 SET c=$1 WHERE id=$2;
DELETE FROM sbtest1 WHERE id=$1;
INSERT INTO sbtest1 (id, k, c, pad) VALUES ($1, $2, $3, $4);
COMMIT;
② 持续插入
测试命令(oltp_insert)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
oltp_insert \
run
源码(仅insert)
local table_name = "sbtest" .. sysbench.rand.uniform(1, sysbench.opt.tables)
local k_val = sysbench.rand.default(1, sysbench.opt.table_size)
local c_val = get_c_value()
local pad_val = get_pad_value()
con:query(
string.format(
"INSERT INTO %s (k, c, pad) VALUES " "(%d, '%s', '%s')", table_name, k_val, c_val, pad_val))
测试语句
INSERT INTO
sbtest1 (k, c, pad)
VALUES
($1, $2, $3);
③ 持续删除
测试命令(oltp_delete)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
oltp_delete \
run
源码(仅delete)
local tnum = sysbench.rand.uniform(1, sysbench.opt.tables)
local id = sysbench.rand.default(1, sysbench.opt.table_size)
param[tnum].deletes[1]:set(id)
stmt[tnum].deletes:execute()
测试语句
DELETE FROM sbtest1 WHERE id=$1;
④ 更新索引列
测试命令(oltp_update_index)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
oltp_update_index \
run
源码(仅update索引列"k列")
execute_index_updates(con)
测试语句
UPDATE sbtest1 SET k=k+1 WHERE id=$1
⑤ 更新非索引列
测试命令(oltp_update_non_index)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
oltp_update_non_index \
run
源码(仅更新非索引列"c列"
execute_non_index_updates()
测试语句
UPDATE sbtest1 SET c=$1 WHERE id=$2;
4.3. 读写混合性能测试
测试命令(oltp_read_write)
sysbench
--db-driver=pgsql \
--pgsql-host=localhost \
--pgsql-password=123456 \
--pgsql-port=54321 \
--pgsql-db=test \
--pgsql-user=system \
--tables=10 \
--table-size=100000 \
--threads=100 \
--time=600 \
--report-interval=5 \
--db-ps-mode=disable \
oltp_read_write \
run
源码(实际上就是 read_only + write_only)
if not sysbench.opt.skip_trx then
begin()
end
execute_point_selects() // 单点where条件查询
if sysbench.opt.range_selects then
execute_simple_ranges() // 范围查询
execute_sum_ranges() // 范围查询+求和
execute_order_ranges() // 范围查询+排序
execute_distinct_ranges() // 范围查询+排序+去重
end
execute_index_updates() // 索引列更新
execute_non_index_updates() // 非索引列更新
execute_delete_inserts() // 先delete,再insert
if not sysbench.opt.skip_trx then
commit()
end
测试语句
BEGIN;
SELECT c FROM sbtest1 WHERE id=$1;
SELECT c FROM sbtest1 WHERE id BETWEEN $1 AND $2;
SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN $1 AND $2;
SELECT c FROM sbtest1 WHERE id BETWEEN $1 AND $2 ORDER BY c;
SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN $1 AND $2 ORDER BY c;
UPDATE sbtest1 SET k=k+1 WHERE id=$1;
UPDATE sbtest1 SET c=$1 WHERE id=$2;
DELETE FROM sbtest1 WHERE id=$1;
INSERT INTO sbtest1 (id, k, c, pad) VALUES ($1, $2, $3, $4);
COMMIT;
5. 测试语句定义
源码如下
local stmt_defs = {
point_selects = {
"SELECT c FROM sbtest%u WHERE id=?",
t.INT},
simple_ranges = {
"SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ?",
t.INT, t.INT},
sum_ranges = {
"SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?",
t.INT, t.INT},
order_ranges = {
"SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c",
t.INT, t.INT},
distinct_ranges = {
"SELECT DISTINCT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c",
t.INT, t.INT},
index_updates = {
"UPDATE sbtest%u SET k=k+1 WHERE id=?",
t.INT},
non_index_updates = {
"UPDATE sbtest%u SET c=? WHERE id=?",
{t.CHAR, 120}, t.INT},
deletes = {
"DELETE FROM sbtest%u WHERE id=?",
t.INT},
inserts = {
"INSERT INTO sbtest%u (id, k, c, pad) VALUES (?, ?, ?, ?)",
t.INT, t.INT, {t.CHAR, 120}, {t.CHAR, 60}},
}
标签:压测,数据库,db,pgsql,--,测试,id,sysbench
From: https://blog.csdn.net/m0_61066945/article/details/140066537