MySQL原理简介—3.生产环境的部署压测
大纲
1.普通的Java应用系统能抗多少请求
2.高并发下的数据库用什么样的机器
3.部署完数据库之后需要先进行压测
4.QPS和TPS之间的区别
5.IO相关的压测性能指标
6.压测时需要关注的其他性能指标
7.一台机器每秒可以抗多少并发的影响因素
8.sysbench是非常好用的数据库压测工具
9.压测中除了QPS和TPS外还要观察机器性能
10.压测时如何观察机器的CPU负载情况
11.压测时如何观察机器的内存负载情况
12.压测时如何观察机器的磁盘IO情况
13.压测时观察网卡的流量情况
14.使用sysbench压测数据库总结
1.普通的Java应用系统能抗多少QPS
部署Java应用系统时,常选用的机器配置是2核4G和4核8G;部署数据库时,常选用的机器配置最低是8核16G,正常16核32G。
一般Java应用系统部署在4核8G的机器上时,每秒能抗500左右的请求。一台机器每秒能抗多少请求,往往跟每个请求处理耗费多长时间有关。假设每个请求1s可以处理完,则一台机器每秒可以处理100个请求;假设每个请求100ms可以处理完,则一台机器每秒可以处理几百个请求。
4核8G的机器部署普通的Java系统,每秒能抗下几百的请求。从每秒一两百请求到每秒七八百请求都有可能,关键还是看每个请求处理要耗费多长时间。
2.高并发下的数据库用什么样的机器
Java应用系统处理请求的耗费时间主要用在与数据库进行交互。若Java系统仅仅只在内部运行一些普通的业务逻辑,性能是很高的。当Java系统和数据库产生交互时,耗时最多的便是:将网络请求发送到数据库 + 等待数据库执行SQL语句返回结果。
常说Java系统压力很大负载很高,主要是指依赖的数据库压力很大。当数据库需要执行大量增删改查的SQL语句时,需要对内存和磁盘文件进行大量IO操作,所以数据库的负载会很高。
一般8核16G的机器部署的MySQL数据库,每秒能抗一两千请求。对于16核32G的机器部署的MySQL数据库,每秒能抗两到四千请求。此外,数据库所在机器最好采用SSD固态硬盘而不是普通机械硬盘。
3.部署完数据库之后需要先进行压测
部署完数据库后,需要先对该数据库进行基准压测。即先基于一些工具模拟一个系统每秒发出1000个请求到数据库上去,观察它的CPU负载、磁盘IO负载、网络IO负载、内存负载。然后看数据库能否处理掉这1000个请求,还是只能处理500个请求。
数据库的压测和Java系统的压测是两回事。因为对于Java系统的压测,首先得知道数据库最大能抗多大压力。然后再根据数据库的最大压力,去看Java系统能抗多大压力。比如可能Java系统每秒抗2000请求,但数据库每秒只能抗500请求。
4.QPS和TPS之间的区别
QPS,指的是每秒可以处理多少个请求,可以理解为一个请求就是一条SQL语句。所以QPS指数据库每秒可以处理多少个SQL语句。
TPS,指的是每秒可以处理的事务量,所以TPS指数据库每秒会处理多少次事务提交或者回滚。一个事务会包含多个SQL语句,这些SQL语句要么一起成功,要么一起回滚。
5.IO相关的压测性能指标
(1)IOPS
(2)吞吐量
(3)latency
压测时需要关注如下的IO相关的性能指标:
(1)IOPS
IOPS指机器的随机IO并发处理能力。比如机器可以达200的IOPS,表示每秒可以执行200个随机IO读写请求。
IOPS这个指标很关键。因为InnoDB更新内存中的脏数据时,最后都会由后台IO线程在不确定的时间刷回到磁盘里,这就涉及随机IO。如果IOPS指标太低,那么会导致内存里的脏数据刷回磁盘的效率不高。
(2)吞吐量
吞吐量指的是机器的磁盘存储每秒可以读写多少字节的数据量。
吞吐量这个指标也很关键。因为MySQL在执行各种SQL语句、提交事务时,都会大量写redo日志、binlog日志,这些日志都会写到磁盘文件。所以一台机器的磁盘存储每秒可以读写多少字节的数据量,就决定了它每秒可以把多少日志写入到磁盘里。
一般写redo之类的日志,都是对磁盘文件进行顺序写入的,也就是一行接着一行的写,而不会进行随机读写。普通磁盘的顺序写入的吞吐量每秒都可以达到200MB左右。通常而言,机器的磁盘吞吐量都是足够承载高并发请求的。
(3)latency
latency指的是往磁盘里写入一条数据的延迟。
latency这个指标同样很重要。因为MySQL在执行一条SQL语句和提交事务时,都需要顺序写一条redo日志和一条binlog日志到磁盘文件。所以此时写一条日志到磁盘文件里去,到底是延迟1ms还是延迟100us,很影响数据库SQL语句的执行性能。一般来说,磁盘读写延迟越低,数据库的性能就越高,执行每个SQL语句和事务的时候速度就会越快。
6.压测时需要关注的其他性能指标
(1)CPU负载
(2)网络负载
(3)内存负载
除了QPS、TPS、IOPS、吞吐量、latency这些指标外,在压测时还需要关注机器的一些其他性能指标:
(1)CPU负载
CPU负载是一个很重要的性能指标。假设数据库压测到了每秒处理3000请求,可能其他的性能指标还都正常,但CPU负载特别高,这也说明数据库不能继续往下压测更高的QPS了。
(2)网络负载
这个要看机器带宽在压测到一定的QPS和TPS时,每秒钟机器的网卡会输入和输出多少MB数据。因为有可能机器的网络带宽最多每秒传输100MB的数据,如果当QPS为1000时网卡就打满了,那么即使其他指标正常,此时也不能继续压测了。
(3)内存负载
就是看在压测到一定情况下,机器内存耗费了多少。如果机器内存耗费过高,说明也不能继续压测了。
7.一台机器每秒可以抗多少并发的影响因素
影响因素:线程数、线程处理请求时间、CPU、内存、磁盘IO、网络带宽
(1)4核8G机器上的Java系统处理每个请求只需0.01ms每秒能抗多少请求
理论上通过增加线程数、内存读写,抗几千并发甚至上万并发都是可以的。但线程数越来越多后,切换上下文很费CPU、导致CPU负载也会变高。因此当请求源源不断进来时,可能会导致挤压从而拖垮系统。
一台机器每秒可以处理的请求数 = 可用线程数 * 每个线程每秒处理请求数;但即使该Java程序处理一个请求需要0.01ms,能扛多少请求还需考虑:内存能抗多少、CPU能支撑多少线程、网卡流量多大的负载能打满等,综合这些因素才能得出一台机器究竟能扛多少请求。
一般的机器配置,如果Java程序不依赖数据库只是请求处理,那么每个请求处理只需要0.01ms,此时每秒还是可以扛上万请求的。
总之,一台机器到底可以每秒抗下多少并发请求,跟CPU、内存、磁盘IO、网络带宽都有关系。
(2)如何区分QPS和TPS
一个交易系统会拆分很多服务。对于单个服务来说,每秒处理请求数量就是QPS。对于整个交易系统来说一次交易请求需要调用多个服务,那么其每秒处理完这些服务的的交易笔数则是TPS。
8.sysbench是非常好用的数据库压测工具
(1)sysbench的用途
(2)在Linux安装sysbench工具
(3)数据库压测的测试用例
(4)基于sysbench构造测试表和测试数据
(5)对数据库进行360度全方位测试
(6)压测结果分析
(1)sysbench的用途
可以在数据库里自动构造出大量的数据,可以模拟几千个线程并发访问数据库,可以模拟使用各种SQL语句来访问数据库,可以模拟出各种事务提交到数据库里,可以模拟出几十万的TPS去压测数据库。
(2)在Linux安装sysbench工具
先设置yum repo仓库,接着基于yum来安装sysbench即可;
$ curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash $ sudo yum -y install sysbench $ sysbench --version
(3)数据库压测的测试用例
接着需要在数据库里创建好一个测试库,可以取名为test_db。同时创建好对应的测试账号,可以叫test_user。然后要基于sysbench构建20个测试表,每个表里有100万条数据。接着使用10个并发线程去对这个数据库发起访问,连续访问5分钟。
(4)基于sysbench构造测试表和测试数据
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_read_write --db-ps-mode=disable prepare
上面构造了一个sysbench命令,加入了很多参数,下面是这些参数解释:
1.--db-driver=mysql:意思是基于mysql的驱动去连接mysql数据库,这里可以选oracle、sqlserver等 2.--time=300:意思是连续访问300秒 3.--threads=10:意思是用10个线程模拟并发访问 4.--report-interval=1:意思是每隔1秒输出一下压测情况 5.--mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user:意思是连接到哪台机器的哪个端口上的MySQL库 6.--mysql-db=test_db --tables=20 --table_size=1000000:意思是在test_db这个库里,构造20个测试表,每个测试表里构造100万条测试数据,测试表的名字将类似于sbtest1、sbtest2 7.oltp_read_write:意思是执行oltp数据库的读写测试 8.--db-ps-mode=disable:意思是禁止ps模式 9.prepare:意思是参照这个命令的设置去构造出我们需要的数据库里的数据,它会自动创建20个测试表,每个表里创建100万条测试数据
(5)对数据库进行360度全方位测试
a.测试数据库的综合读写TPS,使用oltp_read_write模式。命令中最后不是prepare而是run,代表的就是运行压测:
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_read_write --db-ps-mode=disable run
b.测试数据库的只读性能,使用oltp_read_only模式。命令中的oltp_read_write已经变成oltp_read_only了:
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_read_only --db-ps-mode=disable run
c.测试数据库的删除性能,使用oltp_delete模式:
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_delete --db-ps-mode=disable run
d.测试数据库的更新索引字段的性能,使用oltp_update_index模式:
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_update_index --db-ps-mode=disable run
e.测试数据库更新非索引字段的性能,使用oltp_update_non_index模式:
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_update_non_index --db-ps-mode=disable run
f.测试数据库的插入性能,使用oltp_insert模式:
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_insert --db-ps-mode=disable run
g.测试数据库的写入性能,使用的是oltp_write_only模式:
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_write_only --db-ps-mode=disable run
使用上面的命令,sysbench工具会构造出各种各样的SQL语句,然后根据这些SQL语句去更新或者查询20张测试表里的数据,同时检测出数据库的压测性能指标,最后完成压测后可以执行下面的cleanup命令进行清理数据:
$ sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 \ --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 \ --table_size=1000000 oltp_read_write --db-ps-mode=disable cleanup
(6)压测结果分析
按照上面的命令,让sysbench每隔1秒输出一次压测报告,此时每秒输出类似如下的数据:
[22s] thds:10 tps:380.99 qps:7312.66 (r/w/o:5132.99/1155.86/1321.55) lat(ms,95%):21.33 err/s:0.00 reconn/s:0.00
该输出的意思是:这是第22s输出的一段压测统计报告,后面是具体的统计字段:
1.thds: 10,意思是有10个线程在压测 2.tps:380.99,意思是每秒执行了380.99个事务 3.qps:7312.66,意思是每秒可以执行7612.66个请求 4.(r/w/o:5132.99/1155.86/1321.55),意思是每秒7612.66个请求中,有5132.99个请求是读请求,1155.86个请求是写请求,1321.55个请求是其他请求 5.lat(ms,95%):21.33,意思是95%的请求的延迟都在21.33毫秒以下 6.err/s:0.00 reconn/s:0.00,意思是每秒有0个请求是失败的,每秒发生了0次网络重连
完成压测后,最后会显示一个总的压测报告,如下:
SQL statistics: queries performed: read:1480084 //意思是在300s的压测期间执行了148万多次的读请求 write:298457 //意思是在压测期间执行了29万多次的写请求 other:325436 //意思是压测期间执行了32万多次的其他请求 total:2103977 //意思是一共执行了210万多次的请求 transactions:105180 (350.6 per sec.) //意思是一共执行了10万多个事务,每秒执行350多个事务 queries:2103977 (7013.26 per sec.) //意思是一共执行了210万多次的请求,每秒执行7000+请求 ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) //下面的意思是一共执行了300s压测,执行了10万+的事务 General saticstics: total time:300.0052s total number of events:105180 Latency(ms): min:4.32 //请求中延迟最小的是4.32ms avg:13.42 //所有请求平均延迟是13.42ms max:45.66 //延迟最大的请求是45.56ms 95th percentile:21.33 //95%的请求延迟都在21.33ms以内
9.压测中除了QPS和TPS外还要观察机器性能
上面例子使用了10个线程去压测数据库。如果机器的性能很高,10个线程是没法压测出数据库的最高负载能力的。可以在sysbench中不停的增加线程的数量,比如使用20个线程,甚至100个线程去并发的访问数据库,直到发现数据库的QPS和TPS上不去。
当然,不停地提高线程数,让数据库不停地承载更高的QPS的过程,还需要配合对机器性能表现的观察来做,不能盲目增加线程。
为什么在不停增加线程数量的时候,要密切关注机器性能?首先假设数据库当前抗下了每秒2000的QPS,同时这时CPU负载、内存负载、网络负载、磁盘IO负载,都在正常范围。负载相对较高一些,但是还没有达到这些硬件的极限,那么可认为这台数据库在高峰期能抗每秒2000QPS。
但如果一直不停的在压测过程中增加sysbench的线程数量,然后数据库此时勉强抗到了每秒5000的QPS了。但这时发现机器CPU已满负荷运行、内存使用率特别高、内存快耗尽,然后网络带宽几乎被打满、磁盘IO的等待时间特别长,那么这时就说明机器已到了极致了。所以这时压测出的5000QPS是没什么代表性的,因为在生产环境根本不可能让数据库抗下这么高的QPS,因为到这么高的QPS就说明数据库几乎已经快挂掉了,这是不现实的。
所以在压测的过程中:必须是不停增加sysbench的线程数量,持续让数据库承载更高的QPS,同时密切关注CPU、内存、磁盘和网络的负载。在硬件负载情况比较正常的范围内,哪怕负载相对较高一些,也还是可以继续增加线程数量和提高数据库的QPS的。
然后当不停增加线程数量,发现数据库可以抗下下一个QPS的数值时,机器的CPU、内存、网络和磁盘的负载已经比较高了,机器已经到了一个有一定风险的临界值了,那么此时就不能继续增加线程数量和提高数据库压测的QPS了。
10.压测时如何观察机器的CPU负载情况
先来看一个最常用的监测Linux机器性能的命令,就是top命令。在linux命令行输入top命令就会看到如下一行信息:
top - 15:52:00 up 42:35, 1 user, load average: 0.15, 0.05, 0.01
这行信息是最直观可以看到机器的CPU负载情况的:首先15:52:00指的是当前时间;up 42:35指的是机器已经运行了多长时间;1 user就是说当前机器有1个用户在使用;最重要的是load average: 0.15, 0.05, 0.01这行信息,这说的是CPU在1分钟、5分钟、15分钟内的负载情况。
CPU负载指(假设在4核CPU机器执行top命令):
一.如果CPU负载是0.15,则说明4核CPU中连一个核都没用满,4核CPU基本都很空闲没怎么使用;
二.如果CPU负载是1,则说明4核CPU中有一个核已被使用得比较繁忙,另外3个核还是比较空闲的;
三.如果CPU负载是1.5,说明有一个核被使用繁忙,另外一个核也在使用,但是没那么繁忙,此时还有2个核可能是空闲的;
四.如果CPU负载是4,那说明4核CPU都被跑满了;
五.如果CPU负载是6,那说明4核CPU被繁忙的使用还不够处理当前的任务,很多进程可能一直在等待CPU去执行自己的任务。
所以上面看到的load average实际上就是:CPU在最近1分钟5分钟15分钟内的平均负载数值。
上面看到的负载是0.15,说明CPU根本没怎么用。如果压测过程中发现4核CPU的load average已经达到3.5或者4了,则说明CPU基本都跑满了,已经在满负荷运转了。此时就不要再继续提高线程的数量和增加数据库的QPS了。
11.压测时如何观察机器的内存负载情况
在执行top命令后,中间跳过几行内容,可以看到如下一行内容:
Mem: 33554432k total, 20971520k used, 12268339 free, 307200k buffers
这说的就是当前机器的内存使用情况:总内存有32G,已使用20G内存,还有10多G内存是空闲的,有大概300MB左右的内存用作OS内核的缓冲区。
对于内存而言,同样要在压测的过程中紧密观察。如果内存的使用率在80%以内,基本都还能接受,在正常范围内。但是如果机器的内存使用率到了70%~80%了,就说明有点危险了。此时就不要继续增加压测的线程数量和QPS了,差不多就可以了。
12.压测时如何观察机器的磁盘IO情况
可用dstat命令查看存储的IO吞吐量、IOPS等信息。
一.使用命令:dstat -d,会看到如下的信息:
-dsk/total - read writ 103k 211k 0 11k
在上面可以清晰看到:存储的IO吞吐量是每秒钟读取103KB的数据,每秒写入211KB的数据。像这个存储IO吞吐量基本上都不算多的,因为普通的机械硬盘都可以做到每秒钟上百MB的读写数据量。
二.使用命令:dstat -r,可以看到如下的信息:
--io/total- read writ 0.25 31.9 0 253 0 39.0
这个意思就是读IOPS和写IOPS分别是多少。也就是说随机磁盘读取每秒钟多少次,随机磁盘写入每秒钟执行多少次。
一般来说,随机磁盘读写每秒在两三百次都是可以承受的。所以在这里就需要在压测的时候密切观察机器的磁盘IO情况:如果磁盘IO吞吐量已经太高了,都达到极限的每秒上百MB的磁盘IO了,或者随机磁盘读写每秒都到极限的两三百次IOPS了,此时就不要继续增加线程数量了,否则磁盘IO负载就太高了;
13.压测时观察网卡的流量情况
可以使用命令:dstat -n,查看网卡流量信息:
-net/total- recv send 16k 17k
这个说的就是:每秒钟网卡接收到的流量有多少KB;每秒钟通过网卡发送出去的流量有多少KB。
如果机器使用的是千兆网卡,那么每秒网卡的总流量也就在100MB左右,在压测时也要观察网卡的流量。如果网卡传输流量已到极限值,那么此时再怎么提高sysbench线程数量,数据库的QPS也上不去,因为这台机器每秒已无法通过网卡传输更多的数据。
14.使用sysbench压测数据库总结
在数据库压测的过程中,必须不停的增加sysbench的线程数量,测试数据库能抗下的QPS。同时通过各种命令观察机器的CPU、内存、磁盘和网络的负载情况。如果发现某个硬件负载已经很高,此时就可以不再提高数据库的QPS。
在硬件的合理负载范围内,把数据库的QPS提高到最大。这就是数据库压测时最合理的一个极限QPS值。而不是不管机器的各个硬件的负载,盲目增加sysbench的线程数量。
CPU负载:top
内存负载:top下的Mem
磁盘IO吞吐量:dstat -d (每秒上百MB)
磁盘IOPS:dstat -r (每秒两三百)
网卡流量:dstat -n (千兆网卡每秒100MB左右)
#牛客创作赏金赛#MySQL底层原理与应用