如何控制Linux清理cache機制?

我有一台線上伺服器, 上面有IO密集型服務, 平時基本把cache打滿的狀態. (內存使用率99%, 大部分為cache)

但是, 這台伺服器有時在白天業務高峰時, 突然操作系統cache被清理了很大一部分 (內存使用率降到50%左右, cache基本都沒有了), 導致大量缺頁和換頁, IO飆升, 從而影響服務性能.

我知道可以通過echo 3 &> /proc/sys/vm/drop_caches 來手工觸發cache的清理. 但是, 我查了一下操作日誌沒有找到相關操作. 我不清楚還有什麼情況會自動觸發cache的如此大規模清理.

如果自動大規模清理cache這個操作是操作系統自己完成的, 有沒有什麼機制可以控制它呢? 比如, 我想讓操作系統在白天業務高峰時段禁止做清理cache, 到晚上業務低谷時我們自己手工觸發.


那我來自己回答一下吧. 後來我已經找到原因了.

先說結論: 內存突降的原因是因為內存碎片過多, 內核發生了memory compaction

整個分析過程

首先, 我對伺服器出現問題的時間點前後的sar日誌進行了分析.
當時得到的現象是這樣子的:

  1. 分析內存變化情況(使用sar -r), 發現內存突降, 而且突降之後, 系統的內存並沒有馬上回升, 而是維持在一個低位很久
  2. 同時, 觀察到內存低位, 系統卡頓這段時間的換頁和swap情況 (使用sar -B -S), 發現:
  • pageout數據基本沒有變化
  • 沒有大量的swap換進換出操作
  • pagein這時候突增, 並且維持在高位, major fault突增
  • pgscank 這個數值保持高位, %vmeff 保持在100%.

其中, paging的信息給了我線索. 通過查資料, 發現pgscank表示的是Linux當中的負責內存回收的線程kswapd掃描的頁的數量, 而%vmeff表示被kswapd掃描的頁當中, 有多少頁的數據被踢出去了換成其他頁數據了(這個有個術語叫page steal, 在sar -B裡面的pgsteal/s就表示這個值) .
這說明當時, 應該是kswapd自身觸發了內存的突降, 並且它在不斷掃面現有的page, 並換入新的page.

此時, 其實還是沒有實質性進展. 直到有一次, 我們幸運地正好遇到了內存突降的時間窗口. 於是我們趕緊上線分析

  • 使用sar -r 和 sar -B -S 和之前的現象一致
  • 查看top, 我發現系統kswapd的線程CPU佔用率100%, 說明當時kswapd在不停努力工作中, 這個和之前的分析相吻合
  • 然後, 直接查看kswapd進程對應的函數調用的時間佔比, (使用perf top), 這時候, 我發現了原因, 此時kswapd線程大部分時間都在做compact memory !

然後我進一步看了一下memory compaction的觸發條件, 主要是Linux內存分配使用的buddy algorithm 在新分配內存一個較大的內存時, 找不到符合條件的連續頁, 於是觸發了memory compaction. 這個可以通過cat /proc/buddyinfo 進行查看.

解決方法

那剩下的問題就是如何限制系統減少出現memory compaction的概率. 查閱資料後, 發現Linux有一個參數是控制這個的: /proc/sys/vm/extfrag_threshold

這個參數是一個0 ~ 1000的整數. 如果出現內存不夠用的情況, Linux會為當前系統的內存碎片情況打一個分, 如果超過了extfrag_threshold這個值, kswapd就會觸發memory compaction . 所以, 這個值設置接近1000, 說明系統在內存碎片的處理傾向於把舊的頁換出, 以符合申請的需要; 而設置接近0, 表示系統在內存碎片的處理傾向於做memory compaction.

由於這台機器在做memory compaction的時候對性能造成的影響太大, 於是我把extfrag_threshold這個值從系統默認的500設置到了最大1000 設置完了之後, 這台機器就再也沒出現過類似問題, 問題解決.

剩下的疑問

我只是通過現象觀察到做memory compaction的時候系統IO增高, 但是我還是不是很理解為什麼做memory compaction會涉及到大量的pagein操作, 並且維持時間如此之久?

其他說明

如果真的出現了memory compaction, 導致系統卡頓的情況, 可以通過下面2步手工縮短處理過程:

