背景:mysql
最近遇到了一個鬱悶的問題:明明OS還有大量的空閒內存,但是卻發生了SWAP,百思不得其解。
先看下SWAP是幹嗎的,瞭解下它的背景知識。
在Linux下,SWAP的做用相似Windows系統下的「虛擬內存」。當物理內存不足時,拿出部分硬盤空間當SWAP分區(虛擬成內存)使用,從而解決內存容量不足的狀況。
SWAP意思是交換,顧名思義,當某進程向OS請求內存發現不足時,OS會把內存中暫時不用的數據交換出去,放在SWAP分區中,這個過程稱爲SWAP OUT。當某進程又須要這些數據且OS發現還有空閒物理內存時,又會把SWAP分區中的數據交換回物理內存中,這個過程稱爲SWAP IN。在vmstat的輸出結果中,分別表現爲 si\so 兩列,以下圖.1web
圖1sql
看到這裏咱們就知道了,發生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)來的痛快(早死晚死都是死,還不如痛快的死,反正很快就能重生,嗯)。數據庫
先介紹完這麼多信息,你們確定已經不耐煩了,咱們就來看看現場並進行排查吧。服務器
首先,看下系統總體的情況,能看出來什麼呢,有幾個關鍵信息:app
系統負載不算高,最近的平均load是6.8;性能
CPU負載也不算高,有大量的空閒,idle爲 98.4%;優化
內存主要分配給mysqld進程,佔用了80.2%;spa
儘管物理內存有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
從上面圖.五、圖.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,推薦此方案。
說到這裏,這個問題已經基本分析清楚了,相關的解決建議也給了,根據本身的狀況去評估選擇哪一個方案便可。