執行docker ps命令掛住問題分析

查找/var/log/messages,發現有錯誤信息:XFS: possible memory allocation deadlock in kmem_alloc (mode:0x250)html

查找linux內核,搜索"kernel: XFS: possible memory allocation deadlock in kmem_alloc (mode:0x250)"linux

發現源代碼以下:算法

void  *
kmem_alloc( size_t  size, xfs_km_flags_t flags)
{
    int     retries = 0;
    gfp_t  lflags = kmem_flags_convert(flags);
    void    *ptr;
 
    do  {
       ptr = kmalloc(size, lflags);
       if  (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
          return  ptr;
       if  (!(++retries % 100))
          xfs_err(NULL,
       "possible memory allocation deadlock in %s (mode:0x%x)" ,
                __func__, lflags);
       congestion_wait(BLK_RW_ASYNC, HZ/50);
    while  (1);
}

分析代碼:docker

  • 當嘗試申請到內存時,直接返回;
  • 申請不到內存會等待HZ/50 的jiffies後,繼續嘗試,直到申請成功纔會退出;
  • 每嘗試申請失敗100次後,會打印possible memory allocation deadlock in %s (mode:0x%x)
  • 說明申請不到內存時,會卡在這裏一直循環下去

mode的含義是所申請的內存標記爲, GFP_IO|GFP_WAIT|GFP_NOWARN,以下ssh


 


結合日誌來看,有很長一段時間都在打印「XFS: possible memory allocation deadlock in kmem_alloc (mode:0x250)」url

以前只是偶爾打印「XFS: possible memory allocation deadlock in kmem_alloc (mode:0x250)」spa

 

用到的文件系統是XFS,查找到一段資料,裏面描述:.net

咱們能夠看到這裏比較大塊的連續的page 是基本沒有的. 由於在xfs 的申請內存操做裏面咱們看到有這種連續的大塊的內存申請的操做的請求, 好比:debug

 

6000:   map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS);

 

所以比較大的多是線上雖然有少許的空閒內存, 可是這些內存很是的碎片, 所以只要有一個稍微大的的連續內存的請求都沒法知足。日誌

因爲已經作了echo 1 > /proc/sys/vm/drop_caches 操做,查看下另外一臺機器的狀況:

 /proc/buddyinfo是linuxbuddy系統管理物理內存的debug信息。

在linux中使用buddy算法解決物理內存的外碎片問題,其把全部空閒的內存,以2的冪次方的形式,分紅11個塊鏈表,分別對應爲一、二、四、八、1六、3二、6四、12八、25六、5十二、1024個頁塊。

而Linux支持NUMA技術,對於NUMA設備,NUMA系統的結點一般是由一組CPU和本地內存組成,每個節點都有相應的本地內存,所以buddyinfo 中的Node0表示節點ID;而每個節點下的內存設備,又能夠劃分爲多個內存區域(zone),所以下面的顯示中,對於Node0的內存,又劃分類DMA、Normal、HighMem區域。然後面則是表示空閒的區域。

此處以Normal區域進行分析,第二列值爲100,表示當前系統中normal區域,可用的連續兩頁的內存大小爲100*2*PAGE_SIZE;第三列值爲52,表示當前系統中normal區域,可用的連續四頁的內存大小爲52*2^2*PAGE_SIZE

cat /proc/buddyinfo 
Node 0, zone      DMA     23     15      4      5      2      3      3      2      3      1      0 
Node 0, zone   Normal    149    100     52     33     23      5     32      8     12      2     59 
Node 0, zone  HighMem     11     21     23     49     29     15      8     16     12      2    142 

 

能夠看到從第5列開始,只剩下44*16*PAGE_SIZE的頁塊,後面剩下的分別是1 * 32 *PAGE_SIZE, 1 * 64 *PAGE_SIZE, 2 *128 * PAGE_SIZE,剩下256,512的頁塊都沒有了

 

所以推測,致使這個問題出現的時候,該機器的內存碎片不少,當某個應用執行時,在xfs 的申請內存中有這種連續的大塊的內存申請的操做的請求, 好比:

 

6000:   map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS);

就會致使內存一直分配不到。例如執行docker ps,docker exec這些命令時,會一直阻塞在kmem_alloc的循環中,反覆申請內存,因爲內存碎片沒有被組合,所以就一直申請不到,執行這些命令也會卡住,這也就驗證了執行某些命令如ls,ssh都不會失敗(由於須要內存的PAGE不是那麼大)。

而執行echo 1 > /proc/sys/vm/drop_caches 操做會把碎片化的PAGE從新分配,以後在申請大塊的PAGE內存就能夠申請到,不阻塞了。

然而不能老是輸入這個命令解決問題,因而找到了下面的方法:

 

參考

http://www.cnblogs.com/itfriend/archive/2011/12/14/2287160.html

Linux 提供了這樣一個參數min_free_kbytes,用來肯定系統開始回收內存的閥值,控制系統的空閒內存。值越高,內核越早開始回收內存,空閒內存越高。

設置/proc/sys/vm/min_free_kbytes的值爲4G bytes

echo 4194304 > /proc/sys/vm/min_free_kbytes

目前爲90M bytes:

執行後的效果:

 

查看內存碎片狀況,發現有明顯改善。

 

按此方法修改後,再沒有出現docker ps命令掛住的現象。

相關文章
相關標籤/搜索