我們很容易就用free命令看到系統的cache使用量,但是你知道是哪些程序的文件在消耗cache嗎?雖然cache在嚴格意義上也是可以當做free的內存使用的,也可以通過 echo 3>/proc/sys/vm/drop_caches來主動釋放,但是你真的確定運行這條命之後,cache的數據回寫到磁盤不會造成你的系統IO飆升而出現其他問題嗎?你確定當前系統是可以清理page cache的嗎?爲了弄明白,到底是哪些文件被緩存了。今天就來寫個腳本探測一下系統進程所打開的那些文件在消耗我們的cache。
先來看一下我們的內存使用情況:
# free total used free shared buff/cache available Mem: 3882572 762388 398412 194732 2721772 2586636 Swap:
一開始我是參考餘楓大拿的這篇文章(http://blog.yufeng.info/archives/688),需要用上高大上的System Tap來探測,這對於某些線上環境的機器來說是不可能給你安裝kernel-debug,kernel-devel-debug 幾百兆的包來跑System Tap腳本的。
然後我用到了他文章最後提到的那個工具fincore,是由國外的大拿開發的專門用來探測系統的哪些文件正在被cache。(下載地址:https://code.google.com/p/linux-ftools/source/browse/#hg%253Fstate%253Dclosed)
下載下來按照說明,簡單安裝./configure && make && make install,編譯 生成的三個工具linux-fincore、linux-fallocate、linux-fadvise 在/usr/local/bin/目錄下。
今天只用到linux-fincore,他的用法比較簡單:
# linux-fincore fincore version 1.3.0 fincore [options] files... -s --summarize When comparing multiple files, print a summary report -p --pages Print pages that are cached -o --only-cached Only print stats for files that are actually in cache. -g --graph Print a visual graph of each file's cached page distribution. -S --min-size Require that each files size be larger than N bytes. -C --min-cached-size Require that each files cached size be larger than N bytes. -P --min-perc-cached Require percentage of a file that must be cached. -h --help Print this message. -L --vertical Print the output of this script vertically.
使用過程中發現下面的這些參數貌似都不好用,輸出都是一樣的內容,先來看一個庫文件的緩存情況:
# linux-fincore -o /usr/lib64/libz.so.1.2.7 linux-fincore: invalid option -- 'o' filename size total_pages min_cached page cached_pages cached_size cached_perc -------- ---- ----------- --------------- ------------ ----------- ----------- /usr/lib64/libz.so.1.2.7 90,632 23 0 23 94,208 100.00 --- total cached size: 94,208
右側顯示size(Byte), total_pages, min_cached page, cached_pages, cached_size,cached_perc。
這裏可以看到該文件的緩存率是100,就是說它是被完全被緩存起來的,這也可以理解,庫文件經常被調用,緩存起來可以提高訪問速度。
需要注意的是,他只能查看指定的文件是否是被緩存的,而不能指定目錄,因爲linux 的cache是隻緩存文件的。
fincore的工作原理是將指定的文件的相應inode data與kernel的 page cache table做對比,如果page cache table有這個inode 信息,就找該inode對應的data block的大小。因爲kernel的page cache table只存儲data block的引用而不是文件名,即文件的inode信息。所以並沒有任何一個工具運行一次就可以找出所有的文件使用緩存的情況,如果你非要對系統的所有文件都用linux-fincore查看一遍的話,那我就不跟你做朋友了:(。
所以使用linux-fincore只能加文件名,來判斷該文件是否被緩存,如果緩存,大小是多少。問題是你不能隨便猜哪個文件是否被緩存吧,我突然想到了一個方法,既然cache也是內存的一部分,那就查看哪些進程使用的物理內存最多,就找到該進程打開的文件,然後用fincore查看這些文件的緩存使用率。
在這之前,我們先看一下top輸出的VIRT, RES, SHR值的含義。來看看man手冊給我們的解釋:
VIRT -- Virtual Memory Size (KiB) The total amount of virtual memory used by the task. It includes all code, data and shared libraries plus pages that have been swapped out and pages that have been mapped but not used.
一個任務使用的虛擬內存的總量,包括 代碼、數據、共享庫加上已換出的頁和已經被映射出去了但是還沒被使用的頁。 簡單理解就是所有的虛擬內存中含有共享庫、共享內存、堆、棧和所有已經申請的內存空間。
利用命令查看:vsz=data + code + shared lib
$ ps -a -o pid,pmem,cmd,vsz,drs,trs PID %MEM CMD VSZ DRS TRS 3870 0.0 ps -a -o pid,pmem,cmd,vsz,d 148912 148822 89 10906 0.0 screen -dr 129744 129744 0 16116 0.0 sudo -i 195524 195524 0 16117 0.3 -zsh 156876 156876 0
RES -- Resident Memory Size (KiB) The non-swapped physical memory a task is using.
一個任務使用的不可交換的物理內存大小。是一個進程正在使用的內存空間(堆、棧)。
SHR -- Shared Memory Size (KiB) The amount of shared memory available to a task, not all of which is typically resident. It simply reflects memory that could be potentially shared with other processes.
一個任務正在使用的共享內存大小,這個大小對該進程不是固定的,它只是簡單底反應了可以被其他進程共享的內存大小。
因爲cache使用的是物理內存,所以與swap就無關了。所以只關心RES的值。我們來寫個腳本來查看當前系統的哪些文件正在消耗我們的cache。思路是找到使用RES最高的前10個進程,然後用lsof找到該進程正在使用的文件,最後把這些文件交給fincore來處理。
#!/bin/bash #Author: Shanker #Time: 2016/06/08 #set -e #set -u #you have to install linux-fincore if [ ! -f /usr/local/bin/linux-fincore ] then echo "You haven't installed linux-fincore yet" exit fi #find the top 10 processs' cache file ps -e -o pid,rss|sort -nk2 -r|head -10 |awk '{print $1}'>/tmp/cache.pids #find all the processs' cache file #ps -e -o pid>/tmp/cache.pids if [ -f /tmp/cache.files ] then echo "the cache.files is exist, removing now " rm -f /tmp/cache.files fi while read line do lsof -p $line 2>/dev/null|awk '{print $9}' >>/tmp/cache.files done</tmp/cache.pids if [ -f /tmp/cache.fincore ] then echo "the cache.fincore is exist, removing now" rm -f /tmp/cache.fincore fi for i in `cat /tmp/cache.files` do if [ -f $i ] then echo $i >>/tmp/cache.fincore fi done linux-fincore -s `cat /tmp/cache.fincore` rm -f /tmp/cache.{pids,files,fincore}
運行效果如下,可以看到內存使用率最高的前十個進程緩存的文件佔用了296MB的內存。
當然腳本可以實現查看系統所有進程所打開的文件cache 狀態,如果你不想讓你的磁盤I/O搞成這的話,可以試試。
參考鏈接:
http://serverfault.com/questions/278454/is-it-possible-to-list-the-files-that-are-cached
http://blog.yufeng.info/archives/688
歡迎補充!