我们很容易就用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.fincore
    fi
done
linux-fincore -s  `cat /tmp/cache.fincore`
rm -f /tmp/cache.{pids,files,fincore}


运行效果如下,可以看到内存使用率最高的前十个进程缓存的文件占用了296MB的内存。


Linux下哪些进程在消耗我们的Cache?_第1张图片


当然脚本可以实现查看系统所有进程所打开的文件cache 状态,如果你不想让你的磁盘I/O搞成这的话,可以试试。


Linux下哪些进程在消耗我们的Cache?_第2张图片



参考链接:

http://serverfault.com/questions/278454/is-it-possible-to-list-the-files-that-are-cached

http://blog.yufeng.info/archives/688


欢迎补充!