数据库压力(瓶颈)评估!

背景:
    最近线上蛮重要的一个系统遇到了TCP链接瓶颈,运维由此陷入了焦头烂额的工做中,笔者在公司负责维护和运维MySQL,领导也是担忧数据库的瓶颈问题啊,笔者呢,也是好奇当前数据库的瓶颈到底如何,因此,便诞生了本文,谨以此文记录笔者对本地和测试环境进行压测的结果。(建议同行读者在读完本文以后,在作测试,由于上下相关)

工具选择:
    一、mysqlslap
    二、sysbench

mysqlslap:
mysql


    一、使用系统自动生成的SQL脚本测试:
    mysqlslap --concurrency=50,100,200 --iterations=3 --number-int-cols=5 --number-char-cols=30 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=mixed --engine=myisam,innodb --number-of-queries=5000 --debug-info -uroot -p -S /home/data/mysql3306/mysql.sock

    concurrency:客户端并发数量
    iterations:迭代次数(次数越多,取的平均值越准确)
    number-int-cols:表明示例表中integer类型有几个
    auto-generate-sql:使用系统自动生成的SQL脚本
    auto-generate-sql-load-type:测试的类型是读、写、混合
    number-of-queries:总共查询次数
    debug-info:输出CPU及内存等信息

    二、使用自定义SQL测试:
    /usr/local/mysql/bin/mysqlslap --concurrency=700 --iterations=3 --create-schema=edusoho_e --query='SELECT * FROM biz_targetlog WHERE target_type="trade.paid_notify" LIMIT 1' --number-of-queries=2000 -uroot -p -S /home/data/mysql3306/mysql.sock
    Enter password:
    Benchmark
    Average number of seconds to run all queries: 0.341 seconds
    Minimum number of seconds to run all queries: 0.187 seconds
    Maximum number of seconds to run all queries: 0.607 seconds
    Number of clients running queries: 700
    Average number of queries per client: 2

    create-schema:使用自定义的测试库
    query:自定义的语句

