前面的文章已经展示了 MySQL 8.0 的能力,96逻辑CPU下能跑出140万的 QPS 。

这时MySQL实例占用约58个逻辑核,约2.4W QPS / Core 。

IMG群的同学在做类似测试时,发现他的MySQL 8.0却始终只能跑在不到50万 QPS。

通过姜老师的复盘,最终定位了问题,性能从40万提升为了140万 QPS

今天就来带给大家这次错综复杂的性能调优之旅。

这次测试的版本是最新发布的 MySQL 8.0.24 版本。

直接使用的是编译好的Linux Generic通用版本:mysql-8.0.24-linux-glibc2.12-x86_64.tar.xz

打开网易新闻 查看精彩图片

很多同学“迷信”从源码自己手工编译MySQL,从而获得性能的提升。

其实手工编译完全没有必要,是错误的一种执念

试想下Oracle、Microsoft SQL Server是不是都是给的二进制安装包?

难道他们的性能在不同服务器上会有很大的差别么?

你要明白,最终都是将代码逻辑编译成最底层的CPU执行命令,所以不会有本质的差别。

接下来,我们进入到测试流程。

这台服务器的硬件与之前的完全一样,操作系统安装的是 CentOS 7 ,内核版本3.10。

这时通过我们的测试程序my_test进行主键的查询测试,会发现QPS被限制在了42W左右的 QPS 。

而之前我们的测试一直是可以达到140万的 QPS 。

打开网易新闻 查看精彩图片

这时通过命令TOP观察CPU负载,会发现CPU使用率为62个逻辑核,比之前的还要高。

但是,QPS 反而大幅地下降。

若仔细观察,会发现CPU使用率中,sys的使用率极其高,竟然达到了52.3%!!!

打开网易新闻 查看精彩图片

有了这个线索之后,再要定位问题就非常简单了。

再次祭出命令perf。

通过perf top -G -p `pidof mysqld`定位出在测试过程中MySQL消耗最多CPU的函数是哪个。

最终我们定位到了如下这个函数:

打开网易新闻 查看精彩图片

可以发现这里MySQL调用了函数ppoll,占用了73.68%的CPU使用率。

但我记得之前MySQL viosocket网络模块用的是 poll ,接着去 MySQL worklog 去翻看工作日志。

然而,并没有找到任何相关信息:

打开网易新闻 查看精彩图片

接着,在github上搜索提交日志。

这次终于找到了对应的代码修改信息。

看来是Facebook提交的修复补丁:

打开网易新闻 查看精彩图片

看了下,当前MySQL 5.7并没有合并这个修复。

接着大致扫了下源码,MySQL 8.0 用 ppoll 替换 poll ,用于安全捕获某些信号,这是常见的逻辑。

所以,我并不认为 MySQL 8.0 的修复存在太大问题。

要再排查问题,就需要查看Linux内核了。

这时我在Github上Linux的源码库中搜索:_raw_spin_lock_irq high cpu

这时终于定位到了问题的原因:

打开网易新闻 查看精彩图片

原来这是操作系统的内核Bug!!!

即:在多核CPU,高负载的数据库业务场景情况下,系统函数sigprocmask的自旋锁竞争会占用大量CPU时间

这个 Bug 在 4.10 版本就被修复了,但我们的操作系统是 3.10 版本。

所以,要解决这个问题,要么根据Linux源码中的对signal.c进行内核修复并重新编译,或直接将操作系统升级到不低于4.10的版本。

当然,也可以直接修改MySQL源码,牺牲ppoll的安全信号等待特性,退化为之前5.7的方式。

修改 MySQL 8.0 的源码violite.h:

打开网易新闻 查看精彩图片

这样的话,仅在内核 4.10 版本及以上时,才会使用 ppoll。

编译后再进行测试,这时 MySQL 性能就能恢复到先前的百万 QPS 水准了:

打开网易新闻 查看精彩图片

这个操作系统 Bug 5年前就已修复,但其极大影响了 MySQL 8.0 的性能。

然而,该Bug对 MySQL 5.7 版本又毫无影响。

可以说,藏得非常深。

也是第一次真正遇到操作系统系统内核 Bug 直接影响数据库性能。

因此,姜老师强烈建议:若你使用/升级 MySQL 8.0 版本,务必确认自己的操作系统内核版本已经升级到4.10版本

否则,你的 MySQL 8.0 体验可能是非常糟糕的。

甚至可能让你痛不欲生~~~~

看完这篇文章,你还有什么疑问呢?欢迎留言讨论哦~~~