pcstat
最近工作的關係常常需要分析到Linux伺服器的效能,在用系統工具top時,發現有很多的記憶體空間都會被『buffer/cache』給吃掉,一開始會很緊張,覺得是不是我們寫的程式有問題,問了好多人,大家也回答的不出所以然,只知道一件事就是只要需要記憶體時這段空間釋放的出來就沒問題了,但是,誰知道原理是什麼,怎麼會知道它100%一定會釋放出來呢??這時秉持著深度工程師的精神,只好花一點時間來研究一下了。
buff/cache不一定能被回收
當初回答我說反正系統要的時候,buff/cache自然會release出來的那些人,其實誤導了我,因為根據了文章 - 『Linux内存中的Cache真的能被回收么?』並不是這麼一回事,這個部份真的是case by case的去探討,所以問題還是回到了最基本的層次,那到底有什麼機制可以知道系統每個process/file都用了多少的buffer/cache呢?
linux-ftools
原本是用來分析與除錯Linux系統并用來增進效能的一套工具,網址如下,有興趣的可以看一下: https://github.com/david415/linux-ftools 但是已經年久失修了(寫這篇文的時候,看到最後一次commit是2010年9月),並且也無法成功編譯。
pcstat
因為linux-ftools的問題,所以網友『tobert』就自己用GO寫了一套pcstat,主要跟linux-ftools的『fincore』一樣,也是用『mincore』系統呼叫去取得相關的資訊,相關的編譯可以直接參考網頁『https://github.com/tobert/pcstat 』,因為我GO不熟,所以就不多加描述這方面的訊息了,對我來講我只要去取的相關的執行檔就好,如下:
if [ $(uname -m) == "x86_64" ] ; then
curl -L -o pcstat https://github.com/tobert/pcstat/raw/2014-05-02-01/pcstat.x86_64
else
curl -L -o pcstat https://github.com/tobert/pcstat/raw/2014-05-02-01/pcstat.x86_32
fi
chmod 755 pcstat
cp pcstat /usr/local/sbin/
Usage
使用方式如下所示,每個參數後面有個program flags都可以是一個準備被探勘的檔案。
pcstat <-json <-pps>|-terse|-default> <-nohdr> <-bname> file file file
-json output will be JSON
-pps include the per-page information in the output (can be huge!)
-terse print terse machine-parseable output
-histo print a histogram using unicode block characters
-nohdr don't print the column header in terse or default format
-bname use basename(file) in the output (use for long paths)
-plain return data with no box characters
-unicode return data with unicode box characters
output
Default output
預設的輸出是固定欄寬方便人類觀看:
atobey@brak ~ $ pcstat testfile3
|-----------+----------------+------------+-----------+---------|
| Name | Size | Pages | Cached | Percent |
|-----------+----------------+------------+-----------+---------|
| LICENSE | 11323 | 3 | 0 | 000.000 |
| README.md | 6768 | 2 | 2 | 100.000 |
| pcstat | 3065456 | 749 | 749 | 100.000 |
| pcstat.go | 9687 | 3 | 3 | 100.000 |
| testfile3 | 102401024 | 25001 | 60 | 000.240 |
|-----------+----------------+------------+-----------+---------|
Terse output
第二種格式是為了方便給機器處理:
pcstat -terse -bname *
name,size,timestamp,mtime,pages,cached,percent
LICENSE,11323,1400767725,1400492571,3,0,0
README.md,6185,1400767725,1400767719,2,2,100
pcstat,3065456,1400767725,1400766869,749,749,100
pcstat.go,9687,1400767725,1400766807,3,3,100
testfile3,102401024,1400767725,1400761247,25001,60,0.23999040038398464
JSON output
第三種就是Json的格式,『status』將會總是空的除非你加了『-pps』flag,將會輸出一個booleans的陣列,代表的是每個檔案是否有被cached住。
atobey@brak ~ $ pcstat -json testfile3 |json_pp
[
{
"filename": "testfile3",
"size": 102401024,
"timestamp": "2014-05-22T13:57:19.971348936Z",
"mtime": "2014-05-22T12:20:47.940163295Z",
"pages": 25001,
"cached": 60,
"uncached": 24941,
"percent": 0.23999040038398464,
"status": []
}
]
Histogram output
這個會輸出直方圖,但是前提示你的teminal和字體必須支援,檔名後面的數字代表的是檔案裡面的pages。
atobey@brak ~ $ pcstat -bname -histo *
LICENSE 3 ▁▁▁
README.md 2 ██
pcstat 749 █████████████████████████████████████████████████
pcstat.go 3 ███
testfile 2560 ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
testfile2 3 ▁▁▁
testfile3 25001 ▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
應用
根據網頁『谁吃了我的Linux内存?』,裡面有介紹一個script,主要是用來查看哪些processes用最多的physical memory,然後在用pcstat來看這些文件的cache/buffer的使用率。
大概的script如下: https://raw.githubusercontent.com/hugh712/my_script/master/checkCache.sh
#you have to install pcstat
PCSTAT=/usr/local/bin/pcstat
if [ ! -f $PCSTAT ]
then
echo "You haven't installed pcstat yet"
echo "prepare to download and install pcstat"
if [ $(uname -m) == "x86_64" ] ; then
curl -L -o pcstat https://github.com/tobert/pcstat/raw/2014-05-02-01/pcstat.x86_64
else
curl -L -o pcstat https://github.com/tobert/pcstat/raw/2014-05-02-01/pcstat.x86_32
fi
chmod 755 pcstat
sudo mv pcstat /usr/local/bin
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.pcstat ]
then
echo "the cache.pcstat is exist, removing now"
rm -f /tmp/cache.pcstat
fi
for i in `cat /tmp/cache.files`
do
if [ -f $i ]
then
echo $i >>/tmp/cache.pcstat
fi
done
$PCSTAT `cat /tmp/cache.pcstat`
rm -f /tmp/cache.{pids,files,pcstat}
Ref: