sysbench对mysql压力测试的详细教程

前言

在对网站整体性能进行benchmark时,可以使用多种工具,比如大名鼎鼎的ab(Apache bench),http_load等工具。这里我们不关注他们的使用,如果你想了解,可以自行在网上找到答案。

重点来说MySQL的基准测试如何进行,也有很多种工具来供我们选择,比如mysqlslap、sysbench、Super Smack等,其中mysqlslap的使用MySQL官网给出了介绍,Super Smack是服务器压力测试强有力的工具,那么sysbench便是我们进行MySQL基准测试的很漂亮的工具了。

sysbench

sysbench是一款开源的多线程性能测试工具,可以执行CPU/内存/线程/IO/数据库等方面的性能测试。数据库目前支持MySQL/Oracle/PostgreSQL;

它主要包括以下几种方式的测试:

1、cpu性能

2、磁盘io性能

3、调度程序性能

4、内存分配及传输速度

5、POSIX线程性能

6、数据库性能(OLTP基准测试)

sysbench的数据库OLTP测试支持MySQL、PostgreSQL、Oracle,目前主要用于Linux操作系统,开源社区已经将sysbench移植到了Windows,并支持SQL Server的基准测试。

废话不多说,开始。

一、sysbench安装

mysql版本: mysql-community-server-5.6.29

OS: CentOS 6.7 X86_64

sysbench 0.5相比0.4版本有一些变化,包括oltp测试结合了lua脚本,还多了一些隐藏选项,本文会涉及得到一部分。

