前面的文章已經展示了 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 體驗可能是非常糟糕的,
甚至可能讓你痛不欲生~~~~
看完這篇文章,你還有什么疑問呢?歡迎留言討論哦~~~
嗯,非常正確
就那樣,剛用的時候很新奇,提升5倍就夸張了。