三、关于生产环境下的MySQL(上)(sysbench 压测)
3-1 机器的选择
- 我们只关注 有一定并发量的互联网类系统。(每秒 几百、几千甚至上万的并发量)。
- 数据库通常选择 8核 16线程 或 16核 32线程
- 关于 JAVA项目
- java项目 若在 jvm内存中执行一些业务逻辑,实际上是很快的。
- 其实瓶颈在于 IO、网络请求上。例如 JAVA项目中直接对文件进行操作、 请求数据库 进行 增删查改 等等。
- 部署MySQL时,其实还需要针对 OS内核参数、MySQL参数、MySQL启动参数 进行调优。
3-2 压测
- 如何测压呢? 可以用工具模拟一个系统每秒发送一定请求数 到 数据库,观察 其 CPU负载、磁盘IO、网络IO、内存 等系统指标的变化。
3-2-1 测压指标
- 相关指标
- QPS(Query Per Second): 每秒可以处理多少个请求
- TPS (Transaction Per Second): 每秒可以处理的事务量 (也就是每秒可以处理多少次事务提交或回滚)
- IOPS: 随机IO 并发处理能力。(MySQL会有随机IO将内存中数据刷回磁盘)若该指标太低,会导致你内存里的脏数据刷回磁盘的效率就低。
- 吞吐量: 机器的磁盘存储每秒可以读取多少个字节。
- 吞吐量决定他每秒可以将 redo log、undo 等日志写入磁盘里。
- 通常 机器磁盘的吞吐量都能够承载高并发请求
- latency: 磁盘写入一条数据的延迟
- 提交事务时向磁盘写入日志的延迟时间 会影响 SQL语句执行性能
- 当磁盘读写延迟越低,数据库性能越高。
- OS的其他指标
- CPU负载:当CPU负载过高时,说明不能继续提高QPS进行测压
- 网络负载:机器的带宽情况 。当网卡被打满时,即使其他指标正常,也已经不能继续测压了
- 内存负载: 若你内存消耗过高时,也不能继续测压。
3-2-2 如何进行测压
- 推荐一个工具 sysbench。 开业自动往数据库里构造大量数据。模拟并发从而实现MySQL数据库。
- 安装方法
curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash sudo yum -y install sysbench sysbench --version
- 测试用例(例子)
- 构建10个测试表,每个表里有300万行数据。使用10个线程并发访问。连续访问300s
- 构建10个测试表,每个表里有300万行数据。使用10个线程并发访问。连续访问300s
3-2-2-1 基于sysbench进行测试
-
sysbench 命令 详见github仓库 或 sysbench --help
-
第一步:利用 sysbench创建 测试表和测试数据
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_read_write --db-ps-mode=disable prepare
由于我用的是 一个 普通的台式机做演示。需要经过一段时间等待。才能把数据准备好。
- 第二步: 各种测试
- 读写能力测试(oltp_read_write模式)
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_read_write --db-ps-mode=disable run
- 只读能力测试(oltp_read_only)
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_read_write --db-ps-mode=disable run
- 删除能力测试(oltp_delete)
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_delete --db-ps-mode=disable run
- 更新索引字段测试(oltp_update_index)
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_update_index --db-ps-mode=disable run
- 更新非索引字段测试(oltp_update_index)
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_update_index --db-ps-mode=disable run
- 更新索引字段测试(oltp_update_non_index)
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_update_index --db-ps-mode=disable run
- 插入数据测试(oltp_insert)
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_insert --db-ps-mode=disable run
- 写入性能测试(oltp_write_only)
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_write_only --db-ps-mode=disable run
- cleanup命令进行清除数据
sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=192.168.31.10 --mysql-port=3306 --mysql-user=test_u --mysql-password=123456as --mysql-db=test_db --tables=10 --table_size=3000000 oltp_write_only --db-ps-mode=disable cleanup
-
第三步:测压报告
-
根据命令每隔一段时间会输出一次压力报告
[ 300s ] thds: 100 tps: 889.46 qps: 13710.26 (r/w/o: 11955.44/0.00/1754.82) lat (ms,95%): 325.98 err/s: 0.00 reconn/s: 0.00- [ 300s ] 表示第300秒输出的报告
- thds: 100 表示 有 100 个线程压测
- tps: 889.46 表示 每秒执行了 889.46个事务
- qps: 13710.26 表示每秒执行 7610.12个请求
- (r/w/o: 11955.44/0.00/1754.82) 表示 在 13710.26个请求中, 有 读请求:11955.44,写请求 0个,其他请求 1754.82
- lat (ms,95%): 325.98 表示 95%的请求的延迟都在325.98毫秒以下
- err/s: 0.00 reconn/s: 0.00 ,每秒有0个请求失效。有0个请求网络重连
-
最后悔显示一个总的压力测试报告
SQL statistics:
queries performed:
read: 1961386 //表示300s的压测期间执行了 1961386个读请求
write: 0 //表示300s的压测期间执行了 0个写请求
other: 280198 //表示300s的压测期间执行了 280198个其他请求
total: 2241584 //表示300s的压测期间执行了 2241584个请求
transactions: 140099 (466.66 per sec.) // 一个执行了140099 事务,其中每秒执行466.66个事务
queries: 2241584 (7466.52 per sec.) // 一个执行了2241584 请求,其中每秒执行7466.52个请求
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
// 下面就是说,一共执行了300.2160的压测,执行了140099个事务
General statistics:
total time: 300.2160s
total number of events: 140099
Latency (ms):
min: 3.42 // 请求中延迟最小的是3.42ms
avg: 214.16 // 所有请求平均延迟是214.16 ms
max: 17142.23 // 延迟最大的请求是17142.23ms
95th percentile: 960.30 // 95%的请求延迟都在 960.30 ms以内
sum: 30004149.54 // 总共延迟了 30004149.54 ms
Threads fairness:
events (avg/stddev): 1400.9900/59.13
execution time (avg/stddev): 300.0415/0.04