破产码农
IT圈最会讲故事的网红·南山彭于晏前面的文章已经展示了MySQL8.0的能力,96逻辑CPU下能跑出万的QPS。这时MySQL实例占用约58个逻辑核,约2.4WQPS/Core。IMG群的同学在做类似测试时,发现他的MySQL8.0却始终只能跑在不到50万QPS。通过姜老师的复盘,最终定位了问题,性能从40万提升为了万QPS。今天就来带给大家这次错综复杂的性能调优之旅。1
版本选择
这次测试的版本是最新发布的MySQL8.0.24版本。直接使用的是编译好的LinuxGeneric通用版本:mysql-8.0.24-linux-glibc2.12-x86_64.tar.xz很多同学“迷信”从源码自己手工编译MySQL,从而获得性能的提升。其实手工编译完全没有必要,是错误的一种执念。试想下Oracle、MicrosoftSQLServer是不是都是给的二进制安装包?难道他们的性能在不同服务器上会有很大的差别么?你要明白,最终都是将代码逻辑编译成最底层的CPU执行命令,所以不会有本质的差别。2
都是他惹的祸
接下来,我们进入到测试流程。这台服务器的硬件与之前的完全一样,操作系统安装的是CentOS7,内核版本3.10。这时通过我们的测试程序my_test进行主键的查询测试,会发现QPS被限制在了42W左右的QPS。而之前我们的测试一直是可以达到万的QPS。这时通过命令TOP观察CPU负载,会发现CPU使用率为62个逻辑核,比之前的还要高。但是,QPS反而大幅地下降。若仔细观察,会发现CPU使用率中,sys的使用率及其高,竟然达到了52.3%!!!有了这个线索之后,再要定位问题就非常简单了。再次祭出命令perf。通过perftop-G-p`pidofmysqld`定位出在测试过程中MySQL消耗最多CPU的函数是哪个。最终我们定位到了如下这个函数:可以发现发现这里MySQL调用了函数ppoll,占用了73.68%的CPU使用率。但我记得之前MySQLviosocket网络模块用的是poll,接着去MySQLworklog翻看官方工作日志。然而,并没有找到任何相关信息:接着,在github上搜索提交日志。这次终于找到了对应的代码修改信息。看来是Facebook提交的修复补丁:看了下,当前MySQL5.7并没有合并这个修复!!!接着大致扫了下源码,MySQL8.0用ppoll替换poll,用于安全捕获某些信号,这是常见的逻辑。所以,我并不认为MySQL8.0的修复存在太大问题。要再排查问题,就需要查看Linux内核了。这时我在Github上Linux的源码库中搜索:_raw_spin_lock_irqhighcpu这时终于定位到了问题的原因:原来这是操作系统的内核Bug!!!即:在多核CPU,高负载的数据库业务场景情况下,系统函数sigprocmask的自旋锁竞争会占用大量CPU时间。这个Bug在4.10版本就被修复,但我们的操作系统还停留在3.10版本。所以,要解决这个问题,要么根据Linux源码中的对signal.c进行内核修复并重新编译,或直接将操作系统升级到不低于4.10的版本。当然,也可以直接修改MySQL源码,牺牲ppoll的安全信号等待特性,退化为之前5.7的方式。修改MySQL8.0的源码violite.h:这样的话,仅在内核4.10版本及以上时,才会使用ppoll。编译后再进行测试,这时MySQL性能就能恢复到先前的百万QPS水准了:4
看视频,更直接
视频编辑超级累,看完记得点赞哦!!!3
总结
这个操作系统Bug5年前就已修复,但其极大影响了MySQL8.0的性能。然而,该Bug对MySQL5.7版本又毫无影响。可以说,藏得非常深。也是第一次真正遇到操作系统系统内核Bug直接影响数据库性能。因此,姜老师强烈建议:若你使用/升级MySQL8.0版本,务必确认自己的操作系统内核版本已经升级到4.10版本。否则,你的MySQL8.0体验可能是非常糟糕的。甚至可能让你痛不欲生~~~~看完这篇文章,你还有什么疑问呢?欢迎留言讨论哦~~~直播预告
每周五、六,不定期直播,分享技术干货IMG群是码农的交流社区,IMG