实战瓶颈定位-我的MySQL为什么压不上去–写场景
纠结好久要不要写这篇,因为原因非常坑爹,你们基本不会遇到,想了很久觉得思路还是有些价值,所以还是写一下,我尽量简单
背景
继续上文 https://plantegg.github.io/2023/06/20/%E5%AE%9E%E6%88%98%E7%93%B6%E9%A2%88%E5%AE%9A%E4%BD%8D-%E6%88%91%E7%9A%84MySQL%E4%B8%BA%E4%BB%80%E4%B9%88%E5%8E%8B%E4%B8%8D%E4%B8%8A%E5%8E%BB/ ,纯读场景问题解决后,继续压纯写场景,比另外一套类似环境差了很多,大概是2折。
纯写肯定有预期:会有锁、磁盘瓶颈等问题
分析
先看top,结果很明显CPU上不去,并且有一个单核长时间 100%,然后 top -Hp mysqld-pid 展开所有线程,果然一直有一个线程几乎一直 100%,这就太明显了,这个线程遇到了瓶颈,导致整体上不去。
top -Hp mysqld-pid 看到165935 线程一直几乎是 100% 的CPU 状态
所以接下来要搞清楚这个线程在忙什么,刷盘?抢锁?
如果是Java应用就简单了,直接jstack一看就很清楚了,但是MySQLD没这么容易,另外环境里没有 pstack也没法安装,所以这条路走不通。
但是大概率能猜出来和磁盘有点关系,于是iostat -x -d 看看磁盘情况,好家伙果然ioutil 100%,磁盘 IO TPS 好几万。如下nvme0n1是MySQLD 使用的SSD 数据盘,vdb 是OS 系统盘
1 | #iostat -d vdb nvme0n1 3 |
通过 :iostat -x -d vdb nvme0n1 3 可以看到如下图
但这是不是正常情况不好说,于是找到家里同样的环境跑起来(没有单线程 100%问题,QPS 比问题环境高了 5倍),于是也看一下 iostat 做一个对比,对比发现 ioutil 很小,然后磁盘 IO TPS 才我问题环境的30%,在QPS 5倍,IO TPS才 30%的情况下傻子也能看出来这两场景肯定不一样。一个QPS触发的IO TPS差了 15倍了。
不啰嗦,将问题环境的sysbench 脚本复制到正常环境,这下问题重现了,再diff看看两个脚本果然被人改了。问题环境使用的sysbench是别人装的,经过分析后发现里面被改动过一些东西。
之所以一直没有怀疑 sysbench 的问题,也有之前测试只读场景的时候符合预期,所以忽视了sysbench的差异。
这让我想起贝尔实验室Ken Thompson’s “cc hack” 的八卦(有兴趣的同学可以自行查证一下):
当年在贝尔实验室,人们都用Unix系统,但是只有Ken可以绕过密码直接登录,让其他人百思不得其解。按理说整个Unix系统是开源的,很多人检查了系统代码,尤其是登录部分, 并没有发现任何漏洞或者后门。
Ken的同事们不断重新编译Unix, 但是Ken依旧如幽灵一般来去自如。
有人怀疑编译Unix的编译器里面有代码,但是当他们反复检查编译器源码,甚至重新编译c编译器后,依旧没有任何发现。
多年后,在Turing Award Lecture中,Ken终于道出了事情真相,登录源码和编译器源码都是干净的。事实上,这个幽灵般的木马在编译器的可执行文件中。
总结
这里的思路是:单线程100%->磁盘IO TPS非常高->和正常环境对比(常用手段,也要运气好有两个环境可以对比)->一个QPS 对应的IO TPS差异巨大->压测脚本问题
这算是个坑爹的小问题,大家也不会碰到,比网络限速难查多了,网络限速那里我们有放之四海而皆准的 RT 逻辑+抓包,所以很好定位。但是查证分析过程我觉得有一定的参考性,所以记录下。
如果MySQLD能提供一个内部任何一个操作的时间就好了,实际很难实现。当然通过火焰图去看异常偏高的调用是另外一个方向。
跨网络我们有抓包很好界定,但是问题到进程内部的时候反而没了抓包这种一锤定影的工具了