背景
使用sysbench基准工具对Mycat和Atlas进行压测,通过综合比较从中选择一个作为今后选择的方向,更多背景信息请参考如下:
sysbench介绍
SysBench是一个模块化的、跨平台、多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况。它主要包括以下几种方式的测试:
- 列表内容
- cpu性能
- 磁盘io性能
- 调度程序性能
- 内存分配及传输速度
- POSIX线程性能
- 数据库性能(OLTP基准测试)
sysbench压测用法参考如下:
结合sysbench-sharding一起使用,扩展版insert时增加2个参数,其他都一样。
安装sysbench
sysbench国外个人开发的,基本无文档,国内有些博客可以参考,不同版本参数不一,用法也有稍许差异,它有0.4、0.5、1.0,其中0.4功能较弱,1.0网上缺少相关文档缺少,另外我们对sysbench功能也没有极致的要求,综合考虑选择0.5版本
注意:安装sysbench前,先安装lua库和mysql客户端mysql++-devel.x86_64或mysql++-devel.i686
安装sysbench:
1.下载(官方提供)
https://pan.baidu.com/s/1qYdO2oW
2.解压
tar xzvf sysbench-0.5.tar.gz
3.安装
cd sysbench-0.5
./autogen.sh
./configure –with-mysql-includes=/usr/include/mysql –with-mysql-libs=/usr/lib64/mysql
make
make install
sysbench项目工程不大,其实不必安装(不用执行make install,看个人,我就是这样做的),编译后源码目录下生成执行文件sysbench,直接带上相关参数就可以执行了。简单方便,容易修改代码。
sysbench扩展版,支持分库分表测试
sysbench-sharding扩展版下载
sysbench-0.5-sharding.tar.gz百度下载地址:https://pan.baidu.com/s/1MeLoUK8ndyuuOqafvhtUgQ
为什么要扩展sysbench
- 效率优先、工具化。基于lua开发很多能一键运行的脚本,直接使用sysbench压测,需要写好几种类型脚本,填上许多参数很麻烦且学习成本高
- 客户端生成全局唯一数字ID。sysbench预处理创建表为自增主键,也支持客户端生成主键但实测算法是有问题的,运行程序会因为出现重复主键报错而终止,就算忽略错误也会影响实测性能,而分库分表场景需要由客户端生成全局唯一ID
商业数据库中间件开发商,全民软件压测工具也是基于sysbench扩展的。不过闭源,可以下载二进制库,用于测试自家开发的OneProxy,却无法兼容Mycat和Atlas,具体原因不详
OneProxy :: 如何准备sysbench的分库分表测试环境?无须DBA手工建分表!
http://www.onexsoft.com/zh/oneproxy-sysbench-sharding.html
修改sysbench代码
全局唯一ID生成规则:一个无锁自增算法,可以指定ID起点值和步长且可配置,新增参数为id-start-val和id-step-val,id-start-val表示id起始值,id-step-val为步长,具体应用请看stress-testing-atlas-insert.sh
sysbench.c文件增加代码
// sb_arg_t结构体增加字段
sb_arg_t general_args[] = {
{"id-start-val", "generate start value of id", SB_ARG_TYPE_INT, "0"},
{"id-step-val", "generate start value of id", SB_ARG_TYPE_INT, "1"}
}
static int init(void)
{
// 增加代码片段
sb_globals.id_start_val = sb_get_value_int("id-start-val");
sb_globals.id_step_val = sb_get_value_int("id-step-val");
if(sb_globals.id_step_val == 0)
{
log_text(LOG_FATAL, "Invalid value for --id-step-val: %d.\n", sb_globals.id_step_val);
return 1;
}
}
// 此方法生成全局唯一ID,id_start_val起始ID,id_step_val步长
int sb_global_unique_id()
{
return __sync_fetch_and_add( &sb_globals.id_start_val, sb_globals.id_step_val);
}
sysbench.h文件中sb_globals_t结构体增加2个字段
typedef struct
{
unsigned int id_start_val; /* 扩展变量、用于指定全局起始id */
unsigned int id_step_val; /* 扩展变量、用于生成全局唯一id的步长 */
} sb_globals_t;
向lua库函数注册sb_global_unique_id函数,提供给lua脚本调用生成全局唯一ID,下面script_lua.c文件增加代码
lua_State *sb_lua_new_state(const char *scriptname, int thread_id)
{
// 新增代码片段
lua_pushcfunction(state, sb_lua_global_unique_id);
lua_setglobal(state, "sb_global_unique_id");
}
int sb_lua_global_unique_id(lua_State *L)
{
lua_pushnumber(L, sb_global_unique_id());
return 1;
}
说明:sysbench-sharding同理sysbench安装
lua脚本修改
使用sysbench对数据库中间件做压测,它提供DB相关一系列lua脚本,但默认脚本并不完全符合要求,所以需要对相关脚本进行修改或新增脚本,以支撑分库分表测试功能。
本次分库分表压测是为了生成全局唯一ID,所以只需要修改insert.lua脚本就可以了。
insert.lua修改版代码如下:
-- 修改event方法中部分片段代码
function event(thread_id)
local table_name
local i
local c_val
local k_val
local pad_val
table_name = "sbtest".. sb_rand_uniform(1, oltp_tables_count)
k_val = sb_rand(1, oltp_table_size)
c_val = sb_rand_str([[
###########-###########-###########-###########-###########-###########-###########-###########-###########-###########]])
pad_val = sb_rand_str([[
###########-###########-###########-###########-###########]])
if (db_driver == "pgsql" and oltp_auto_inc) then
rs = db_query("INSERT INTO " .. table_name .. " (k, c, pad) VALUES " ..
string.format("(%d, '%s', '%s')", k_val, c_val, pad_val))
else
if (oltp_auto_inc) then
i = 0
else
-- i = sb_rand_uniq(1, oltp_table_size)
i = sb_global_unique_id();
end
rs = db_query("INSERT INTO " .. table_name ..
" (id, k, c, pad) VALUES " ..
string.format("(%d, %d, '%s', '%s')", i, k_val, c_val,
pad_val))
end
end
创建自动化脚本
编写lua脚本设置参数时,Mycat与Atlas的区别:
* Mycat携带账号参数,需要使用Mycat的账号,因为Mycat首先是逻辑库概念,对物理库进行了隔离且有资源管理,就是权限控制
* Atlas携带账号参数,直接使用MySQL的账号,因为Atlas没有权限管理,也没有对MySQL物理资源进行管理
lua脚本存储路径
lua脚本与sysbench可执行同一目录(sysbench编译后自动生成到该目录)
删除表数据
batch-mysql-truncate.sh内容如下:
#!/bin/bash
mysql -uzhitao -p123456 -hIP01 -P3306 -e "truncate table dbproxy.sbtest1;"
sleep 2
mysql -uzhitao -p123456 -hIP02 -P3306 -e "truncate table dbproxy.sbtest1;"
sleep 2
mysql -uzhitao -p123456 -hIP03 -P3306 -e "truncate table dbproxy.sbtest1;"
sleep 2
mysql -uzhitao -p123456 -hIP04 -P3306 -e "truncate table dbproxy.sbtest1;"
sleep 2
插入数据压测脚本
Atlas的insert脚本stress-testing-atlas-insert.sh如下
#!/bin/bash
./batch-mysql-truncate.sh
# 默认8线程
NUMTHREADS=8
echo -e "线程数赋值前 $1"
NUMTHREADS=$1
#判断如果$1为空
if [ -z $1 ]; then
NUMTHREADS=8
fi
echo -e "线程数赋值后 $1"
MAXTIME=$2
if [ -z $2 ]; then
MAXTIME=120
fi
./sysbench --test=/home/zhitao.li/sysbench-0.5/sysbench/tests/db/insert.lua --mysql-host=dbproxyIP --mysql-port=1234 \
--mysql-user=zhitao --mysql-password=123456 --mysql-db=dbproxy --oltp-tables-count=1 --oltp-table-size=10000 \
--report-interval=10 --rand-init=on --max-requests=0 --report-interval=10 --oltp_auto_inc=off \
--oltp-read-only=off --max-time=$MAXTIME --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors \
# 新增参数,用于调节生成全局唯一ID,id-start-val和id-step-val参数可选,id-start-val表示id起始值,id-step-val为步长
--id-start-val=1 --id-step-val=4 \
run
#--oltp-read-only=off --max-time=120 --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors
执行命令为:./stress-testing-atlas-insert.sh 线程数 执行持续时间(单位秒)
Mycat的insert脚本stress-testing-mycat-insert.sh如下
#!/bin/bash
./batch-mysql-truncate.sh
sleep 5
# 默认8线程
NUMTHREADS=8
echo -e "线程数赋值前 $1"
NUMTHREADS=$1
#判断如果$1为空
if [ -z $1 ]; then
NUMTHREADS=8
fi
echo -e "线程数赋值后 $1"
MAXTIME=$2
if [ -z $2 ]; then
MAXTIME=120
fi
./sysbench --test=/home/zhitao.li/sysbench-0.5/sysbench/tests/db/insert.lua --mysql-host=dbproxyIP --mysql-port=8066 \
--mysql-user=root --mysql-password=123456 --mysql-db=testdb --oltp-tables-count=1 --oltp-table-size=1000000 --oltp_auto_inc=off \
--report-interval=10 --rand-init=on --max-requests=0 --oltp-test-mode=nontrx --oltp-nontrx-mode=select --report-interval=10 \
--oltp-read-only=off --max-time=$MAXTIME --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors \
run
#--oltp-read-only=off --max-time=120 --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors
执行命令为:./stress-testing-mycat-insert.sh 线程数 执行持续时间(单位秒)
查询压测脚本
Atlas的select脚本stress-testing-atlas-select.sh如下
#!/bin/bash
# 默认8线程
NUMTHREADS=8
echo -e "线程数赋值前 $1"
NUMTHREADS=$1
#判断如果$1为空
if [ -z $1 ]; then
NUMTHREADS=8
fi
echo -e "线程数赋值后 $1"
MAXTIME=$2
if [ -z $2 ]; then
MAXTIME=120
fi
./sysbench --mysql-host=dbproxyIP --mysql-port=1234 --mysql-user=zhitao --mysql-password=123456 \
--mysql-db=dbproxy --max-requests=0 --test=/home/zhitao.li/sysbench-0.5/sysbench/tests/db/select.lua --num-threads=$NUMTHREADS \
--oltp_tables_count=1 --oltp-table-size=1000000 --rand-init=on --max-time=$MAXTIME --report-interval=10 \
--oltp-test-mode=nontrx --oltp-nontrx-mode=select --oltp-read-only=on --oltp-skip-trx=on \
run
执行命令为:./stress-testing-atlas-select.sh 线程数 执行持续时间(单位秒)
Mycat的select脚本stress-testing-mycat-select.sh如下:
#!/bin/bash
# 默认8线程
NUMTHREADS=8
echo -e "线程数赋值前 $1"
NUMTHREADS=$1
#判断如果$1为空
if [ -z $1 ]; then
NUMTHREADS=8
fi
echo -e "线程数赋值后 $1"
MAXTIME=$2
if [ -z $2 ]; then
MAXTIME=120
fi
./sysbench --test=/home/zhitao.li/sysbench-0.5/sysbench/tests/db/select.lua --mysql-host=dbproxyIP --mysql-port=8066 \
--mysql-user=root --mysql-password=123456 --mysql-db=testdb --oltp-tables-count=1 --oltp-table-size=1000000 --oltp_auto_inc=off \
--report-interval=10 --rand-init=on --max-requests=0 --oltp-test-mode=nontrx --oltp-nontrx-mode=select --report-interval=10 \
--oltp-read-only=off --max-time=$MAXTIME --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors \
run
#--oltp-read-only=off --max-time=120 --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors
执行命令为:./stress-testing-mycat-select.sh 线程数 执行持续时间(单位秒)
修改数据压测脚本
Atlas的update脚本stress-testing-atlas-update.sh如下
#!/bin/bash
NUMTHREADS=8
echo -e "线程数赋值前 $1"
NUMTHREADS=$1
#判断如果$1为空
if [ -z $1 ]; then
NUMTHREADS=8
fi
echo -e "线程数赋值后 $1"
MAXTIME=$2
if [ -z $2 ]; then
MAXTIME=120
fi
./sysbench --test=/home/zhitao.li/sysbench-0.5/sysbench/tests/db/update_non_index.lua --mysql-host=dbproxyIP --mysql-port=1234 \
--mysql-user=zhitao --mysql-password=123456 --mysql-db=dbproxy --oltp-tables-count=1 --oltp-table-size=1000000 \
--report-interval=10 --rand-init=on --max-requests=0 --report-interval=10 --oltp_auto_inc=off \
--oltp-read-only=off --max-time=$MAXTIME --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors \
run
执行命令为:./stress-testing-atlas-update.sh 线程数 执行持续时间(单位秒)
Mycat的update脚本stress-testing-mycat-update.sh如下
#!/bin/bash
sleep 5
NUMTHREADS=8
echo -e "线程数赋值前 $1"
NUMTHREADS=$1
#判断如果$1为空
if [ -z $1 ]; then
NUMTHREADS=8
fi
echo -e "线程数赋值后 $1"
MAXTIME=$2
if [ -z $2 ]; then
MAXTIME=120
fi
./sysbench --test=/home/zhitao.li/sysbench-0.5/sysbench/tests/db/update_non_index.lua --mysql-host=dbproxyIP --mysql-port=8066 \
--mysql-user=root --mysql-password=123456 --mysql-db=testdb --oltp-tables-count=1 --oltp-table-size=1000000 --oltp_auto_inc=off \
--report-interval=10 --rand-init=on --max-requests=0 --oltp-test-mode=nontrx --oltp-nontrx-mode=select --report-interval=10 \
--oltp-read-only=off --max-time=$MAXTIME --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors \
run
#--oltp-read-only=off --max-time=120 --num-threads=$NUMTHREADS --mysql-ignore-duplicates=on --mysql-ignore-errors
执行命令为:./stress-testing-mycat-update.sh 线程数 执行持续时间(单位秒)
lua批量化脚本,利用sysbench在不同线程数下进行压力测试的自动化脚本
批量化插入数据压测脚本
脚本batch-atlas-insert.sh如下
#!/bin/bash
# 执行持续时间(单位秒)
MAXTIME=180
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-insert.sh 2 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-insert.sh 4 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-insert.sh 8 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-insert.sh 16 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-insert.sh 32 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-insert.sh 64 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-insert.sh 128 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-insert.sh 256 $MAXTIME
执行命令为:./batch-atlas-insert.sh
脚本batch-mycat-insert.sh如下
#!/bin/bash
# 执行持续时间(单位秒)
MAXTIME=180
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-insert.sh 2 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-insert.sh 4 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-insert.sh 8 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-insert.sh 16 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-insert.sh 32 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-insert.sh 64 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-insert.sh 128 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-insert.sh 256 $MAXTIME
执行命令为:
批量化查询数据压测脚本
脚本batch-atlas-select.sh如下
#!/bin/bash
# 执行持续时间(单位秒)
MAXTIME=180
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-select.sh 2 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-select.sh 4 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-select.sh 8 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-select.sh 16 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-select.sh 32 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-select.sh 64 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-select.sh 128 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-select.sh 256 $MAXTIME
执行命令为:./batch-atlas-select.sh
脚本batch-mycat-select.sh如下
#!/bin/bash
MAXTIME=180
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-select.sh 2 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-select.sh 4 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-select.sh 8 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-select.sh 16 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-select.sh 32 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-select.sh 64 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-select.sh 128 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-select.sh 256 $MAXTIME
执行命令为:
批量化修改数据压测脚本
脚本batch-atlas-update.sh如下
#!/bin/bash
MAXTIME=180
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-update.sh 2 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-update.sh 4 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-update.sh 8 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-update.sh 16 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-update.sh 32 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-update.sh 64 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-update.sh 128 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-atlas-update.sh 256 $MAXTIME
执行命令为:./batch-atlas-update.sh
脚本batch-mycat-update.sh如下
#!/bin/bash
MAXTIME=180
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-update.sh 2 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-update.sh 4 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-update.sh 8 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-update.sh 16 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-update.sh 32 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-update.sh 64 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-update.sh 128 $MAXTIME
date "+%Y-%m-%d %H:%M:%S"
./stress-testing-mycat-update.sh 256 $MAXTIME
执行命令为:./batch-mycat-update.sh
压测运行
脚本batch-stress-testing.sh如下
./batch-atlas-insert.sh
./batch-mycat-insert.sh
./batch-atlas-select.sh
./batch-mycat-select.sh
./batch-atlas-update.sh
./batch-mycat-update.sh
以上脚本输出结果格式,请参照: 使用sysbench对mysql压力测试 “结果解读”部分