压榨数据库的真实处理速度

引子

你了解你们线上数据库的真实处理速度吗?请认真思考半分钟再回答。

我先来回答一下:的确知道,因为我特别关注这块内容,咨询过DBA同学。其他朋友欢迎在评论区留言,大家一起探讨。

为什么会突然提出这样一个问题呢,因为前几天看到一篇文章是讲电商系统中如何优化库存预占能力,文中提到:"经压测数据验证,仅能支撑50次/秒,一旦发生热点商品高频预占,TP99就会飙升,如果高频预占时间较长,会给系统带来稳定性风险,鉴于这种情况必须对预占做一系列优化之类的。"我不禁问自己,当年我们单台数据库好像也能轻松支持1000多的写操作,这篇文章中提到的数据库居然这么脆弱,况且是来源于大厂的案例,硬件肯定不会太草率,一瞬间居然有点怀疑当年DBA给我的信息是否准确。

初步思考

冷静下来思索一番,还是有点收获的,我们当时的业务场景(聚合支付)其实很少有热点数据的更新,比如之前提到的库存预占场景,我们大多数都是INSERT然后根据id做UPDATE,压力被分散到多行,自然吞吐量高,可以拿JAVA中的ConcurrentHashMap和Hashtable来举例,虽然都实现了线程安全,但是前者采用分段锁机制而后者采用共享锁,吞吐量一目了然。

"不同场景的性能指标没有可比性,做系统设计的时候要先考虑场景,不能简单的带入过往的经验"。

上手实验

秉承着没有调查就没有发言权的原则,决定动手测试一番,准备工作很简单:

1.本地搭建mysql,本次选用mysql8.0,调整innodb_buffer_pool_size的大小,直接给6G,innodb_buffer_pool_size感兴趣的请参考终于做了一把MySQL调参boy

2.使用mysql自带的mysqlslap工具进行压测,得到测试报告;

mysqlslap is a diagnostic program designed to emulate client load for a MySQL server and to report the timing of each stage. It works as if multiple clients are accessing the server.

(来自mysql官网介绍https://dev.mysql.com/doc/refman/8.0/en/mysqlslap.html)

3.测试场景模拟100个用户对id=1的商品做10000次数量扣减,测试脚本如下:

 mysqlslap --no-defaults -uroot -proot -P3306  --concurrency=100 --number-of-queries=10000 --create-schema=goods --query="UPDATE `goods`.`goods` SET `cnt` = `cnt`-1 WHERE (`ID` = 1);"

--concurrency指定并发数为100

--number-of-queries指定执行sql语句的次数为10000

--create-schema要测试的目标数据库

--query要执行的sql语句是针对id=1的商品做数量的扣减

4.解读测试报告

执行完10000次查询的的平均时间
Average number of seconds to run all queries: 47.797 seconds
执行完10000次查询的的最小时间
Minimum number of seconds to run all queries: 47.797 seconds
执行完10000次查询的的最大时间
Maximum number of seconds to run all queries: 47.797 seconds
100个客户端执行本次测试
Number of clients running queries: 100
每个客户端执行100次查询
Average number of queries per client: 100

大概估算下每秒能支撑10000/47.707=210次的热点写,比之前提到的50次/秒的确要高一些,但依然是一个数量级,况且我这个测试场景只是单一的模拟热点商品的库存扣减,和真实的业务场景还是有很大差距,综合来讲测试结果符合预期(一开始我也不相信,还发生了一点小插曲,后面会提到)。

这里顺便交代下我pc机的硬件情况:

1.cpu 13th Intel i5-13500H,核心数12,逻辑处理器16,频率2.6 GHz;

2.内存32 GB(5200 MHz)

3.ssd硬盘

测试过程中cpu占用率10%-15%、内存稳定在47%,磁盘写入速度9 MB/秒,平均响应时间3-35毫秒。

小插曲

上一节提到测试出我本地mysql能支持210次/秒的热点写,比之前大厂文章中提到的50次/秒要高出3倍左右,一开始怀疑是mysql版本的问题,我假设大厂应该用的还是更稳定的5.7版本,所以本地又启动了5.7版本的mysql用来测试,谁承想测试结果更让人奔溃。

可以看到吞吐量达到了惊人的10000/2.297=4300次/秒的热点写,快的很假。

我开始对比本地mysql 5.7和8.0之间的参数差异,对比一番以后发现原来5.7版本的binlog默认是关闭的,相当于少了10000次磁盘写,速度当然是非常nice的,到此整个测试之旅算真正结束。

不要做一个拿来主义者,去测试,实践出真知。