// 先安装编译依赖环境
$ sudo yum install gcc gcc-c++ automake make libtool mysql-community-devel
$ cd /tmp && git clone https://github.com/akopytov/sysbench.git
$ cd /tmp/sysbench && ./autogen.sh
$ ./configure --prefix=/usr/local/sysbench-0.5
$ ./make && sudo make install
// 0.5版本需要oltp.lua测试脚本
// 如果是rpm包方式安装的,在 /usr/share/doc/sysbench/tests/db/ 下可找到
$ cd /usr/local/sysbench && sudo mkdir -p share/tests/db
$ cp /tmp/sysbench/sysbench/tests/db/*.lua share/tests/db/
$ ./bin/sysbench --version
sysbench 0.5

如果需要测试PostgreSQL、Oracle,则在configure时需要加上 –with-oracle 或者 –with-pgsql 参数

二、使用sysbench对mysql压测

2.1 只读示例

./bin/sysbench --test=./share/tests/db/oltp.lua \
--mysql-host=10.0.201.36 --mysql-port=8066 --mysql-user=ecuser --mysql-password=ecuser \
--mysql-db=dbtest1a --oltp-tables-count=10 --oltp-table-size=500000 \
--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来准备好表和数据,run执行真正的压测,cleanup用来清除数据和表。实际prepare的表结构:

mysql> desc dbtest1a.sbtest1;
+-------+------------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra     |
+-------+------------------+------+-----+---------+----------------+
| id  | int(10) unsigned | NO  | PRI | NULL  | auto_increment |
| k   | int(10) unsigned | NO  | MUL | 0    |        |
| c   | char(120)    | NO  |   |     |        |
| pad  | char(60)     | NO  |   |     |        |
+-------+------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

上面的测试命令代表的是:对mysql进行oltp基准测试,表数量10,每表行数约50w(几乎delete多少就会insert的多少),并且是非事务的只读测试,持续60s,并发线程数12。

需要说明的选项:

mysql-db=dbtest1a:测试使用的目标数据库,这个库名要事先创建

--oltp-tables-count=10:产生表的数量

--oltp-table-size=500000:每个表产生的记录行数

--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。

./bin/sysbench --test=./share/tests/db/oltp.lua --mysql-host=10.0.201.36 --mysql-port=8066 --mysql-user=ecuser --mysql-password=ecuser --mysql-db=dbtest1a --oltp-tables-count=10 --oltp-table-size=500000 --report-interval=10 --rand-init=on --max-requests=0 --oltp-test-mode=nontrx --oltp-nontrx-mode=select --oltp-read-only=off --max-time=120 --num-threads=128 prepare
./bin/sysbench --test=./share/tests/db/oltp.lua --mysql-host=10.0.201.36 --mysql-port=8066 --mysql-user=ecuser --mysql-password=ecuser --mysql-db=dbtest1a --oltp-tables-count=10 --oltp-table-size=500000 --report-interval=10 --rand-init=on --max-requests=0 --oltp-test-mode=nontrx --oltp-nontrx-mode=select --oltp-read-only=off --max-time=120 --num-threads=128 run
./bin/sysbench --test=./share/tests/db/oltp.lua --mysql-host=10.0.201.36 --mysql-port=8066 --mysql-user=ecuser --mysql-password=ecuser --mysql-db=dbtest1a --oltp-tables-count=10 --oltp-table-size=500000 --report-interval=10 --rand-init=on --max-requests=0 --oltp-test-mode=nontrx --oltp-nontrx-mode=select --oltp-read-only=off --max-time=120 --num-threads=128 cleanup

然而oltp-test-mode=nontrx一直没有跟着我预期的去走,在mysql general log里面看到的sql记录与complex模式相同。所以上面示例中的--oltp-test-mode=nontrx --oltp-nontrx-mode=select可以删掉。

update:

原来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-selectsoltp-simple-rangesoltp-sum-rangesoltp-order-rangesoltp-distinct-rangesoltp-index-updatesoltp-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版本加入的,但目前没有文档标明。

这里不得不佩服老外的办事效率和责任心,提个疑惑能立马得到回复,反观国内,比如在atlas,mycat项目里提到问题到现在都没人搭理。。。

2.3 只更新

如果基准测试的时候,你只想比较两个项目的update(或insert)效率,那可以不使用oltp脚本,而直接改用update_index.lua

./bin/sysbench --test=./share/tests/db/update_index.lua \
--mysql-host=10.0.201.36 --mysql-port=8066 --mysql-user=ecuser --mysql-password=ecuser \
--mysql-db=dbtest1a --oltp-tables-count=10 --oltp-table-size=500000 \
--report-interval=10 --rand-init=on --max-requests=0 \
--oltp-read-only=off --max-time=120 --num-threads=128 \
[ prepare | run | cleanup ]

此时像oltp-read-only=off许多参数都失效了。需要说明的是这里 (非)索引更新,不是where条件根据索引去查找更新,而是更新索引列上的值。

三. 结果解读

sysbench 0.5: multi-threaded system evaluation benchmark
Running the test with following options:
Number of threads: 128
Report intermediate results every 20 second(s)
Initializing random number generator from timer.
Random number generator seed is 0 and will be ignored
Initializing worker threads...
Threads started!
[ 20s] threads: 128, tps: 2354.54, reads: 33035.89, writes: 9423.39, response time: 66.80ms (95%), errors: 0.00, reconnects: 0.00
[ 40s] threads: 128, tps: 2377.75, reads: 33274.26, writes: 9507.55, response time: 66.88ms (95%), errors: 0.00, reconnects: 0.00
[ 60s] threads: 128, tps: 2401.35, reads: 33615.30, writes: 9607.40, response time: 66.40ms (95%), errors: 0.00, reconnects: 0.00
[ 80s] threads: 128, tps: 2381.20, reads: 33331.50, writes: 9522.55, response time: 67.30ms (95%), errors: 0.00, reconnects: 0.00
[ 100s] threads: 128, tps: 2388.85, reads: 33446.10, writes: 9556.35, response time: 67.00ms (95%), errors: 0.00, reconnects: 0.00
[ 120s] threads: 128, tps: 2386.40, reads: 33421.35, writes: 9545.35, response time: 66.94ms (95%), errors: 0.00, reconnects: 0.00
OLTP test statistics:
  queries performed:
    read:              4003048 //总select数量
    write:              1143728 //总update、insert、delete语句数量
    other:              571864  //commit、unlock tables以及其他mutex的数量
    total:              5718640
  transactions:            285932 (2382.10 per sec.) //通常需要关注的数字(TPS)
  read/write requests:         5146776 (42877.85 per sec.)
  other operations:          571864 (4764.21 per sec.)
  ignored errors:           0   (0.00 per sec.) //忽略的错误数
  reconnects:             0   (0.00 per sec.)
General statistics:
  total time:             120.0334s //即max-time指定的压测实际
  total number of events:       285932  //总的事件数,一般与transactions相同
  total time taken by event execution: 15362.6623s
  response time:
     min:                 17.60ms
     avg:                 53.73ms //95%的语句的平均响应时间
     max:                252.90ms
     approx. 95 percentile:       66.88ms
Threads fairness:
  events (avg/stddev):      2233.8438/9.04
  execution time (avg/stddev):  120.0208/0.01

我们一般关注的用于绘图的指标主要有:

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使用的环境参数限制是一样的。以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

(0)

相关推荐

  • mysql中key 、primary key 、unique key 与index区别

    mysql中索引是非常重要的知识点,相比其他的知识点,索引更难掌握,并且mysql中的索引种类也有很多,比如primary key .unique key 与index等等,本文章向大家介绍mysql中key .primary key .unique key 与index区别.  一.key与primary key区别 CREATE TABLE wh_logrecord ( logrecord_id int(11) NOT NULL auto_increment, user_name varch

  • mysql alter table命令修改表结构实例详解

    mysql alter table语句可以修改表的基本结构,例如添加字段.删除字段.添加主键.添加索引.修改字段数据类型.对表重命名等等操作,本文章通过两个简单的实例向大家介绍mysql alter table的使用方法.  实例一:使用ALTER TABLE命令向表中添加字段.修改字段类型以及设置主键. 首先创建一个表,SQL语句如下: mysql> CREATE TABLE myTable( -> ID SMALLINT -> ); 使用desc命令查看表结构: mysql>

  • JDBC 连接MySQL实例详解

    JDBC连接MySQL JDBC连接MySQL 加载及注册JDBC驱动程序 Class.forName("com.mysql.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver").newInstance(); JDBC URL 定义驱动程序与数据源之间的连接 标准语法: <protocol(主要通讯协议)>:<subprotocol(次要通讯协议,即驱动程序名称)>:<data so

  • mysql alter table命令修改表结构实例

    mysql实例之使用alter table命令修改表结构 mysql alter table语句可以修改表的基本结构,例如添加字段.删除字段.添加主键.添加索引.修改字段数据类型.对表重命名等等操作,本文章通过两个简单的实例向大家介绍mysql alter table的使用方法  实例一:使用ALTER TABLE命令向表中添加字段.修改字段类型以及设置主键. 首先创建一个表,SQL语句如下: mysql> CREATE TABLE myTable( -> ID SMALLINT ->

  • PHP读MYSQL中文乱码的快速解决方法

    打算切换某个网站的主机,没想到遇到Php和Mysql中文乱码的问题. 以前的国外主机用的Mysql是4.x系列的,感觉还比较好,都无论GBK和UTF-8都没有乱码,没想到新的主机的Mysql是5.0版本的,导入数据后,用Php读出来全是问号,乱码一片,记得我以前也曾经有过一次切换出现乱码的经验,原因肯定是Mysql版本之间的差异问题. 只好查资料,发现了一个解决方法,就是在mysql_connect后面加一句SET NAMES UTF8,即可使得UTF8的数据库消除乱码,对于GBK的数据库则使用

  • Mysql中Identity 详细介绍

    假如表中包含一列为auto_increment, 如果是Myisam类型的引擎,那么在删除了最新一笔数据,无论是否重启Mysql,下一次插入之后仍然会使用上次删除的最大ID+1. mysql> create table test_myisam (id int not null auto_increment primary key, name char(5)) engine=myisam; Query OK, 0 rows affected (0.04 sec) mysql> insert in

  • MySQL中的alter table命令的基本使用方法及提速优化

    一.基本用法 1. 增加列 alter table tbl_name add col_name type 例如,  给pet的表增加一列 weight, mysql>alter table pet add weight int; 2. 删除列 alter table tbl_name drop col_name 例如, 删除pet表中的weight这一列 mysql>alter table pet drop weight; 3. 改变列 分为改变列的属性和改变列的名字 改变列的属性--方法1:

  • MySQL隐式类型的转换陷阱和规则

    前言 相信大家都知道隐式类型转换有无法命中索引的风险,在高并发.大数据量的情况下,命不中索引带来的后果非常严重.将数据库拖死,继而整个系统崩溃,对于大规模系统损失惨重.所以下面通过本文来好好学习下MySQL隐式类型的转换陷阱和规则. 1. 隐式类型转换实例 今天生产库上突然出现MySQL线程数告警,IOPS很高,实例会话里面出现许多类似下面的sql:(修改了相关字段和值) SELECT f_col3_id,f_qq1_id FROM d_dbname.t_tb1 WHERE f_col1_id=

  • Mysql5.6启动内存占用过高解决方案

    vps的内存为512M,安装好nginx,php等启动起来,mysql死活启动不起来看了日志只看到对应pid被结束了,后跟踪看发现是内存不足被killed; 调整my.cnf 参数,重新配置(系统默认配置太高直接占用400M内存,小玩家玩不起呢)即可 performance_schema_max_table_instances=200 table_definition_cache=200 table_open_cache=128 下面附一个相关的my.cnf配置文件的说明 [client] po

  • mysql 复制表结构和数据实例代码

    在mysql数据库开发中,我们有时候需要复制或拷贝一张表结构和数据到例外一张表,这个时候我们可以使用create ... select ... from语句来实现,本文章向大家介绍mysql复制表结构和数据一个简单实例, 比如现在有一张表,我们要将该表复制一份,以备以后使用,那么如何使用mysql语句来实现呢?其实我们可以直接使用create ... select ... from语句来实现,具体实现方法请看下面实例. 我们先来创建一张Topic表,创建Topic表的SQL语句如下: mysql

  • MySQL学习笔记5:修改表(alter table)

    我们在创建表的过程中难免会考虑不周,因此后期会修改表修改表需要用到alter table语句 修改表名 复制代码 代码如下: mysql> alter table student rename person; Query OK, 0 rows affected (0.03 sec) 这里的student是原名,person是修改过后的名字 用rename来重命名,也可以使用rename to 修改字段的数据类型 复制代码 代码如下: mysql> alter table person modi

随机推荐