1. 程式人生 > >[轉]找到MySQL發生swap的原因

[轉]找到MySQL發生swap的原因

比較 linux下 nes 進程 col 系列 sql load 知識

背景:

最近遇到了一個郁悶的問題:明明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(查看vm.swappiness = 10),最好是設置為 0。原因很簡單,對數據庫這種需要集中CPU資源、大內存、高I/O的程序而言,如果用SWAP分區代替內存,那數據庫服務性能將是不可接受的,還不如直接被OOM kill(數據庫進程通常占用最多內存,最容易被OOM kill)來的痛快(早死晚死都是死,還不如痛快的死,反正很快就能重生,嗯)。

先介紹完這麽多信息,大家肯定已經不耐煩了,我們就來看看現場並進行排查吧。

現場排查

首先,看下系統整體的狀況,能看出來什麽呢,有幾個關鍵信息:

  • 系統負載不算高,最近的平均load是6.8;

  • CPU負載也不算高,有大量的空閑,idle為 98.4%;

  • 內存主要分配給mysqld進程,占用了80.2%;

  • 盡管物理內存有256G,空閑的也將近39G,但確實發生swap了,並且把SWAP都耗盡了。

得到第一個排查結果:物理內存還有不少空閑,但卻把swap都耗盡了。作為一個有經驗的DBA,遇到這種情況第一反應是什麽呢?嗯,先不點破,繼續往下看。

再執行 free -gt 查看內存、SWAP消耗情況,如下圖.3所示

技術分享
圖3

看出來了吧:遇到這種情況,第一條件反射很直接就是:發生內存泄露(memory leak)了。

一般來說,如果發現內存統計結果中,cached 和 used 相差特別大的話,基本可確定系統發生內存泄露。相應的處理手法有:

  • 治標的辦法:擇機重啟進程,徹底釋放內存歸還給OS;

  • 治本的辦法:找到代碼中導致泄露的代碼,修復之(我們這次面對的是mysql代碼,還是去官方提交bug吧,哈哈);

  • 治本的辦法:升級程序版本,通常新版本會解決舊版本存在的問題,推薦此方案。

再看下MySQL中內存相關選項怎麽配置的:

技術分享
圖4

除了 innodb-buffer-pool 分配的稍微多一些外,其他的還算正常。看了下,MySQL的版本是 5.6.19,看來是有必要升級到5.6系列的最新版本。

到這裏,我們得到第二個排查結果:mysqld進程發生內存泄露,建議擇機重啟進程,並盡快安排升級到最新版本。

然而,僅僅是因為mysqld進程內存泄露導致的SWAP嗎,貌似不全然?還記得上面我們有個地方還沒點破的不:物理內存還有不少空閑,但把swap都耗盡了。絕大多數情況是因為沒有關閉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,推薦此方案。

說到這裏,這個問題已經基本分析清楚了,相關的解決建議也給了,根據自己的情況去評估選擇哪個方案即可。

[轉]找到MySQL發生swap的原因