歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> SWAP的罪與罰

SWAP的罪與罰

日期:2017/2/27 15:59:39   编辑:Linux教程

說個案例:一台Apache服務器,由於其MaxClients參數設置過大,並且恰好又碰到訪問量激增,結果內存被耗光,從而引發SWAP,進而負載攀升,最終導致宕機。

正所謂:SWAP,性能之大事,死生之地,存亡之道,不可不察也。

哪些工具可以監測SWAP

最容易想到的就是free命令了,它指明了當前SWAP的使用情況:

shell> free -m
             total       used       free
Swap:        34175      11374      22801

另一個常用的是sar命令,它能列出系統在各個時間的SWAP使用情況:

shell> sar -r
kbswpfree kbswpused  %swpused  kbswpcad
 23345644  11650572     33.29   4656908
 23346452  11649764     33.29   4656216
 23346556  11649660     33.29   4650308
 23346932  11649284     33.29   4649888
 23346992  11649224     33.29   4648848

不過free命令和sar命令顯示的都不是實時數據,如果需要,可以使用vmstat命令:

shell> vmstat 1
-----------memory------------- ---swap--
  swpd   free   buff   cache     si   so
11647532 123664 305064 7193168    0    0
11647532 123672 305064 7193172    0    0
11647532 125728 305064 7193468    0    0
11647532 125376 305064 7193476    0    0
11647532 124508 305068 7193624    0    0

每秒刷新一次結果,在SWAP一欄裡列出了相關數據,至於si和so的解釋,大致如下:

  • si: Amount of memory swapped in from disk (/s).
  • so: Amount of memory swapped to disk (/s).

如果它們一直是零當然最好不過了,偶爾不為零也沒啥,糟糕的是一直不為零。

前面介紹的方法,看到的都是SWAP的整體情況,可是如果我想查看到底是哪些進程使用了SWAP,應該如何操作呢?這個問題有點棘手,我們來研究一下:

好消息是top命令能提供這個信息,不過缺省並沒有顯示,我們需要激活一下:

  1. 打開top;
  2. 按「f」進入選擇字段的界面;
  3. 按「p」選擇「SWAP」字段;
  4. 按回車確認。

壞消息是top命令提供的SWAP信息只是一個理論值,或者更直白一點兒來說它根本就是不可信的(在top裡SWAP的計算公式是:SWAP=VIRT-RES)。

BTW:相比之下,top裡的「nFLT」字段更有價值,它表示PageFault的次數。

那到底我們能不能獲取到進程的SWAP情況呢?別著急,看代碼:

#!/bin/bash
cd /proc
for pid in [0-9]*; do
    command=$(cat /proc/$pid/cmdline)
    swap=$(
        awk '
            BEGIN  { total = 0 }
            /Swap/ { total += $2 }
            END    { print total }
        ' /proc/$pid/smaps
    )
    if (( $swap > 0 )); then
        if [[ "${head}" != "yes" ]]; then
            echo -e "PID\tSWAP\tCOMMAND"
            head="yes"
        fi
        echo -e "${pid}\t${swap}\t${command}"
    fi
done

說明:請使用root權限來運行此腳本。

哪些因素可能影響SWAP

內存不足無疑會SWAP,但有些時候,即便看上去內存很充裕,還可能會SWAP,這種現象被稱為SWAP Insanity,罪魁禍首主要有以下幾點:

Swappiness的迷失

實際上,當可用內存不足時,系統有兩個選擇:一個是通過SWAP來釋放內存,另一個是刪除Cache中的Page來釋放內存。一個很常見的例子是: 當拷貝大文件的時候,時常會發生SWAP現象。這是因為拷貝文件的時候,系統會把文件內容在Cache中按Page來緩存,此時一旦可用內存不足,系統便 會傾向於通過SWAP來釋放內存。

內核中的swappiness參數可以用來控制這種行為,缺省情況下,swappiness的值是60:

shell> sysctl -a | grep swappiness
vm.swappiness = 60

它的含義是:如果系統需要內存,有百分之六十的概率執行SWAP。知道了這一點,我們很自然的會想到用下面的方法來降低執行SWAP的概率:

shell> echo "vm.swappiness = 0" >> /etc/sysctl.conf
shell> sysctl -p

這樣做的確可以降低執行SWAP的概率,但並不意味著永遠不會執行SWAP。

NUMA的詛咒

NUMA在MySQL社區有很多討論,這裡不多說了,直擊NUMA和SWAP的恩怨糾葛。

大概了解一下NUMA最核心的numactl命令:

shell> numactl --hardware
available: 2 nodes (0-1)
node 0 size: 16131 MB
node 0 free: 100 MB
node 1 size: 16160 MB
node 1 free: 10 MB
node distances:
node   0   1
  0:  10  20
  1:  20  10

可以看到系統有兩個節點(其實就是兩個物理CPU),它們各自分了16G內存,其中零號節點還剩100M內存,一號節點還剩10M內存。設想啟動了 一個需要11M內存的進程,系統把它分給了一號節點來執行,此時雖然系統總體的可用內存大於該進程需要的內存,但因為一號節點本身剩余的可用內存不足,所 以仍然可能會觸發SWAP行為。

需要說明的一點事,numactl命令中看到的各節點剩余內存中時不包括Cache內存的,如果需要知道,我們可以利用drop_caches參數先釋放它:

shell> sysctl vm.drop_caches=1

注:這步操作可能會引起系統負載的震蕩。

另:如何確定一個進程的節點及內存分配情況?網絡上有現成的腳本。

如果要規避NUMA對SWAP的影響,最簡單的方法就是在啟動進程的時候禁用它:

shell> numactl --interleave=all ...

此外,內核參數zone_reclaim_mode通常也很重要,當某個節點可用內存不足時,如果為0的話,那麼系統會傾向於從遠程節點分配內存;如果為1的話,那麼系統會傾向於從本地節點回收Cache內存。多數時候,Cache對性能很重要,所以0是一個更好的選擇。

shell> echo "vm.zone_reclaim_mode = 0" >> /etc/sysctl.conf
shell> sysctl -p

另:網絡上有一些關於MySQL和SWAP的討論,對於理解SWAP有一定意義,推薦:

  • MySQL如何避免使用swap(一)
  • MySQL如何避免使用swap(二)
  • MySQL如何避免使用swap(三)

補:Memcached在啟動的時候如果帶上了k選項,就能避免使用SWAP,但要慎用。

早些年,YouTube曾經被SWAP問題困擾過,他們當時的解決方法很極端:刪除SWAP!不得不說這真是藝高人膽大,可惜對芸芸眾生的我們而言,這實在是太危險了,因為如此一來,一旦內存耗盡,由於沒有SWAP的緩沖,系統會立即開始OOM,結果可能會讓問題變得更加復雜,所以大家還是安分守己做個老實人吧。

Copyright © Linux教程網 All Rights Reserved