數據庫

MySQL訪問行更新慢、用戶線程大量堆積竟是因為它

1 問題現象


最近,騰訊云某內部系統不定期出現數據庫訪問行更新慢,數據庫用戶線程大量堆積的現象。從slow log中觀察,大量update執行時間超過10秒,甚至個別update執行時間超過百秒,這已經嚴重影響該系統的正常運行。

運維同學不得不采取殺死運行session的方式解決該問題,由于訪問數據庫的任務是離線后臺批處理任務,因此會選擇業務壓力小的時候運行該任務,比如半夜12點,因此,運維同學必須半夜采取緊急措施,這給線上運行造成極大的負擔。

2 問題分析


2.1 山重水復

根據運維同學反饋,數據庫是不定期出現慢查詢的現象,懷疑數據庫可能存在死鎖問題。由于問題復現的不確定性,因此在線上實例寫腳本抓現場:當問題出現時,記錄下innodb引擎狀態(show innodb status)、用戶線程狀態,innodb引擎狀態信息中存在死鎖信息。遺憾的是,通過對innodb status分析,發現LATEST DETECTED DEADLOCK中不存在死鎖問題,初步排除偶發死鎖導致問題的可能,只能從業務模型角度尋找思路。

2.2 峰會路轉

通過與業務系統開發、運維人員的溝通,發現有三個業務子系統會訪問該數據庫,這三個子系統訪問模式類似,整理該業務模型如下圖所示:

每一個離線請求都會觸發上述流程,對同一個id的行短時間內有多次更新,如果等鎖超時會重試,會重試十次。在極端場景,疊加重試請求,會有2000+線程同時更新數據庫,造成大量連接等待現象。對熱點行更新會加行鎖,行鎖在事務提交時釋放,釋放后喚醒其他線程繼續更新,正常情況下熱點行更新會降低數據庫吞吐但不會產生數十秒的事務等待,因此懷疑加鎖、釋放鎖、喚醒其他線程的某些環節有問題,導致大并發的極端情況下數據庫性能嚴重下降。

2.3 柳暗花明

由于抽象出了出問題時的業務模型,按照該業務模型基本可以復現問題,因此搭建線下環境,用pt-pmp、perf等工具分析數據庫問題。經過對pt-pmp仔細分析,發現部分線程等待異常,如下圖所示:

上圖中1442個線程等待喚醒,這個是正常的,但有圖上標出的2組異常線程:

  • 233個線程等待lock_wait_suspend_thread中的lock_wait_table_release_slot的入口mutex上
  • 181個線程等待lock_wait_suspend_thread本身的mutex上。

經過代碼分析,這兩個mutex為lock_wait_mutex_enter(),這把鎖出現在兩個地方中:

  • 用戶線程調用的lock_wait_suspend_thread
  • 后臺線程:lock_wait_timeout_thread

lock_wait_suspend_thread函數讓所有調用線程進入suspend狀態,掛起。當熱點行更新時,只有一個線程更新其他所有線程都掛起等待行鎖,因此在熱點行更新時,這個函數是熱點。圖中的1442個線程就是在等待行鎖喚醒。

lock_wait_timeout_thread是鎖超時監測線程,監測是否有線程等鎖超時,該線程會掃描每一個由lock_wait_suspend_thread進入等待的線程,判斷其是否超時,如果有超時,喚醒。觸發機制有2種:

  • 每秒定時觸發
  • lock_wait_suspend_thread通知觸發,這個就是熱點行更新慢的關鍵!

lock_wait_suspend_thread與lock_wait_timeout_thread關系如下圖所示:

每增加n個進入等待進程,其中的每一個進程都會觸發一次lock_wait_timeout_thread,而每一次lock_wait_timeout_thread調用都會對m個已經掛起線程持鎖掃描,這樣多出n * m次持鎖掃描。由于持鎖掃描會進一步加劇用戶線程等待在lock_wait_suspend_thread入口鎖lock_wait_mutex_enter()的等待,造成更多觸發lock_wait_timeout_thread線程的機會,單次運lock_wait_timeout_thread時間增加,那個進入惡性循環,所有線程都在爭奪lock_wait_mutex_enter()鎖。

3 問題解決



阻斷lock_wait_suspend_thread 對lock_wait_timeout_thread觸發,如下圖所示:lock_wait_suspend_thread 對lock_wait_timeout_thread的調用,是用來加速監測鎖超時等待的,去掉該調用,減少大壓力并發的熱點行更新對lock_wait_timeout_thread的調用,進而減小lock_wait_suspend_thread 鎖等待,進而消除熱點。

4 結果


業務模擬工具按照線上業務模型,模擬線上運行2000個業務請求同時進行,每秒每個請求更新一次,分析每個訪問的執行時間(對binlog掃面得到執行時間(exec_time)得出執行時間)
用模擬業務的測試工具對改前、改后版本進行測試,結果如下:執行時間5.6優化前5.6優化后

所有696832460
1-91504(占比21.6%)802(2.47%)
>1012(占比0.17%)0

從效果上看,優化后的熱點基本消失,5.6延遲(1-9s)的占比,優化后是優化前的十分之一,基本解決熱點問題。查看ptpmp堆棧如下所示:

由圖可見,大部分線程被掛起,等在lock_wait_suspend_thread上的slot->event上面,這是一個正常的行為。之前的熱點消失,只有5個線程等在入口鎖上面。該修復隨著最新的txsql 5.6發布線上,經過近一個月的線上運行,騰訊云的線上業務沒有再出現更新慢的問題,基本確認問題已經解決。

我還沒有學會寫個人說明!

如何熟悉一個系統?(內含知識大圖)

上一篇

大咖說:出道十五載,認知五迭代

下一篇

你也可能喜歡

MySQL訪問行更新慢、用戶線程大量堆積竟是因為它

長按儲存圖像,分享給朋友

ITPUB 每周精要將以郵件的形式發放至您的郵箱


微信掃一掃

微信掃一掃
30岁的男人干啥赚钱快赚钱多