使用sysbench对mysql压力测试
数据库的基准测试是对数据库的性能指标进行定量的、可复现的、可对比的测试。
基准测试与压力测试
基准测试可以理解为针对系统的一种压力测试。但基准测试不关心业务逻辑,更加简单、直接、易于测试,数据可以由工具生成,不要求真实;而压力测试一般考虑业务逻辑(如购物车业务),要求真实的数据。
2、基准测试的作用
对于多数Web应用,整个系统的瓶颈在于数据库;原因很简单:Web应用中的其他因素,例如网络带宽、负载均衡节点、应用服务器(包括CPU、内存、硬盘灯、连接数等)、缓存,都很容易通过水平的扩展(俗称加机器)来实现性能的提高。而对于MySQL,由于数据一致性的要求,无法通过增加机器来分散向数据库写数据带来的压力;虽然可以通过前置缓存(Redis等)、读写分离、分库分表来减轻压力,但是与系统其它组件的水平扩展相比,受到了太多的限制。
而对数据库的基准测试的作用,就是分析在当前的配置下(包括硬件配置、OS、数据库设置等),数据库的性能表现,从而找出MySQL的性能阈值,并根据实际系统的要求调整配置。
3、基准测试的指标
常见的数据库指标包括:
- TPS/QPS:衡量吞吐量。
- 响应时间:包括平均响应时间、最小响应时间、最大响应时间、时间百分比等,其中时间百分比参考意义较大,如前95%的请求的最大响应时间。。
- 并发量:同时处理的查询请求的数量。
4、基准测试的分类
对MySQL的基准测试,有如下两种思路:
(1)针对整个系统的基准测试:通过http请求进行测试,如通过浏览器、APP或postman等测试工具。该方案的优点是能够更好的针对整个系统,测试结果更加准确;缺点是设计复杂实现困难。
(2)只针对MySQL的基准测试:优点和缺点与针对整个系统的测试恰好相反。
在针对MySQL进行基准测试时,一般使用专门的工具进行,例如mysqlslap、sysbench等。其中,sysbench比mysqlslap更通用、更强大,且更适合Innodb(因为模拟了许多Innodb的IO特性),下面介绍使用sysbench进行基准测试的方法。
二、sysbench
1、sysbench简介
sysbench是跨平台的基准测试工具,支持多线程,支持多种数据库;主要包括以下几种测试:
- cpu性能
- 磁盘io性能
- 调度程序性能
- 内存分配及传输速度
- POSIX线程性能
- 数据库性能(OLTP基准测试)
本文主要介绍对数据库性能的测试。
2、sysbench安装
本文使用的环境时CentOS 6.5;在其他Linux系统上的安装方法大同小异。MySQL版本是5.6。
(1)下载解压
1
2
3
|
wget https://github.com/akopytov/sysbench/archive/1.0.zip -O "sysbench-1.0.zip" unzip sysbench-1.0.zip cd sysbench-1.0 |
(2)安装依赖
1
|
yum install automake libtool –y |
(3)安装
安装之前,确保位于之前解压的sysbench目录中。
1
2
3
4
5
|
./autogen.sh ./configure export LD_LIBRARY_PATH=/usr/ local /mysql/include #这里换成机器中mysql路径下的include make make install |
(4)安装成功
1
2
|
[root@test sysbench-1.0]# sysbench --version sysbench 1.0.9 |
3、sysbench语法
执行sysbench –help,可以看到sysbench的详细使用方法。
sysbench的基本语法如下:
sysbench [options]... [testname] [command]
下面说明实际使用中,常用的参数和命令。
(1)command
command是sysbench要执行的命令,包括prepare、run和cleanup,顾名思义,prepare是为测试提前准备数据,run是执行正式的测试,cleanup是在测试完成后对数据库进行清理。
(2)testname
testname指定了要进行的测试,在老版本的sysbench中,可以通过--test参数指定测试的脚本;而在新版本中,--test参数已经声明为废弃,可以不使用--test,而是直接指定脚本。
例如,如下两种方法效果是一样的:
1
2
|
sysbench --test=./tests/include/oltp_legacy/oltp.lua sysbench ./tests/include/oltp_legacy/oltp.lua |
测试时使用的脚本为lua脚本,可以使用sysbench自带脚本,也可以自己开发。对于大多数应用,使用sysbench自带的脚本就足够了。不同版本的sysbench中,lua脚本的位置可能不同,可以自己在sysbench路径下使用find命令搜索oltp.lua。P.S.:大多数数据服务都是oltp类型的,如果你不了解什么是oltp,那么大概率你的数据服务就是oltp类型的。
(3)options
sysbench的参数有很多,其中比较常用的包括:
MySQL连接信息参数
- --mysql-host:MySQL服务器主机名,默认localhost;如果在本机上使用localhost报错,提示无法连接MySQL服务器,改成本机的IP地址应该就可以了。
- --mysql-port:MySQL服务器端口,默认3306
- --mysql-user:用户名
- --mysql-password:密码
MySQL执行参数
- --oltp-test-mode:执行模式,包括simple、nontrx和complex,默认是complex。simple模式下只测试简单的查询;nontrx不仅测试查询,还测试插入更新等,但是不使用事务;complex模式下测试最全面,会测试增删改查,而且会使用事务。可以根据自己的需要选择测试模式。
- --oltp-tables-count:测试的表数量,根据实际情况选择
- --oltp-table-size:测试的表的大小,根据实际情况选择
- --threads:客户端的并发连接数
- --time:测试执行的时间,单位是秒,该值不要太短,可以选择120
- --report-interval:生成报告的时间间隔,单位是秒,如10
4、sysbench使用举例
在执行sysbench时,应该注意:
(1)尽量不要在MySQL服务器运行的机器上进行测试,一方面可能无法体现网络(哪怕是局域网)的影响,另一方面,sysbench的运行(尤其是设置的并发数较高时)会影响MySQL服务器的表现。
(2)可以逐步增加客户端的并发连接数(--thread参数),观察在连接数不同情况下,MySQL服务器的表现;如分别设置为10,20,50,100等。
(3)一般执行模式选择complex即可,如果需要特别测试服务器只读性能,或不使用事务时的性能,可以选择simple模式或nontrx模式。
(4)如果连续进行多次测试,注意确保之前测试的数据已经被清理干净。
下面是sysbench使用的一个例子:
(1)准备数据
1
|
sysbench ./tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.10.10 --mysql-port=3306 --mysql-user=root --mysql-password=123456 --oltp-test-mode=complex --oltp-tables-count=10 --oltp-table-size=100000 --threads=10 --time=120 --report-interval=10 prepare |
其中,执行模式为complex,使用了10个表,每个表有10万条数据,客户端的并发线程数为10,执行时间为120秒,每10秒生成一次报告。
(2)执行测试
将测试结果导出到文件中,便于后续分析。
1
|
sysbench ./tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.10.10 --mysql-port=3306 --mysql-user=root --mysql-password=123456 --oltp-test-mode=complex --oltp-tables-count=10 --oltp-table-size=100000 --threads=10 --time=120 --report-interval=10 run >> /home/test/mysysbench.log |
(3)清理数据
执行完测试后,清理数据,否则后面的测试会受到影响。
1
|
sysbench ./tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.10.10 --mysql-port=3306 --mysql-user=root --mysql-password=123456 cleanup |
5、测试结果
测试结束后,查看输出文件,如下所示:
其中,对于我们比较重要的信息包括:
queries:查询总数及qps
transactions:事务总数及tps
Latency-95th percentile:前95%的请求的最大响应时间,本例中是344毫秒,这个延迟非常大,是因为我用的MySQL服务器性能很差;在正式环境中这个数值是绝对不能接受的。
三、建议
下面是使用sysbench的一些建议。
1、在开始测试之前,应该首先明确:应采用针对整个系统的基准测试,还是针对MySQL的基准测试,还是二者都需要。
2、如果需要针对MySQL的基准测试,那么还需要明确精度方面的要求:是否需要使用生产环境的真实数据,还是使用工具生成也可以;前者实施起来更加繁琐。如果要使用真实数据,尽量使用全部数据,而不是部分数据。
3、基准测试要进行多次才有意义。
4、测试时需要注意主从同步的状态。
5、测试必须模拟多线程的情况,单线程情况不但无法模拟真实的效率,也无法模拟阻塞甚至死锁情况。
参考文献
http://blog.csdn.net/oahz4699092zhao/article/details/53332105
它主要包括以下几种方式的测试:
- cpu性能
- 磁盘io性能
- 调度程序性能
- 内存分配及传输速度
- POSIX线程性能
- 数据库性能(OLTP基准测试)
sysbench的数据库OLTP测试支持MySQL、PostgreSQL、Oracle,目前主要用于Linux操作系统,开源社区已经将sysbench移植到了Windows,并支持SQL Server的基准测试。
废话不多说,开始。
1. sysbench安装
- mysql版本: mysql-community-server-5.6.29
- OS: CentOS 6.7 X86_64
- sysbench 0.5相比0.4版本有一些变化,包括oltp测试结合了lua脚本,还多了一些隐藏选项,本文会涉及得到一部分。
目前许多仓库里已编译好的二进制sysbench还是0.4.x版本,不过现在主流也还是github上的0.5(我这里使用的是1.0),可以从 这里下载0.5版本的rpm包直接安装,不过我选择自己编译,因为只有这个办法是通用的。
2. 使用sysbench对mysql压测
2.1 只读示例
./bin/sysbench --test=share/sysbench/oltp.lua \
--mysql-host=10.229.153.175 --mysql-port=7001 --mysql-user=kp --mysql-password=kp123456 \
--mysql-db=conanwang --oltp-tables-count=10 --oltp-table-size=10000000 \
--report-interval=10 --oltp-dist-type=uniform --rand-init=on --max-requests=0 \
--oltp-test-mode=nontrx --oltp-nontrx-mode=select \
--oltp-read-only=on --oltp-skip-trx=on \
--max-time=120 --num-threads=12 \
prepare
来准备好表和数据,run
执行真正的压测,cleanup
用来清除数据和表。实际prepare的表结构:上面的测试命令代表的是:对mysql进行oltp基准测试,表数量10,每表行数约1000w(几乎delete多少就会insert的多少),并且是非事务的只读测试,持续60s,并发线程数12。
需要说明的选项:
mysql-db=dbtest1a
:测试使用的目标数据库,这个库名要事先创建--oltp-tables-count=10
:产生表的数量--oltp-table-size=10000000
:每个表产生的记录行数--oltp-dist-type=uniform
:指定随机取样类型,可选值有 uniform(均匀分布), Gaussian(高斯分布), special(空间分布)。默认是special--oltp-read-only=off
:表示不止产生只读SQL,也就是使用oltp.lua时会采用读写混合模式。默认 off,如果设置为on,则不会产生update,delete,insert的sql。--oltp-test-mode=nontrx
:执行模式,这里是非事务式的。可选值有simple,complex,nontrx。默认是complex- simple:简单查询,SELECT c FROM sbtest WHERE id=N
- complex (advanced transactional):事务模式在开始和结束事务之前加上begin和commit, 一个事务里可以有多个语句,如点查询、范围查询、排序查询、更新、删除、插入等,并且为了不破坏测试表的数据,该模式下一条记录删除后会在同一个事务里添加一条相同的记录。
- nontrx (non-transactional):与simple相似,但是可以进行update/insert等操作,所以如果做连续的对比压测,你可能需要重新cleanup,prepare。
-
--oltp-skip-trx=[on|off]
:省略begin/commit语句。默认是off -
--rand-init=on
:是否随机初始化数据,如果不随机化那么初始好的数据每行内容除了主键不同外其他完全相同 --num-threads=12
: 并发线程数,可以理解为模拟的客户端并发连接数--report-interval=10
:表示每10s输出一次测试进度报告--max-requests=0
:压力测试产生请求的总数,如果以下面的max-time
来记,这个值设为0--max-time=120
:压力测试的持续时间,这里是2分钟。
注意,针对不同的选项取值就会有不同的子选项。比如oltp-dist-type=special
,就有比如oltp-dist-pct=1
、oltp-dist-res=50
两个子选项,代表有50%的查询落在1%的行(即热点数据)上,另外50%均匀的(sample uniformly)落在另外99%的记录行上。
再比如oltp-test-mode=nontrx
时, 就可以有oltp-nontrx-mode
,可选值有select(默认), update_key, update_nokey, insert, delete,代表非事务式模式下使用的测试sql类型。
以上代表的是一个只读的例子,可以把num-threads
依次递增(16,36,72,128,256,512),或者调整my.cnf参数,比较效果。另外需要注意的是,大部分mysql中间件对事务的处理,默认都是把sql发到主库执行,所以只读测试需要加上oltp-skip-trx=on
来跳过测试中的显式事务。
ps1: 只读测试也可以使用share/tests/db/select.lua
进行,但只是简单的point select。
ps2: 我在用sysbench压的时候,在mysql后端会话里有时看到大量的query cache lock,如果使用的是uniform取样,最好把查询缓存关掉。当然如果是做两组性能对比压测,因为都受这个因素影响,关心也不大。
2.2 混合读写
读写测试还是用oltp.lua,只需把--oltp-read-only
等于off
。
然而oltp-test-mode=nontrx
一直没有跟着我预期的去走,在mysql general log里面看到的sql记录与complex
模式相同。所以上面示例中的--oltp-test-mode=nontrx --oltp-nontrx-mode=select
可以删掉。
update:
sysbench作者 akopytov 对我这个疑问有了回复:https://github.com/akopytov/sysbench/issues/34 ,原来sysbench 0.5版本去掉了这个选项,因为作者正在准备1.0版本,所以也就没有更新0.5版本的doc。网上的博客漫天飞,就没有一个提出来的,也是没谁了。
分析一下oltp.lua脚本内容,可以清楚单个事务各操作的默认比例:select:update_key:update_non_key:delete:insert = 14:1:1:1:1,可通过oltp-point-selects
、oltp-simple-ranges
、oltp-sum-ranges
、oltp-order-ranges
、oltp-distinct-ranges
,oltp-index-updates
、oltp-non-index-updates
这些选项去调整读写权重。
同只读测试一样,在atlas,mycat这类中间件测试中如果不加oltp-skip-trx=on
,那么所有查询都会发往主库,但如果在有写入的情况下使用--oltp-skip-trx=on
跳过BEGIN和COMMIT,会出现问题:
ALERT: failed to execute MySQL query:
INSERT INTO sbtest4 (id, k, c, pad) VALUES (48228, 47329, '82773802508-44916890724-85859319254-67627358653-96425730419-64102446666-75789993135-91202056934-68463872307-28147315305', '13146850449-23153169696-47584324044-14749610547-34267941374')
:
ALERT: Error 1062 Duplicate entry ‘48228’ for key ‘PRIMARY’
FATAL: failed to execute function `event’: (null)
原因也很容易理解,每个线程将选择一个随机的表,不加事务的情况下高并发更新(插入)出现重复key的概率很大,但我们压测不在乎这些数据,所以需要跳过这个错误--mysql-ignore-errors=1062
,这个问题老外有出过打补丁的方案允许--mysql-ignore-duplicates=on
,但作者新加入的忽略错误码这个功能已经取代了它。mysql-ignore-errors
选项是0.5版本加入的,但目前没有文档标明,也是我在github上提的 issue 作者回复的。
这里不得不佩服老外的办事效率和责任心,提个疑惑能立马得到回复,反观国内,比如在atlas,mycat项目里提到问题到现在都没人搭理。。。
2.3 只更新
如果基准测试的时候,你只想比较两个项目的update(或insert)效率,那可以不使用oltp脚本,而直接改用update_index.lua
:
此时像oltp-read-only=off
许多参数都失效了。需要说明的是这里 (非)索引更新,不是where条件根据索引去查找更新,而是更新索引列上的值。
3. 结果解读
我们一般关注的用于绘图的指标主要有:
- response time avg: 平均响应时间。(后面的95%的大小可以通过
--percentile=98
的方式去更改) - transactions: 精确的说是这一项后面的TPS 。但如果使用了
-oltp-skip-trx=on
,这项事务数恒为0,需要用total number of events
去除以总时间,得到tps(其实还可以分为读tps和写tps) - read/write requests: 用它除以总时间,得到吞吐量QPS
- 当然还有一些系统层面的cpu,io,mem相关指标
sysbench还可以对文件系统IO测试,CPU性能测试,以及内存分配与传输速度测试,这里就不介绍了。
总结起来sysbench的缺点就是,模拟的表结构太简单,不像tpcc-mysql那样完整的事务系统。但对于性能压测对比还是很有用的,因为sysbench使用的环境参数限制是一样的。