0、導讀
MySQL資料庫伺服器發生SWAP相信很多人都遇到過,如何找出元兇,又如何應對呢?
1、寫在前面
在昨晚的知數堂公開課中,其實用的就是本次的案例。本次公開課的PPT、視訊已上傳到百度雲盤,連結:
https://pan.baidu.com/s/1eR53Qd8,
關于知數堂
http://zhishuedu.com
“知數堂教育訓練”是由資深MySQL專家葉金榮、吳炳錫聯合推出專業優質線上教育訓練課程,主要有MySQL DBA實戰優化和Python運維開發兩個課程,是業内最有良心、最有品質的教育訓練課程。
2、問題交代
我的朋友小芳(這次不是小明了,hoho),最近遇到了一個郁悶的問題:明明OS還有大量的空閑記憶體,可是卻發生了SWAP,百思不得其解,她就來找我搬救兵了(嗯,我可不是🐒派來的)。
先看下SWAP是幹嘛的,了解下它的背景知識。
在Linux下,SWAP的作用類似Windows系統下的“虛拟記憶體”。當實體記憶體不足時,拿出部分硬碟空間當SWAP分區(虛拟成記憶體)使用,進而解決記憶體容量不足的情況。
SWAP意思是交換,顧名思義,當某程序向OS請求記憶體發現不足時,OS會把記憶體中暫時不用的資料交換出去,放在SWAP分區中,這個過程稱為SWAP OUT。當某程序又需要這些資料且OS發現還有空閑實體記憶體時,又會把SWAP分區中的資料交換回實體記憶體中,這個過程稱為SWAP IN。在vmstat的輸出結果中,分别表現為 si\so 兩列,如下圖.1
圖1
看到這裡我們就知道了,發生SWAP的最直接可能的原因是程序向OS申請記憶體時,發現實體記憶體不足,當沒有SWAP可用的話,這時可能會一直等待,也可能會觸發OOM-killer機制,OS把消耗記憶體最多的那個程序kill掉以釋放記憶體,這個選擇取決于核心參數 vm.swappiness。該參數可選範圍從 0 - 100,設為 0 就是希望最大限度使用實體記憶體,盡量不使用swap,設為 100 則是希望積極使用swap。在運作資料庫程序的伺服器上,我們通常強烈建議這個值小于等于10,最好是設定為 0。原因很簡單,對資料庫這種需要集中CPU資源、大記憶體、高I/O的程式而言,如果用SWAP分區代替記憶體,那資料庫服務性能将是不可接受的,還不如直接被OOM kill(資料庫程序通常占用最多記憶體,最容易被OOM kill)來的痛快(早死晚死都是死,還不如痛快的死,反正很快就能重生,嗯)。
先介紹完這麼多資訊,大家肯定已經不耐煩了,我們就來看看現場并進行排查吧。
3、現場排查
首先,看下系統整體的狀況,如下圖.2所示
圖2
從上圖能看出來什麼呢,有幾個關鍵資訊:
- 系統負載不算高,最近的平均load是6.8;
- CPU負載也不算高,有大量的空閑,idle為 98.4%;
- 記憶體主要配置設定給mysqld程序,占用了80.2%;
- 盡管實體記憶體有256G,空閑的也将近39G,但确實發生swap了,并且把SWAP都耗盡了。
得到第一個排查結果:實體記憶體還有不少空閑,但卻把swap都耗盡了。作為一個有經驗的DBA,遇到這種情況第一反應是什麼呢?嗯,先不點破,繼續往下看。
再執行 free -gt 檢視記憶體、SWAP消耗情況,如下圖.3所示
圖3
看出來了吧,尤其是參加過
知數堂教育訓練MySQL DBA優化班課程的同學應該都知道,我們在課上多次強調:遇到這種情況,第一條件反射很直接就是:發生記憶體洩露(memory leak)了。
一般來說,如果發現記憶體統計結果中,cached 和 used 相差特别大的話,基本可确定系統發生記憶體洩露。相應的處理手法有:
- 治标的辦法:擇機重新開機程序,徹底釋放記憶體歸還給OS;
- 治本的辦法:找到代碼中導緻洩露的代碼,修複之(我們這次面對的是mysql代碼,還是去官方送出bug吧,哈哈);
- 治本的辦法:更新程式版本,通常新版本會解決舊版本存在的問題,推薦此方案。
再看下MySQL中記憶體相關選項怎麼配置的:
圖4
除了 innodb-buffer-pool 配置設定的稍微多一些外,其他的還算正常。看了下,MySQL的版本是 5.6.19,看來是有必要更新到5.6系列的最新版本。
到這裡,我們得到第二個排查結果:mysqld程序發生記憶體洩露,建議擇機重新開機程序,并盡快安排更新到最新版本。
然而,僅僅是因為mysqld程序記憶體洩露導緻的SWAP嗎,貌似不全然?還記得上面我們有個地方還沒點破的不:實體記憶體還有不少空閑,但把swap都耗盡了。同樣滴,這種案例在我們知數堂的MySQL DBA教育訓練課程裡也被多次談及,絕大多數情況是因為沒有關閉NUMA引起的。在運作資料庫程序的伺服器上,強烈建議關閉NUMA,在之前的分享
比較全面的MySQL優化參考(上篇)中也有提及。我們接着來看下NUMA的狀況:
圖5
圖6
從上面圖.5、圖.6可見,NUMA問題導緻其中一個CPU可配置設定的記憶體遠小于另一個(1.8G vs 38G),那麼這個CPU上如果要申請大記憶體時,顯然不夠了,是以發生SWAP。關于NUMA的相關背景知識我這裡不贅述。
是以,我們得到第三個排查結果:由于伺服器硬體、系統設定不當,沒有關閉NUMA,導緻發生SWAP。建議方案有:
- 在BIOS設定層面關閉NUMA,缺點是需要重新開機OS;
- 或修改GRUB配置檔案,缺點也是要重新開機OS;
- 更新MySQL版本到5.6.27及以後,新增了一個選項 innodb_numa_interleave,隻需要重新開機mysqld執行個體,無需重新開機OS,推薦此方案。
說到這裡,這個問題已經基本分析清楚了,相關的解決建議也給了,根據自己的情況去評估選擇哪個方案即可。
4、寫在最後
類似的案例發生也不是一次兩次了,我肯定以後還會繼續存在,看完案例的的同學也沒辦法立刻把所有伺服器上的NUMA政策全部修整過來,或者可能沖動一下想修複,但過幾天就又給忘光了。
老葉曾多次在各種場合不厭其煩地強調一些基礎的MySQL運維、開發規範,也正是因為看到了其實還有不少此類問題的存在。這些基礎的規範都沒執行到位的話,早晚是有一天要去填坑的,不管是填自己的挖下的坑,還是前人留下的坑,哈哈。