回城传送–》《32天SQL筑基》
今天是学习 SQL 打卡的第 24 天,每天我会提供一篇文章供群成员阅读( 不需要订阅付钱 )。
希望大家先自己思考,如果实在没有想法,再看下面的解题思路,自己再实现一遍。在小虚竹JAVA社区 中对应的 【打卡贴】打卡,今天的任务就算完成了,养成每天学习打卡的好习惯。
虚竹哥会组织大家一起学习同一篇文章,所以有什么问题都可以在群里问,群里的小伙伴可以迅速地帮到你,一个人可以走得很快,一群人可以走得很远,有一起学习交流的战友,是多么幸运的事情。
我的学习策略很简单,题海策略+ 费曼学习法。如果能把这些题都认认真真自己实现一遍,那意味着 SQL 已经筑基成功了。后面的进阶学习,可以继续跟着我,一起走向架构师之路。
今天的学习内容是:SQL进阶-查询优化- performance_schema系列实战一:利用等待事件排查MySQL性能问题
在生产上线之前,对数据库进行增删改查的基准测试,收集基准数据,为了后续做扩容和架构升级做准备。
MySQL数据库基准测试通常选择sysbench、tpcc-mysql、workbench。
以下我们以sysbench基准测试工具压测MySQL数据库为例,介绍如何使用performance_schema的等待事件来排查数据库性能瓶颈所在。
使用performance_schema配置表启用等待事件的采集与记录。
use performance_schema;
修改setup_instruments 表的enabled和timed字段为yes,表示启用对应的instruments
update setup_instruments set enabled='yes',timed='yes' where name like 'wait/%';
查看修改结果,enabled和timed字段为YES即表示当前instruments已经启用(但此时采集器并不会立即采集事件数据,需要保存这些等待事件的表–consumers,启用之后才会开始采集)
select * from setup_instruments where name like 'wait/%';
update setup_consumers set enabled='yes' where name like '%wait%';
select * from setup_consumers where name like '%wait%';
mysql 基准测试可以理解为对mysql数据库运行时的一种压力测试。关键指标有3个方面:
TPS/QPS:衡量吞吐量。
响应时间:包括平均响应时间,最小响应时间,最大响应时间和时间百分比竺。
并发量:同时处理查询请求的数量。
sysbench支持多线程工作,并且能够跨平台安装部署。
curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
sudo yum -y install sysbench
sysbench --version
sysbench --help
以下中括号中的值表示默认值
option类型 | 参数名称 | 参数含义 |
---|---|---|
通用选项 | threads | 指定线程数[1] |
通用选项 | events | 限制最大请求数,0表示不限制[0] |
通用选项 | time | 限制最长执行时间,0表示不限制[10] ,单位秒 |
通用选项 | forced-shutdown | 达到最长执行时间后还需等待多久关闭sysbench off表示禁用该功能[off] |
通用选项 | thread-stack-size | 每个线程使用的栈空间大小[64K] |
通用选项 | rate | 平均事务处理速率,0表示不限制[0] |
通用选项 | report-interval | 每隔几秒报告一次结果,0表示禁用间隔报告[0] |
通用选项 | config-file | 从文件中读取命令行选项 |
mysql专用选项 | mysql-host | mysql主机名,[localhost] |
mysql专用选项 | mysql-port | mysql端口,[3306] |
mysql专用选项 | mysql-socket | 指定 socket 文件来连接 |
mysql专用选项 | mysql-user | 登录mysql的用户名,默认值:[sbtest] |
mysql专用选项 | mysql-password | 登录mysql的密码 |
mysql专用选项 | mysql-db | 指定数据库名称,默认值:[sbtest] |
mysql专用选项 | mysql-ssl | 使用ssl连接 |
mysql专用选项 | mysql-ssl-cipher | 使用ssl连接时的密码 |
mysql专用选项 | mysql-compression | 使用压缩算法 |
mysql专用选项 | mysql-debug | 跟踪所有的客户端使用,[off] |
mysql专用选项 | mysql-ignore-errors | 忽略指定的错误代码或者使用all忽略所有的错误,[1213,1020,1205] |
testname :指定要进行测试的名称。
command : 代表sysbench 要执行的命令,包含prepare,run和cleanup三个命令。
sysbench cpu --cpu-max-prime=20000 --threads=2 run
对cpu的测试,是进行素数的加法运算测试,其中:
–cpu-max-prime:生成素数的数量上限。
–threads:启动进行素数计算的线程数。
说明:
Running the test with following options:
#指定线程个数
Number of threads: 2
Initializing random number generator from current time
#每个线程产生的素数上限为2万个。
Prime numbers limit: 20000
Initializing worker threads...
Threads started!
CPU speed:
#所有线程每秒完成了839.89次event
events per second: 839.89
General statistics:
total time: 10.0022s
total number of events: 8402 #在10.0022s秒内共完成了8402次event
Latency (ms):
min: 2.29
avg: 2.38
max: 10.31
95th percentile: 2.61 #95%的events都在2.61毫秒内完成。
sum: 19997.47
Threads fairness:
# 平均每完成4201.0000次event,标准差是2
events (avg/stddev): 4201.0000/2.00
# 每个线程平均耗时9.9987秒。
execution time (avg/stddev): 9.9987/0.00
sysbench fileio --file-total-size=1G --file-test-mode=rndrw --time=30 --max-requests=0 prepare
sysbench fileio --file-total-size=1G --file-test-mode=rndrw --time=30 --max-requests=0 run
执行效果:
IOPS的计算公式如下:
IOPS=(Throughput read +Throughput written)*1024/16KB
Throughput read :每秒的输入量
Throughput written:每秒的输出量。
从图上的测试数据可以计算出当前硬盘的IOPS为:
IOPS=( 12.31+8.21)*1024/16=1313.28
sysbench fileio --file-total-size=1G --file-test-mode=rndrw --time=30 --max-requests=0 cleanup
sysbench提供了对数据库性能测试的lua脚本。这些脚本放在: /usr/share/sysbench/目录下。
为了以树形查看结构,先安装tree命令。
sudo yum install -y tree
列 出lua脚本。
tree /usr/share/sysbench/ -P *.lua
下面实战演示使用lua脚本测试mysql数据库。
创建测试数据库sysbenchdemo
create database sysbenchdemo;
sysbench /usr/share/sysbench/oltp_insert.lua \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-socket=/tmp/mysql.sock \
--mysql-user=root \
--mysql-password=xiaoxuzhu \
--mysql-db=sysbenchdemo \
--db-driver=mysql \
--tables=5 \
--table-size=100000 \
--time=180 prepare
说明:
使用/usr/share/sysbench/oltp_insert.lua脚本,创建了5张表,往每张表插入100000条数据。
sysbench /usr/share/sysbench/oltp_insert.lua \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-socket=/tmp/mysql.sock \
--mysql-user=root \
--mysql-password=xiaoxuzhu \
--mysql-db=sysbenchdemo \
--db-driver=mysql \
--tables=5 \
--table-size=100000 \
--time=180 run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 1
Initializing random number generator from current time
Initializing worker threads...
Threads started!
SQL statistics:
queries performed:
read: 0
# 总的写次数
write: 29970
other: 0
total: 29970
# 总的事务数和每秒事务数
transactions: 29970 (166.50 per sec.)
queries: 29970 (166.50 per sec.)
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
# 总的执行时间和事件数。
total time: 180.0018s
total number of events: 29970
# 延时统计信息
Latency (ms):
min: 3.16
avg: 6.00
max: 237.40
95th percentile: 11.24
sum: 179912.58
Threads fairness:
events (avg/stddev): 29970.0000/0.00
execution time (avg/stddev): 179.9126/0.00
sysbench /usr/share/sysbench/oltp_insert.lua \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-socket=/tmp/mysql.sock \
--mysql-user=root \
--mysql-password=xiaoxuzhu \
--mysql-db=sysbenchdemo \
--db-driver=mysql \
--tables=5 \
--table-size=100000 \
--time=180 cleanup
逐渐增加并发线程数,直到tps、qps不再随着线程数的增加而增加为止
sysbench /usr/share/sysbench/oltp_insert.lua \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-socket=/tmp/mysql.sock \
--mysql-user=root \
--mysql-password=xiaoxuzhu \
--mysql-db=sysbenchdemo \
--db-driver=mysql \
--tables=8 \
--table-size=100000 \
--time=180 prepare
sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-socket=/tmp/mysql.sock \
--mysql-user=root \
--mysql-password=xiaoxuzhu \
--mysql-db=sysbenchdemo \
--db-driver=mysql \
--oltp-table-size=5000000 \
--oltp-tables-count=8 \
--num-threads=16 \
--max-time=1800 \
--max-requests=0 \
--report-interval=1 run
从sysbench的输出结果中,我们可以看到在16个并发线程oltp压力下,tps可以跑到600~900,qps:15000左右,且延迟在1000ms+
为什么延迟这么高,使用top看下,可以看出mysql 的cpu占用率高。
为了方便查询等待事件统计,我们可以先创建一个视图,用于实时统计当前等待事件(非历史数据)
use performance_schema;
create view sys.test_waits as select sum(TIMER_WAIT) as TIMER_WAIT,sum(NUMBER_OF_BYTES) as NUMBER_OF_BYTES, EVENT_NAME,OPERATION from events_waits_current where EVENT_NAME!='idle' group by EVENT_NAME,OPERATION;
select sys.format_time(TIMER_WAIT),sys.format_bytes(NUMBER_OF_BYTES),EVENT_NAME,OPERATION from sys.test_waits where sys.format_time(TIMER_WAIT) not regexp 'ns|us' order by TIMER_WAIT desc;
也可以直接查询events_waits_current表
select THREAD_ID,EVENT_NAME,sys.format_time(TIMER_WAIT),INDEX_NAME,NESTING_EVENT_TYPE,OPERATION,NUMBER_OF_BYTES
from events_waits_current
where EVENT_NAME!='idle' order by TIMER_WAIT desc;
从上述等待事件的查询结果中,是cpu不够,wait/synch/cond/mysqlx/scheduler_dynamic_worker_pending 调度程序动态工作程序挂起。
本文分享了sysbench如何安装和使用,详细介绍了通过sysbench压测mysql数据库,利用等待事件排查MySQL性能问题。
哈哈哈,你学会了吗~
应用示例荟萃 | performance_schema全方位介绍(上)
【mysql 数据库进阶实战-第10章mysql性能优化与运维管理】作者:赵渝强老师
我是虚竹哥,我们明天见~