echo 1 &> /proc/sys/vm/drop_caches
echo 1 &> /proc/sys/vm/compact_memory

這個實質就是減少memory compaction的內存總量, 然後手工去整理. 測試發現效果不錯

參考

  • http://ftp.dei.uc.pt/pub/linux/kernel/people/andrea/patches/v2.6/2.6.34/transparent_hugepage-24/memory-compaction-extfrag_threshold
  • https://serverfault.com/a/746067
  • https://www.kernel.org/doc/Documentation/sysctl/vm.txt


1 Linux下內存佔用多的原因

當linux第一次讀取一個文件運行時,一份放到一片內存中cache起來,另一份放入運行程序的內存中,正常運行,當程序運行完,關閉了,cache中的那一分卻沒有釋放,第二次運行的時候,系統先看看在內存中是否有一地次運行時存起來的cache中的副本,如果有的話,直接從內存中讀取,那樣,速度就快多了。

說明這種情況的很典型的例子是啟動firefox,由於firefox程序很大,因此第一次讀取運行的時候很慢,尤其在速度不快的機器上,但是當你徹底關閉了firefox,ps看不到一個firefox進程,第二次再啟動的時候就比第一次明顯快很多,這是由於這次系統是直接從cache中讀取的firefox來運行,並不是從磁碟上讀取的。

再有一個例子:我們頻繁使用的ls命令等基本命令,你運行的時候根本看不到硬碟燈閃,因為這些常用的命令都是再第一次運行後就保存在cache中的,以後就一直從內存中讀出來運行。

如果cache佔用的內存過多了,影響正常運行程序需要的內存,那麼會釋放掉一部分cache內存,但是總量會保持一個很高的值,所以,linux總是能最大限度的使用內存,就算加到16G,32G內存,也會隨著不斷的IO操作,內存的free值會慢慢減少到只有幾M,想要內存不發生這種情況,只有一個辦法:把內存加到比硬碟大。

2 手動釋放方法

2.1 使用free查看一下當前內存使用情況(可略過):

[root@*** ~]# free -m

total used free shared buffers cached

Mem: 512 488 23 0 57 157

-/+ buffers/cache: 273 238 Swap: 1055 0 10552.2 執行sync同步數據

[root@*** ~]# sync2.3 清理cache

[root@*** ~]#echo 3 &> /proc/sys/vm/drop_caches2.4 drop_cache的詳細文檔如下,以便查閱

Writing to this will cause the kernel to drop clean caches, dentries and inodes from memory, causing that memory to become free.

To free pagecache:

* echo 1 &> /proc/sys/vm/drop_caches

To free dentries and inodes:

* echo 2 &> /proc/sys/vm/drop_caches

To free pagecache, dentries and inodes:

* echo 3 &> /proc/sys/vm/drop_caches

As this is a non-destructive operation, and dirty objects are notfreeable, the user should run "sync" first in order to make sure allcached objects are freed.

This tunable was added in 2.6.16.


回答pagein的問題

應該是因為文件頁面不像匿名頁做remap而是直接丟掉重新讀

具體可見 compact_zone-&>migrate_pages

解決 另外把預讀大一點連續點減少點碎頁?

我覺得核心還是內存不能滿足你的業務需求 雖然可調整招還不少 不過那麼辛苦折騰不如加點內存來的省力不容易出問題啊

最後再多說幾句 這幾年IO的節省挺重要的 而去年mapping-&>a_ops-&>migratepage的介面已經就位(現在主要用戶是zsmalloc) 是不是可以給file cache增加migrate的來節省IO是一個不錯的點子?


cache是因為對帶文件系統的介質進行讀寫引起的。是內核做的頁緩存。可以通過vmtouch工具去定位是哪些文件占的cache,從而查到對應的服務進程。


最簡單的echo 1 &>/proc/sys/vm/drop_caches


可通過調節 min_free_kbytes 來達到類似目的


用selinux鎖掉dropcache和其他懷疑項,誰碰誰進log


推薦閱讀:

Linux 是否被過譽了?
scp如何跨過中轉主機直接傳輸文件?
怎麼給電腦裝系統?
在使用Multiplexed I/O的情況下,還有必要使用Non Blocking I/O么 ?
超級計算機的組成:一個系統還是多個系統協同合作?

TAG:操作系統 | Linux | Linux內核 | Linux運維 |