小结:
    mysqlslap是MySQL自带的压力测试工具,工具效果呢,只能说是仁者见仁,智者见智了!笔者在测试时,感受此工具的Benchmark和系统load并非成正比的,也就是说,相同的语句下(相同的迭代次数,相同的queries,相同的查询语句,并发数大的(700)的Benchmark比并发数低的(600)的Benchmark还低,load也是;另一方面,测试结果也是很不稳定,并发600的测试,第一次load>4,第二次相同的测试语句,load<1。
    不知道是什么缘由,笔者没想明白,秉着实践出真知的原则,感受此工具测试结果不是很稳定,写在这里仅供了解一下

sysbench:

简介:
    sysbench是一个模块化的、跨平台、多线程基准测试工具,主要用于评估测试各类不一样系统参数下的数据库负载状况,sysbench主要支持 MySQL,pgsql,oracle 这3种数据库

安装:
    yum install sysbench -y(笔者采用的是阿里云yum源安装,系统本地yum源好像没有)
    [root@slave ~]#sysbench --version
    sysbench 1.0.17

测试用的lua脚本文件:
    [root@slave ~]#cd /usr/share/sysbench/
    [root@slave sysbench]# ls
    ... 根据名字都能明白测试用途
    笔者线上主要以SELECT为主,因此将用oltp_read_only.lua脚原本作测试,读者根据本身的状况自行选择合适的脚本进行测试

Sysbench压测MySQL流程:
prepare(准备数据) -> run(运行测试) -> cleanup(清除测试数据)
sql


详细用法:
[root@slave sysbench]# sysbench --help

准备数据:
以edusoho_e为测试库,生成10张表,每表5w数据
[root@slave sysbench]# sysbench oltp_read_only.lua --db-driver=mysql --mysql-user=root --mysql-password='' --mysql-socket=/home/data/mysql3306/mysql.sock --mysql-db=edusoho_e --tables=10 --table-size=50000 prepare
sysbench 1.0.17 (using system LuaJIT 2.0.4)

Initializing worker threads...

Creating table 'sbtest8'...
Creating table 'sbtest2'...
Creating table 'sbtest5'...
Creating table 'sbtest3'...
Creating table 'sbtest4'...
Creating table 'sbtest7'...
Creating table 'sbtest1'...
Creating table 'sbtest10'...
Creating table 'sbtest6'...
Creating table 'sbtest9'...
Inserting 50000 records into 'sbtest10'
Inserting 50000 records into 'sbtest3'
Inserting 50000 records into 'sbtest9'
Inserting 50000 records into 'sbtest4'
Inserting 50000 records into 'sbtest6'
Inserting 50000 records into 'sbtest5'
Inserting 50000 records into 'sbtest2'
Inserting 50000 records into 'sbtest1'
Inserting 50000 records into 'sbtest7'
Inserting 50000 records into 'sbtest8'
Creating a secondary index on 'sbtest4'...
Creating a secondary index on 'sbtest7'...
Creating a secondary index on 'sbtest2'...
Creating a secondary index on 'sbtest5'...
Creating a secondary index on 'sbtest9'...
Creating a secondary index on 'sbtest3'...
Creating a secondary index on 'sbtest8'...
Creating a secondary index on 'sbtest10'...
Creating a secondary index on 'sbtest6'...
Creating a secondary index on 'sbtest1'...

运行测试:
一、并发100个thread,events为1w,间隔报告时间为10s,测试时间为10分钟
[root@slave sysbench]# sysbench oltp_read_only.lua --db-driver=mysql --mysql-user=root --mysql-password='' --mysql-socket=/home/data/mysql3306/mysql.sock --mysql-db=edusoho_e --tables=10 --table-size=50000 --threads=100 --events=10000 --report-interval=10 --time=600 run

二、和上面的大致相同,但不限制请求数量,测试时间为1分钟
[root@slave sysbench]# sysbench oltp_read_only.lua --db-driver=mysql --mysql-user=root --mysql-password='' --mysql-socket=/home/data/mysql3306/mysql.sock --mysql-db=edusoho_e --tables=10 --table-size=50000 --threads=100 --report-interval=10 --time=60 run  

[ 10s ] thds: 25 tps: 515.20 qps: 8280.37 (r/w/o: 7247.47/0.00/1032.90) lat (ms,95%): 69.29 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 25 tps: 526.22 qps: 8419.66 (r/w/o: 7367.21/0.00/1052.44) lat (ms,95%): 65.65 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 25 tps: 522.29 qps: 8354.94 (r/w/o: 7310.36/0.00/1044.58) lat (ms,95%): 66.84 err/s: 0.00 reconn/s: 0.00
[ 40s ] thds: 25 tps: 527.80 qps: 8446.26 (r/w/o: 7390.66/0.00/1055.59) lat (ms,95%): 63.32 err/s: 0.00 reconn/s: 0.00
[ 50s ] thds: 25 tps: 527.52 qps: 8439.37 (r/w/o: 7384.34/0.00/1055.03) lat (ms,95%): 65.65 err/s: 0.00 reconn/s: 0.00
[ 60s ] thds: 25 tps: 525.47 qps: 8407.17 (r/w/o: 7356.33/0.00/1050.83) lat (ms,95%): 64.47 err/s: 0.00 reconn/s: 0.00
SQL statistics:
    queries performed:
        read:                            440580     总select语句
        write:                           0              总insert、delete、update语句
        other:                           62940      commit、unlock table、mutex等
        total:                           503520
    transactions:                        31470  (524.30 per sec.)       TPS
    queries:                             503520 (8388.78 per sec.)      QPS
    ignored errors:                      0      (0.00 per sec.)            忽略的错误数
    reconnects:                          0      (0.00 per sec.)

General statistics:
    total time:                          60.0216s           实际压测时间
    total number of events:              31470         总的事件数,通常和transactions相同

Latency (ms):
         min:                                    1.77       最小响应时间
         avg:                                   47.66      平均响应时间
         max:                                  163.41     最大响应时间
         95th percentile:                       65.65   95%的语句的平均响应时间
         sum:                              1499944.29   总响应时间

Threads fairness:
    events (avg/stddev):           1258.8000/3.88
    execution time (avg/stddev):   59.9978/0.01

清除测试数据:(固然了,能够在数据库中删除)
[root@slave sysbench]# sysbench oltp_read_only.lua --db-driver=mysql --mysql-user=root --mysql-password='' --mysql-socket=/home/data/mysql3306/mysql.sock --mysql-db=edusoho_e --tables=10 cleanup

负载监控:
在运行sysbench测试时,压力必定要慢慢增长(即,慢慢增长  --threads=N ,--events=N 的值),以此来肯定负载瓶颈为多少,毫不能成倍数(100、200、400、800) 的增长压力。
数据库

一方面,压力瓶颈不易肯定,好比:在400的时候,系统load还在承受范围以内,一旦变为800的时候,系统load忽然急剧变为原来的十数倍,甚至几十倍,这个时候,你很难肯定瓶颈究竟是在400-800之间的哪里,由于系统load在达到瓶颈之间,压力是一直缓慢增加的,一旦突破了某个瓶颈,将会成指数增长多线程

另外一方面,成倍数增长测试压力,一旦突破系统load负载,忽然间猛增的压力,可能会将系统crash。并发


因此,在使用sysbench测试数据库瓶颈的时候,一方面须要缓慢增长测试压力,另外一方面,须要同时监控系统load,当超出你设定的系统load时,立刻终止运行。这样慢慢的,在保证系统load在正常范围的前提下,测试出最大的数据库瓶颈。

题外:
sysbench还能够测试磁盘I/O、CPU、memory等,具体的测试用法,请自行百度吧。固然了,对于本文的不当之处,还请各位读者在下方评论区留言指正,不胜感激!
oracle