当我们手头有了一个可以使用的数据库之后,比较专业的做法是,对这个数据库进行一次较为基本的基准测试,而不是马上基于它进行系统开发。那么,怎么对数据库进行压测呢?
一、压测
1、压测的定义
所谓压测,就是基于一些工具模拟一个系统每秒发出一定数量的请求到数据库上去,观察它的CPU负载、磁盘IO负载、网络IO负载和内存负载等情况,测试出这个数据库在目前的机器配置下,大致的负载压力如何,性能表现如何,每秒最多可以处理多少请求。
2、压测性能指标
既然要压测,那我们应该测试哪些性能指标呢?
- QPS(Query Per Second):数据库每秒可以处理多少个SQL语句
- TPS(Transaction Per Second):数据库每秒可以处理多少事务量
- IOPS:机器的随机并发处理能力,即每秒可以执行多少随机IO读写请求。比如,数据库在内存中更新的脏数据,最后都会由后台IO线程在不确定的时间,刷回到磁盘里去,这就是一个随机IO的过程。
- 吞吐量:机器的磁盘存储每秒可以读写多少字节的数据量。
- latency: 往磁盘里写入一条数据的延迟。
- CPU负载
- 网络负载
- 内存负载
3、压测
我们现在就用sysbench压测工具对数据库做压测。
I、sysbench安装:
curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
sudo yum -y install sysbench
-- 查看版本号
sysbench --version
如果可以看到版本号,说明sysbench就安装成功了。
II、构造测试表和测试数据
首先在数据创建一个测试库test_db
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
参数解释:
- –db-driver=mysql
- –time=300:连续访问300秒
- –threads=10:用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:构造20个测试表
- –table_size=1000000:每个测试表构造100完条测试数据
- oltp_read_write:执行oltp数据库的读写测试
- –db-ps-mode=disable:禁止ps模式
- prepare:参照以上设置构造数据
III、测试
测试数据库综合读写性能:
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
除了最后参数变成了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_only --db-ps-mode=disable run
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_delete --db-ps-mode=disable run
使用的是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_update_index --db-ps-mode=disable run
使用的是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_non_index --db-ps-mode=disable run
使用的是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_insert --db-ps-mode=disable run
使用的是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_write_only --db-ps-mode=disable run
使用的是oltp_write_only模式
IV、清理数据
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
测试完成后,可以用cleanup清理数据。
5、压测结果分析
上面的测试会输出类似以下的内容:
[ 22s ] thds: 10 tps: 380.99 qps: 7312.66 (r/w/o: 5132.99/1155.86/1321.35) lat (ms, 95%): 21.33 err/s: 0.00 reconn/s: 0.00
字段解释:
- [ 22s ]:第22秒输出的测试报告
- thds: 10:10个线程在压测
- tps: 380.99:每秒执行了380.99个事务
- qps: 7312.66:每秒执行了7312.66个请求
- (r/w/o: 5132.99/1155.86/1321.35):在7312.66个请求中,有多少读请求,有多少写请求,有多少其他请求
- lat (ms, 95%): 21.33:95%的请求延迟都在21.33毫秒以下
- err/s: 0.00:每秒有0个请求失败
- reconn/s: 0.00:发生了0次网络重连
压测完成之后,会显示一个总的压测报告:
SQL statistics:
queries performed:
read: 1480084 // 这就是说在300s的压测期间执行了148万多次的读请求
write: 298457 // 这是说在压测期间执行了29万多次的写请求
other: 325436 // 这是说在压测期间执行了30万多次的其他请求
total: 2103977 // 这是说一共执行了210万多次的请求
// 这是说一共执行了10万多个事务,每秒执行350多个事务
transactions: 105180( 350.6 per sec. )
// 这是说一共执行了210万多次的请求,每秒执行7000+请求
queries: 2103977 ( 7013.26 per sec. )
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
// 下面就是说,一共执行了300s的压测,执行了10万+的事务
General staticstics:
total time: 300.0052s
total number of events: 105180
Latency (ms):
min: 4.32 // 请求中延迟最小的是4.32ms
avg: 13.42 // 所有请求平均延迟是13.42ms
max: 45.56 // 延迟最大的请求是45.56ms
95th percentile: 21.33 // 95%的请求延迟都在21.33ms以内
二、性能监测
在压测过程中,输入top命令,就可以看到以下内容:
1、CPU负载
top - 10:18:34 up 16 days, 23:21, 3 users, load average: 0.42, 0.25, 0.17
第一行就是机器CPU负载情况
解释:
- 10:18:34:表示当前时间
- 16 days, 23:21:表示机器运行了多长时间
- 3 users:表示当前机器有几个用户在用
- load average: 0.42, 0.25, 0.17:表示CPU在1分钟、5分钟和15分钟内的负载情况
2、内存负载
Mem : 3880188 total, 164828 free, 2579352 used, 1136008 buff/cache
这一行显示的就是当前机器的内存使用情况
解释:
- 3880188 total:总内存
- 164828 free:剩余内存
- 2579352 used:已经使用的内存
- 1136008 buff/cache:用作OS内存缓冲区的内存
3、磁盘IO
输入dstat -d,会看到以下内容:
意思是每秒钟读取6677B的数据,每秒钟写入28K的数据输入dstat -r,可以看到IOPS情况
4、网卡流量
输入dstat -n,可以查看网卡流量情况
意思是每秒钟接收到多少流量,每秒钟发出去多少流量
三、监测系统
虽然我们可以通过一些命令去查看机器和数据库的负载情况,但是不能做到对这些有一个实时的了解。所以我们应该也必须建立起一套完善的监控体系,不然哪天数据库负载已经很高了,系统还在运行,数据库很可能就挂了。
我们可以基于Prometheus和Grafana搭建一个可视化监控平台,来实时监控机器和数据库的运行情况。
1、安装和启动Prometheus
可以在 http://cactifans.hi-www.com/prometheus/ 中下载
prometheus-2.1.0.linux-amd64.tar.gz
node_exporter-0.15.2.linux-amd64.tar.gz
可以通过 https://github.com/prometheus/mysqld_exporter/releases/download/v0.10.0/mysqld_exporter-0.10.0.linux-amd64.tar.gz 下载 mysqld_exporter-0.10.0.linux-amd64.tar.gz
接着解压上面三个安装包,然后进入prometheus,修改prometheus.yml配置文件
现在就可以启动prometheus
nohup ./prometheus --config.file=prometheus.yml &
浏览器中输入IP:9090就可以访问
因为还没有部署mysqld_exporter和node_exporter服务,所以两个的状态都是DOWN
2、部署mysqld_exporter和node_exporter
切换到node_exporter目录,运行nohup ./node_exporter &就可以启动node_exporter服务
mysqld_exporter需要连接到MySQL,所以需要授权
mysql> grant replication client, process on *.* to 用户名@"localhost" identified by "密码";
mysql> grant select on performance_schema.* to 用户名@"localhost";
然后切换到mysqld_exporter目录,添加 .my.cnf 配置文件
[client]
user=用户名
password=密码
现在就可以启动mysqld_exporter服务
nohup ./mysqld_exporter --config.my-cnf=.my.cnf &
现在所有服务状态都变成了UP
3、部署Grafana
可以通过https://mirrors.huaweicloud.com/grafana/4.6.3/grafana-4.6.3.linux-x64.tar.gz 下载grafana-4.6.3.linux-x64.tar.gz安装包
解压,进入bin目录,输入./grafana-server &就可以启动grafana服务
通过3000端口就可以访问,默认用户名和密码都是admin
接着切换到Data Sources,点击Add data source按钮,就可以添加一个数据源
然后输入Name,Type和URL,其他的默认就行
Grafana就可以从Prometheus获取数据并展示出来了
接着就需要安装Grafana仪表盘组件
可以通过https://codeload.github.com/percona/grafana-dashboards/tar.gz/v1.6.1 下载 grafana-dashboards-1.6.1.tar.gz 安装包
解压并切换到grafana-dashboards主目录,运行一下命令进行安装
updatedb
locate json |grep dashboards/
然后再dashboards目录下可以看到一堆json文件,这些就是仪表盘的配置文件。
接下来点击grafana页面的Home按钮,会看到一个Import Dashboard按钮,可以把刚才的json文件导入进来
现在我们就可以看到机器和数据库的使用情况: