MySQL数据库压力测试报告
类别 | 名称 |
OS | 虚拟机 CentOS release 6.5 (Final) |
DISK | 765GB |
MySQLl | v5.6.27 |
Sysbench | v0.5 |
测试innodb buffer pool设置为24G和44G这两种情形下的性能差距;
测试操作系统cpu个数在8和12这两种情形下的性能差距;
测试表加索引和不加索引时数据库性能差距;
测试硬盘的随机读、随机写、随机读写、顺序写、顺序读、顺序读写等所有模式的iops、吞吐量。
利用现在生产MySQL备库搭建压力测试环境,在测试时,停掉备库的slave复制:
说明:本次测试,只测试在不同情况下的select查询,用来测试的sql如下:
SELECT pad FROM test.sbtest1 where k = ‘xxxxxx;
表结构为:
数据量为100万行:
QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
cpu负载:通过top命令的load average获取1分钟内的平均值,它代表了任务队列的平均长度。
执行下面的命令准备测试数据:
sysbench --test=/usr/local/src/sysbench-0.5/sysbench/tests/db/oltp.lua /
--mysql-host=localhost /
--mysql-user=root /
--mysql-password=xxxxx /
--mysql-db=test /
--oltp-tables-count=1 /
--oltp-table-size=1000000 /
--num-threads=50 /
--max-requests=1000000 /
--report-interval=1 /
prepare
上述命令会在MySQL的test数据库里面创建sbtest1表,数据量为100w行。
参数说明:
--mysql-host=locahost #数据库host
--mysql-port=3306 #数据库端口
--mysql-user=your_username #数据库用户名
--mysql-password=your_password #数据库密码
--mysql-db=your_db_for_test #数据库名
--oltp-tables-count=1 #模拟的表的个数,规格越高该值越大
--oltp-table-size=1000000 #模拟的每张表的行数,规格越高该值越大
--num-threads=50 #模拟的并发数量,规格越高该值越大
--max-requests=100000000 #最大请求次数
--report-interval=1 #每1秒打印一次当前的QPS等值
--test=/usr/local/src/sysbench-0.5/sysbench/tests/db/oltp.lua#选用的测试脚本(lua),此脚本可以从sysbench-0.5源代码文件目录下找 [prepare | run | cleanup] #prepare准备数据,run执行测试,cleanup清理数据
sysbench --test=/usr/local/src/sysbench-0.5/sysbench/tests/db/select.lua /
--mysql-host=localhost /
--mysql-user=root /
--mysql-password=xxxx /
--mysql-db=test /
--oltp-tables-count=1 /
--oltp-table-size=1000000 /
--num-threads=16 /
--max-requests=1000000 /
--report-interval=1 /
--max-time=60 /
run
说明:--num-threads=16 #模拟数据库线程并发数量,规格越高该值越大
--max-time=60#最大测试时间(与--max-requests只要有一个超过,则退出)。
利用sysbench测试了并发线程个数不同的情况下,分别执行最大请求次数为100w的 select操作,通过修改--num-threads可以获得不同并发线程数。
测试有索引和无索引这两种情况下的 QPS(QPS越大,系统性能越好), 每条sql平均执行时间(每条sql执行时间越小,系统性能越好), cpu负载,每组数据重复测试三次后取平均值,具体数据对比如下表所示:
buffer_pool:24G | 线程数 | 请求数 | 数据量 | cpu负载 | qps(r/s) | min(ms) | avg(ms) | max(ms) | 95% |
有索引 | 16 | 701116 | 100万行 | 3.21 | 11680 | 0.09 | 1.37 | 1274.83 | 0.73 |
没有索引 | 16 | 720 | 100万行 | 11 | 11 | 278 | 1345 | 5997 | 2373 |
有索引 | 32 | 707720 | 100万行 | 4.46 | 11737 | 0.08 | 2.71 | 1995 | 1.38 |
没有索引 | 32 | 688 | 100万行 | 21 | 11 | 686 | 2829 | 12666 | 5700 |
有索引 | 64 | 746723 | 100万行 | 18 | 12416 | 0.09 | 5.15 | 2253 | 9.52 |
没有索引 | 64 | 726 | 100万行 | 38 | 11 | 1587 | 5430 | 19856 | 11000 |
有索引 | 128 | 910519 | 100万行 | 36 | 15145 | 0.09 | 8.43 | 3147 | 20.17 |
没有索引 | 128 | 804 | 100万行 | 43 | 12 | 1525 | 10379 | 68659 | 58056 |
有索引 | 256 | 896962 | 100万行 | 80 | 14932 | 0.09 | 17.14 | 4945 | 38.97 |
没有索引 | 256 | 917 | 100万行 | 52 | 11 | 1673 | 20022 | 81671 | 77778 |
有索引 | 512 | 850414 | 100万行 | 194 | 14161 | 0.1 | 36.15 | 5750 | 321 |
没有索引 | 512 | 1133 | 100万行 | 59 | 11 | 1252 | 38431 | 107995 | 103269 |
有索引 | 1024 | 818863 | 100万行 | 252 | 13629 | 0.09 | 75 | 17780 | 401 |
没有索引 | 1024 | 1667 | 100万行 | 63 | 11 | 1535 | 66188 | 153542 | 147680 |
有索引 | 2048 | 799571 | 100万行 | 652 | 13282 | 0.1 | 153 | 9599 | 563 |
没有索引 | 2048 | 2595 | 100万行 | 72 | 10 | 1325 | 132090 | 265936 | 255631 |
上表对应的QPS折线图如下所示:
从QPS折线图可以看出,当sysbench的并发测试线程数小于128时,有索引的QPS在1万2左右。 这主要是因为当sysbench并发线程少时,数据库性能没有得到充分的发挥。
当sysbench的并发测试线程到128时,此时MySQL的性能就得到了充分的发挥,有索引的QPS达到了1万5左右。如果继续增加并发测试线程数,有索引的QPS稍有下降,但是还在1万3左右,还是不错的。
这时,我们再观察无索引的情况,无论并发测试线程数是多少,无索引的QPS都是11,也就是,无索引时数据库每秒只能处理11个select查询,这对高并发的业务简直不可接受。这说明了索引对数据库的性能影响是多么巨大。
上表对应的每条SQL执行时间折线图如下所示:
从每条SQL执行时间的折线图来看,无索引的sql执行时间随着并发测试线程数的增加而增加。也就是说,本来单条sql执行时间是1s,但是线程数越多,其执行时间越长,如上图,当线程数128时,其执行时间已经由1s升到10.379s了。
这时,我们再观察有索引的每条sql执行时间,不论线程数是多少,其执行时间都不会超过1s,可见有索引和无索引的性能差距太大了。
上表对应的cpu负载折线图如下所示:
从cpu折线图来看,在无索引情况下,当线程数128时,cpu负载为43,这和我们生产系统发生故障情况是吻合的,即当我们数据库cpu负载在40~50时,确实有100左右的并发线程在数据库里面执行。
再来看有索引情况下cpu的负载情况,可以看到,当并发线程数128以上时,有索引的cpu负载骤然升高,甚至高于无索引的。关于这个现象,出乎我的预料,甚至很不理解。
后来,我仔细分析了linux 里面的cpu负载的含义,CPU负载显示的是一段时间内正在使用和等待使用CPU的平均任务数。不过,我也不好解释上述现象,只能列在这,供人参考。
小知识:
CPU负载怎么理解?是不是CPU利用率?
这里要区别CPU负载和CPU利用率,它们是不同的两个概念,但它们的信息可以在同一个top命令中进行显示。CPU利用率显示的是程序在运行期间实时占用的CPU百分比,而CPU负载显示的是一段时间内正在使用和等待使用CPU的平均任务数。CPU利用率高,并不意味着负载就一定大。网上有篇文章举了一个有趣比喻,拿打电话来说明两者的区别,我按自己的理解阐述一下。
某公用电话亭,有一个人在打电话,四个人在等待,每人限定使用电话一分钟,若有人一分钟之内没有打完电话,只能挂掉电话去排队,等待下一轮。电话在这里就相当于CPU,而正在或等待打电话的人就相当于任务数。
在电话亭使用过程中,肯定会有人打完电话走掉,有人没有打完电话而选择重新排队,更会有新增的人在这儿排队,这个人数的变化就相当于任务数的增减。为了统计平均负载情况,我们5秒钟统计一次人数,并在第1、5、15分钟的时候对统计情况取平均值,从而形成第1、5、15分钟的平均负载。
有的人拿起电话就打,一直打完1分钟,而有的人可能前三十秒在找电话号码,或者在犹豫要不要打,后三十秒才真正在打电话。如果把电话看作CPU,人数看作任务,我们就说前一个人(任务)的CPU利用率高,后一个人(任务)的CPU利用率低。
当然, CPU并不会在前三十秒工作,后三十秒歇着,只是说,有的程序涉及到大量的计算,所以CPU利用率就高,而有的程序牵涉到计算的部分很少,CPU利用率自然就低。但无论CPU的利用率是高是低,跟后面有多少任务在排队没有必然关系。
下面我们把cpu由8加到12,其他配置都不变,再进行压力测试,看有什么变化。
buffer_pool:24G | 线程数 | 请求数 | 数据量 | cpu负载 | qps(r/s) | min(ms) | avg(ms) | max(ms) | 95% |
有索引 | 16 | 716917 | 100万行 | 3.4 | 11948 | 0.09 | 1.34 | 944 | 1.02 |
没有索引 | 16 | 873 | 100万行 | 10.34 | 14 | 282 | 1104 | 3224 | 2474 |
有索引 | 32 | 708405 | 100万行 | 7.48 | 11787 | 0.09 | 2.71 | 1159 | 1.71 |
没有索引 | 32 | 888 | 100万行 | 20 | 14 | 292 | 2193 | 7901 | 4749 |
有索引 | 64 | 719369 | 100万行 | 18.84 | 11920 | 0.08 | 5.37 | 1156 | 15 |
没有索引 | 64 | 898 | 100万行 | 40 | 14 | 638 | 4416 | 15063 | 9432 |
有索引 | 128 | 696889 | 100万行 | 10 | 11614 | 0.09 | 11 | 1157 | 29.32 |
没有索引 | 128 | 943 | 100万行 | 42 | 14 | 817 | 8686 | 67268 | 49821 |
有索引 | 256 | 681509 | 100万行 | 59 | 11588 | 0.1 | 22.53 | 2495 | 55 |
没有索引 | 256 | 1051 | 100万行 | 47 | 13 | 730 | 16978 | 78149 | 75079 |
有索引 | 512 | 704611 | 100万行 | 78 | 11730 | 0.1 | 43.63 | 2800 | 413 |
没有索引 | 512 | 1267 | 100万行 | 54 | 13 | 822 | 31718 | 96230 | 92691 |
有索引 | 1024 | 593684 | 100万行 | 204 | 9868 | 0.1 | 103 | 6522 | 545 |
没有索引 | 1024 | 1764 | 100万行 | 59 | 12 | 662 | 58212 | 139380 | 133509 |
有索引 | 2048 | 571730 | 100万行 | 196 | 8898 | 0.09 | 225 | 8748 | 948 |
没有索引 | 2048 | 2769 | 100万行 | 116 | 12 | 606 | 103518 | 214829 | 205576 |
上表对应的QPS折线图如下所示:
从上图可以看到,当线程数为512时,有索引的qps开始骤降;但无索引的qps不论线程数是多少,都是14。
上表对应的每条SQL执行时间折线图如下所示:
从上图可以看到,随着线程数的增加,无索引的每条sql执行时间在增加;而有索引的每条sql平均执行时间不到1s。
上表对应的cpu负载折线图如下所示:
从上图可以看到,随着线程数的增加,cpu负载也在增加,但是当线程数为256时,有索引的cpu负载要比无索引的高,这个暂时没法解释。
下面我们把innodb buffer pool由24G升至44G,其他配置都不变,再进行压力测试,看有什么变化。
buffer_pool:44G | 线程数 | 请求数 | 数据量 | cpu负载 | qps(r/s) | min(ms) | avg(ms) | max(ms) | 95% |
有索引 | 16 | 709587 | 100万行 | 3.56 | 11826 | 0.09 | 1.35 | 544 | 1.06 |
没有索引 | 16 | 894 | 100万行 | 11 | 14 | 279 | 1087 | 3211 | 2471 |
有索引 | 32 | 693606 | 100万行 | 3.14 | 11503 | 0.08 | 2.77 | 1121 | 1.79 |
没有索引 | 32 | 907 | 100万行 | 20 | 14 | 549 | 2146 | 9473 | 4504 |
有索引 | 64 | 681148 | 100万行 | 10.21 | 11352 | 0.08 | 5.64 | 1880 | 16 |
没有索引 | 64 | 813 | 100万行 | 42 | 14 | 722 | 4828 | 15398 | 9626 |
有索引 | 128 | 654430 | 100万行 | 24 | 10906 | 0.09 | 11 | 1641 | 39 |
没有索引 | 128 | 934 | 100万行 | 40 | 14 | 774 | 12272 | 114780 | 61804 |
有索引 | 256 | 652889 | 100万行 | 67 | 10828 | 0.09 | 23 | 2561 | 90 |
没有索引 | 256 | 1091 | 100万行 | 47 | 14 | 770 | 16203 | 76963 | 72930 |
有索引 | 512 | 651804 | 100万行 | 143 | 10800 | 0.09 | 47 | 2816 | 448 |
没有索引 | 512 | 1325 | 100万行 | 88 | 14 | 506 | 30334 | 95839 | 90471 |
有索引 | 1024 | 466049 | 100万行 | 220 | 7109 | 0.1 | 140 | 18282 | 573 |
没有索引 | 1024 | 1818 | 100万行 | 68 | 14 | 730 | 54924 | 132208 | 126847 |
有索引 | 2048 | 578978 | 100万行 | 247 | 9574 | 0.09 | 212 | 5251 | 771 |
没有索引 | 2048 | 2807 | 100万行 | 105 | 14 | 616 | 100284 | 209988 | 200952 |
上表对应的QPS折线图如下所示:
从上图可以看到,当线程数为512时,有索引的qps开始骤降;但无索引的qps不论线程数是多少,都是14。
上表对应的每条SQL执行时间折线图如下所示:
从上图可以看到,随着线程数的增加,无索引的每条sql平均执行时间在增加;而有索引的每条sql平均执行时间不到1s。
上表对应的cpu负载折线图如下所示:
从上图可以看到,随着线程数的增加,cpu负载也在增加,但是当线程数为256时,有索引的cpu负载要比无索引的高,这种现象暂时没法解释。
io测试脚本:
[root@Mysql03 test]# cat iotest.sh
#!/bin/sh
set -u
set -x
set -e
for size in 2G ;do
for mode in seqrd seqrw rndrd rndwr rndrw;do
for blksize in 16384;do
sysbench --test=fileio --file-num=64 --file-total-size=$size prepare
for threads in 1 16 32 64 128 512 1024 2048;do
echo "====== testing $blksize in $threads threads"
echo PARAMS $size $mode $threads $blksize > sysbench-size-$size-mode-$mode-threads-$threads-blksz-$blksize
for i in 1 ;do
sysbench --test=fileio --file-total-size=$size --file-test-mode=$mode --max-time=180 --max-requests=100000000/
--num-threads=$threads --init-rng=on --file-num=64 --file-extra-flags=direct --file-fsync-freq=0/
--file-block-size=$blksize run | tee -a sysbench-size-$size-mode-$mode-threads-$threads-blksz-$blksize 2>&1
done
done
sysbench --test=fileio --file-total-size=$size cleanup
done
done
done
得到如下数据:
线程数 | 模式 | 数据块大小 | 吞吐量(Mb/s) | IOPS |
1 | 顺序读 | 16k | 59.639 | 3816.87 |
16 | 顺序读 | 16k | 139.81 | 8948 |
32 | 顺序读 | 16k | 158.85 | 10166.69 |
64 | 顺序读 | 16k | 147 | 9451 |
128 | 顺序读 | 16k | 149 | 9542 |
512 | 顺序读 | 16k | 153 | 9853 |
1024 | 顺序读 | 16k | 151 | 9712.16 |
2048 | 顺序读 | 16k | 151 | 9666 |
1 | 随机读 | 16k | 5 | 337 |
16 | 随机读 | 16k | 41 | 2668 |
32 | 随机读 | 16k | 61 | 3912.03 |
64 | 随机读 | 16k | 61 | 3939.21 |
128 | 随机读 | 16k | 61 | 3939 |
因为测试磁盘io会影响生产系统,所以只测试了上面几组数据,没有对顺序读、顺序写、顺序读写、随机读、随机写、随机读写等全面测试,即使测试可能意义也不大。
因为磁盘是机械硬盘,按理应该是220,上面出现1万的情况,因为硬盘有闪存。
有索引的qps在1万2左右,没索引的qps只有14,两者相差1000倍;
有索引的sql执行时间不论线程数是多少都不到一秒,而无索引的sql随着线程数的增加,其执行时间也会增加,最高到132s,相差倍数可是千倍万倍;
数据库的线程数达到128时,会使数据库性能明显下降;当增加cpu和内存时,也不能很好的解决这个问题,这可能是my.cnf和linux 内核参数配置的不合适导致,后期仔细研究这些参数,使数据库性能上一个新的台阶;
磁盘IO能力固定,只能从数据库和操作系统参数着手。
完