Linux服務端swap配置和監控
什麼是swap
Linux作業系統將實體記憶體分為多個小的記憶體塊,稱之為頁(pages). 當應用請求的實體記憶體不夠分配時,作業系統會將一段時間之內不用的記憶體頁交換至swap分割槽,從而為應用釋放記憶體空間。
Swap對於系統過來說非常重要:
首先,當主記憶體不夠用時,作業系統可以swap out一部分記憶體頁,迅速為當前急需記憶體的應用或者程序分配記憶體;其次,某些記憶體頁只在應用初始化階段用到,之後可能就不再使用了,作業系統可以將這些記憶體頁swap out,從而為應用或者磁碟cache騰出更多的記憶體空間。
swap有哪些缺陷
我們知道,計算機磁碟I/O通常是系統的瓶頸所在。主記憶體的讀寫速度是納秒級別,而磁碟讀寫速度是毫秒級別,兩者相差3、4個數量級。然而,即使是當前廣泛使用的SSD,讀寫速度相比主記憶體或者CPU cache也相差2、3個數量級。系統發生swap交換越多,那麼系統自然也越慢。
特別對於web伺服器來說,都是面對使用者的互動式應用,因此響應速度尤其重要。如果系統經常因為swap交換而變得響應遲鈍,那麼使用者體驗效果可想而知。
總結成一句話:swap分割槽要有,在關鍵時刻不至於讓你的應用因為記憶體不夠用而被作業系統OOM KILLER幹掉;但是不到關鍵時刻不要進行swap交換,因為這些操作會影響系統的響應速度。
人為干預Linux的swap行為——配置Swappiness
Swappiness是Linux的一個屬性,取值範圍0-100,用於控制作業系統進行swap out交換以及丟棄記憶體cache頁的傾向程度:數值越高,表示作業系統進行swap out的“積極性”越高。
簡而言之:
vm.swappiness = 0,表示只有在避免OOM的時候才進行swap操作;
vm.swappiness = 60,系統預設值;
vm.swappiness = 100,系統主動的進行swap操作。
檢視當前swappiness引數,linux系統一般預設值為60:
$ cat /proc/sys/vm/swappiness 60
修改Swappiness引數:
$ sudo echo 0 > /proc/sys/vm/swappiness
為了使上面的修改永久生效,還需要在/etc/sysctl.conf後面加上
vm.swappiness = 0
目前酒店搜尋組所屬的伺服器該引數都被配置為0.
監控伺服器swap的使用
檢視swap的整體使用情況
$ free -m total used free shared buffers cached Mem: 7836 6078 1758 0 165 3000 -/+ buffers/cache: 2911 4924 Swap: 7999 0 7999
關注最後一行就可以了,一目瞭然。
vmstat檢視swap in 和 swap out
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 1721436 170864 3090256 0 0 53 50 153 28 3 10 87 0 0
1 0 0 1721548 170864 3090300 0 0 0 44 7220 5693 5 11 84 0 0
1 0 0 1721424 170864 3090300 0 0 0 0 6826 5196 5 10 85 0 0
其中si和so分別代表swap in和swap out,上圖表明我的系統當前時間沒有進行swap操作。
檢視每個程序使用swap的情況
Linux系統中有一個檔案smaps檔案,記錄了當前程序所對應的記憶體映像資訊,路徑為/proc/$pid/smaps,以酒店搜尋組hslist系統的Java程序為例(只輸出一個記憶體塊映象資訊):
$ sudo cat /proc/25665/smaps | head -n9
40000000-40009000 r-xp 00000000 ca:07 1312980 /home/q/java/jdk1.6.0_37/bin/java
Size: 36 kB
Rss: 36 kB
Shared_Clean: 36 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Swap: 0 kB
Pss: 11 kB
其中Swap欄位代表該記憶體塊存在於swap分割槽的資料大小,其它欄位的意思請戳這裡。
瞭解了這個就可以用指令碼統計了,以下指令碼摘自網路,直接拿來用:
#!/bin/bash function getswap { SUM=0 OVERALL=0for DIR in `find /proc/ -maxdepth 1 -type d | egrep "^/proc/[0-9]"` ; doPID=`echo $DIR | cut -d / -f 3` PROGNAME=`ps -p $PID -o comm --no-headers`for SWAP in `grep Swap $DIR/smaps 2>/dev/null| awk '{ print $2 }'`dolet SUM=$SUM+$SWAP done echo "PID=$PID - Swap used: $SUM - ($PROGNAME )"let OVERALL=$OVERALL+$SUM SUM=0 done echo "Overall swap used: $OVERALL"} getswap #getswap|egrep -v "Swap used: 0"
執行結果:
$ getswap|egrep -v "Swap used: 0"Overall swap used: 0
當然,多數時候我們只需要關注我們的java程序是否吃swap,這就更簡單了,不需要上面那個複雜的指令碼,單行awk就搞定了:
pgrep java | xargs -I{} sudo cat /proc/{}/smaps | grep 'Swap' | awk '{a+=$(NF-1)}END{print a}'
如何清除被佔用的swap
在我們明確知道哪些程序吃swap以後,接下來的問題就是我們如何釋放這些swap,釋放swap的意思就是把交換到swap中的資料swap in到實體記憶體頁中。有兩種做法可以達到目的:
重啟吃swap的服務,比如重啟一下我們的java程序
swapoff && swapon
這個方法的好處是,不用重啟服務,但是需要確保現在有足夠的實體記憶體可以容下從swap中釋放出來的資料。下面給出了swapoff和swapon的具體做法,大家注意看swapoff後和swapon後,free的輸出有什麼異同。
可以看到swapoff後,free的輸出裡,swap分割槽的大小變為0,佔用變為0,也就是說swap分割槽中的資料已經釋放到實體記憶體中,同時swap分割槽被禁用。swapon後,free的輸出裡,swap分割槽的容量又恢復為4094M,也就是說swap分割槽重新被啟用了。當然我們可以把這兩個命令寫到一起:
sudo /sbin/swapoff -a && sudo /sbin/swapon -a
參考文獻
http://www.data-recovery-app.com/datarecovery/linux-swap.html
http://arminds.com/forums/linux-talk/226-configure-linux-swap-to-improve-server-performance
http://en.wikipedia.org/wiki/Swappiness