一、問題描述:
存儲節點中 used 內存使用量遠高于進程占用的內存,此時系統 used 內存占用了96G,used內存應約等于 /proc/meminfo 中統計的 AnonPages、SReclaimable、KernelStack及PageTables總和,計算后發現后者總和約為22G ,與 used內存差距過大,故需分析該現象出現的原因。其中AnonPages 16.66G約等于進程占用的內存(RSS)總和 17.13G。
二、結論:
used內存占用率高,是由于ceph相關的進程ceph-osd 下的tp_osd_tp線程頻繁進行getdents、stat、openat等系統調用,導致內存中緩存了很多xfs_buf。當系統內存充足時,只能通過主動執行 "echo 2 > /proc/sys/vm/drop_caches " 命令觸發系統回收一直未被使用的 xfs_buf,當系統內存較低時,系統通過喚醒后臺異步回收 kswapd 內核線程回收該緩存。
三、問題分析過程:
通過內核提供的接口主動進行回收,觀察系統 used 內存是否能被回收。
系統最初 used 內存有 41G,通過 echo 2 > /proc/sys/vm/drop_caches 后,系統 used 內存從 41G 降到了 29G,因此可知系統可回收內存大部分是slab。
- 確認 slab 中具體占用內存的位置
跟蹤 echo 2 > /proc/sys/vm/drop_caches 時觸發的回收流程,發現大部分回收發生在 xfs_buftarg_shrink 函數調用中。
因此,首先查看 xfs_buftarg_shrink 函數中回收的內存總量,在跟蹤過程中,系統 used 內存從 40G 降到了 29G。
而 xfs_buftarg_shrink 函數在該過程中大約釋放了 3037466 頁 4k 頁面,即回收了約 11G 內存,與前面計算的系統內存減少了 11G 匹配。因此,系統 used 內存中絕大部分都是 xfs_buf。
由上文可知,xfs_buf 占用了大量內存,因此我們需要跟蹤 xfs_buf 分配的內存量是否和系統 used 內存增長量一致。在跟蹤過程中,系統 used 內存從 50G 增長到了 55G,而 xfs_buf 共分配了 4.68G,故 xfs_buf 分配的內存量 與 系統 used 內存增量基本一致。
通過上述跟蹤,可以得出:系統used內存增量與xfs_buf內存使用量基本一致,主動回收內存時,系統used內存減少量與xfs_buf緩存回收量基本一致。故系統used內存持續增長是由于大量的xfs_buf緩存導致。
- xfs_buf 分配請求的主要來源
通過上述跟蹤,可以知道 tp_osd_tp 線程一直在請求分配 xfs_buf。
其次,跟蹤xfs_buf分配過程的調用棧,發現xfs_buf分配請求集中在打開文件openat 、統計文件信息stat、讀取目錄getdents等過程中,主要是ceph相關的進程對文件的操作導致的used內存持續增加。
- ceph-osd 服務分配 xfs_buf 的速度及對內存的影響
首先跟蹤關掉 ceph-osd 服務后,系統在15分鐘內 xfs_buf 分配請求的數量,發現分配請求均來自于titanagent 3785880線程,其在15分鐘內共請求分配了6個xfs_buf,并不能使得系統內存顯著增長。
開啟ceph-osd服務后,統計發現系統在15分鐘內分配了 82554 個xfs_buf,系統內存也從 21G增長到了 25G。
綜上,ceph-osd服務開啟后,xfs_buf分配速度從原來的15分鐘內分配6個提升到了82554個,系統內存使用量顯著增多。
4、xfs_buf的回收機制
查看代碼發現 xfs_buf 最終通過調用 xfs_buf_rele 函數來釋放緩存的 xfs_buf,其通過判斷 xfs_buf 的引用計數是否為 0 來決定是否直接回收內存,如果引用計數為 0,則直接回收內存,反之,則將 xfs_buf 放回到xfs lru 鏈表中,等回收流程被觸發時再被回收。
xfs_buf緩存回收有以下四種路徑:
(1)xfs_buf映射磁盤文件時,磁盤文件丟失或內存不足,直接回收 xfs_buf;
(2) xfs log 已經回寫到磁盤了,此時緩存 log 的xfs_buf可直接被回收;
(3)系統空閑內存充足時,用戶通過“echo 2 > /proc/sys/vm/drop_caches”方式主動觸發回收流程;
(4)系統空閑內存不足時,內核后臺異步回收線程kswapd被喚醒,回收xfs_buf對應的緩存。如下所示,系統空閑內存只有3.6G 時,內核線程 kswapd 主動進行內存回收。
當tp_osd_tp 線程執行getdents、stat、openat等系統調用時,xfs_buf 被成功映射相應的內容后,其引用計數大于0,故被放入xfs lru鏈表中,等待上述回收路徑中的(3)或者(4)被觸發時,方能被回收釋放內存。