注意了!這個遠古Bug,讓你的 MySQL 8.0 性能下降2倍!

前面的文章已經展示了 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 體驗可能是非常糟糕的,

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

看完這篇文章,你還有什么疑問呢?歡迎留言討論哦~~~

2 条回复 A文章作者 M管理員
  1. 嗯,非常正確

  2. 就那樣,剛用的時候很新奇,提升5倍就夸張了。