Linux下swap升高的原因分析案例


機器配置:2 CPU,8GB 內存

需要預先安裝 sysstat 等工具,如 yum  install sysstat

終端中運行 free 命令,查看 Swap 的使用情況。

$ free
             total        used        free      shared  buff/cache   available
Mem:        8169348      331668     6715972         696     1121708     7522896
Swap:             0           0           0

  從這個 free 輸出你可以看到,Swap 的大小是 0,這說明我的機器沒有配置 Swap。為了繼續 Swap 的案例, 就需要先配置、開啟 Swap。如果你的環境中已經開啟了 Swap,那你可以略過下面的開啟步驟,繼續往后走。要開啟 Swap,我們首先要清楚,Linux 本身支持兩種類型的 Swap,即 Swap 分區和 Swap 文件。以 Swap 文件為例,在第一個終端中運行下面的命令開啟 Swap,這里配置 Swap 文件的大小為 8GB:

# 創建Swap文件
$ fallocate -l 8G /mnt/swapfile
# 修改權限只有根用戶可以訪問
$ chmod 600 /mnt/swapfile
# 配置Swap文件
$ mkswap /mnt/swapfile
# 開啟Swap
$ swapon /mnt/swapfile

  再執行 free 命令,確認 Swap 配置成功:

$ free
             total        used        free      shared  buff/cache   available
Mem:        8169348      331668     6715972         696     1121708     7522896
Swap:       8388604           0     8388604

  現在,free  輸出中,Swap 空間以及剩余空間都從 0 變成了 8GB,說明 Swap 已經正常開啟。接下來,在第一個終端中,運行下面的 dd 命令,模擬大文件的讀取:

# 寫入空設備,實際上只有磁盤的讀請求
$ dd if=/dev/sda1 of=/dev/null bs=1G count=2048

  接着,在第二個終端中運行 sar 命令,查看內存各個指標的變化情況。

# 間隔1秒輸出一組數據
# -r表示顯示內存使用情況,-S表示顯示Swap使用情況
$ sar -r -S 1
04:39:56    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:39:57      6249676   6839824   1919632     23.50    740512     67316   1691736     10.22    815156    841868         4

04:39:56    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:39:57      8388604         0      0.00         0      0.00

04:39:57    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:39:58      6184472   6807064   1984836     24.30    772768     67380   1691736     10.22    847932    874224        20

04:39:57    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:39:58      8388604         0      0.00         0      0.00

…


04:44:06    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:44:07       152780   6525716   8016528     98.13   6530440     51316   1691736     10.22    867124   6869332         0

04:44:06    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:44:07      8384508      4096      0.05        52      1.27

  sar 的輸出結果是兩個表格,第一個表格表示內存的使用情況,第二個表格表示 Swap 的使用情況。其中,各個指標名稱前面的 kb 前綴,表示這些指標的單位是 KB。

大部分指標我們都已經見過了,剩下的幾個新出現的指標,簡單介紹一下。

kbcommit,表示當前系統負載需要的內存。它實際上是為了保證系統內存不溢出,對需要內存的估計值。%commit,就是這個值相對總內存的百分比。

kbactive,表示活躍內存,也就是最近使用過的內存,一般不會被系統回收。

kbinact,表示非活躍內存,也就是不常訪問的內存,有可能會被系統回收。

清楚了界面指標的含義后,再結合具體數值,來分析相關的現象。可以清楚地看到,總的內存使用率(%memused)在不斷增長,從開始的 23% 一直長到了 98%,並且主要內存都被緩沖區(kbbuffers)占用。具體來說:

剛開始,剩余內存(kbmemfree)不斷減少,而緩沖區(kbbuffers)則不斷增大,由此可知,剩余內存不斷分配給了緩沖區。

一段時間后,剩余內存已經很小,而緩沖區占用了大部分內存。這時候,Swap 的使用開始逐漸增大,緩沖區和剩余內存則只在小范圍內波動。

還得看看進程緩存的情況。cachetop 正好能滿足這一點。

在第二個終端中,按下 Ctrl+C 停止 sar 命令,然后運行下面的 cachetop 命令,觀察緩存的使用情況:

$ cachetop 5
12:28:28 Buffers MB: 6349 / Cached MB: 87 / Sort: HITS / Order: ascending
PID      UID      CMD              HITS     MISSES   DIRTIES  READ_HIT%  WRITE_HIT%
   18280 root     python                 22        0        0     100.0%       0.0%
   18279 root     dd                  41088    41022        0      50.0%      50.0%

  通過 cachetop 的輸出,dd 進程的讀寫請求只有 50% 的命中率,並且未命中的緩存頁數(MISSES)為 41022(單位是頁)。這說明,正是案例開始時運行的 dd,導致了緩沖區使用升高。

這種情況,還得進一步通過 /proc/zoneinfo  ,觀察剩余內存、內存閾值以及匿名頁和文件頁的活躍情況。

可以在第二個終端中,按下 Ctrl+C,停止 cachetop 命令。然后運行下面的命令,觀察 /proc/zoneinfo 中這幾個指標的變化情況:

# -d 表示高亮變化的字段
# -A 表示僅顯示Normal行以及之后的15行輸出
$ watch -d grep -A 15 'Normal' /proc/zoneinfo
Node 0, zone   Normal
  pages free     21328
        min      14896
        low      18620
        high     22344
        spanned  1835008
        present  1835008
        managed  1796710
        protection: (0, 0, 0, 0, 0)
      nr_free_pages 21328
      nr_zone_inactive_anon 79776
      nr_zone_active_anon 206854
      nr_zone_inactive_file 918561
      nr_zone_active_file 496695
      nr_zone_unevictable 2251
      nr_zone_write_pending 0

  可以發現,剩余內存(pages_free)在一個小范圍內不停地波動。當它小於頁低閾值(pages_low) 時,又會突然增大到一個大於頁高閾值(pages_high)的值。'

  再結合剛剛用 sar 看到的剩余內存和緩沖區的變化情況,我們可以推導出,剩余內存和緩沖區的波動變化,正是由於內存回收和緩存再次分配的循環往復。當剩余內存小於頁低閾值時,系統會回收一些緩存和匿名內存,使剩余內存增大。其中,緩存的回收導致 sar 中的緩沖區減小,而匿名內存的回收導致了 Swap 的使用增大。緊接着,由於 dd 還在繼續,剩余內存又會重新分配給緩存,導致剩余內存減少,緩沖區增大。

其實還有一個有趣的現象,如果多次運行 dd 和 sar,可能會發現,在多次的循環重復中,有時候是 Swap 用得比較多,有時候 Swap 很少,反而緩沖區的波動更大。換句話說,系統回收內存時,有時候會回收更多的文件頁,有時候又回收了更多的匿名頁。顯然,系統回收不同類型內存的傾向,似乎不那么明顯。你應該想到了上節課提到的 swappiness,正是調整不同類型內存回收的配置選項。

還是在第二個終端中,按下 Ctrl+C 停止 watch 命令,然后運行下面的命令,查看 swappiness 的配置:

 

$ cat /proc/sys/vm/swappiness
60

  swappiness 顯示的是默認值 60,這是一個相對中和的配置,所以系統會根據實際運行情況,選擇合適的回收類型,比如回收不活躍的匿名頁,或者不活躍的文件頁

到這里,已經找出了 Swap 發生的根源

還是推薦 proc 文件系統,用來查看進程 Swap 換出的虛擬內存大小,它保存在 /proc/pid/status 中的 VmSwap 中(推薦你執行 man proc 來查詢其他字段的含義)。

第二個終端中運行下面的命令,就可以查看使用 Swap 最多的進程。

# 按VmSwap使用量對進程排序,輸出進程名稱、進程ID以及SWAP用量
$ for file in /proc/*/status ; do awk '/VmSwap|Name|^Pid/{printf $2 " " $3}END{ print ""}' $file; done | sort -k 3 -n -r | head
dockerd 2226 10728 kB
docker-containe 2251 8516 kB
snapd 936 4020 kB
networkd-dispat 911 836 kB
polkitd 1004 44 kB

  從這里你可以看到,使用 Swap 比較多的是 dockerd 和 docker-containe 進程,所以,當 dockerd 再次訪問這些換出到磁盤的內存時,也會比較慢。這也說明了一點,雖然緩存屬於可回收內存,但在類似大文件拷貝這類場景下,系統還是會用 Swap 機制來回收匿名內存,而不僅僅是回收占用絕大部分內存的文件頁。最后,如果你在一開始配置了 Swap,不要忘記在案例結束后關閉。你可以運行下面的命令,關閉 Swap:

$ swapoff -a

  實際上,關閉 Swap 后再重新打開,也是一種常用的 Swap 空間清理方法,比如:

$ swapoff -a && swapon -a 

  在內存資源緊張時,Linux 會通過 Swap ,把不常訪問的匿名頁換出到磁盤中,下次訪問的時候再從磁盤換入到內存中來。你可以設置 /proc/sys/vm/min_free_kbytes,來調整系統定期回收內存的閾值;也可以設置 /proc/sys/vm/swappiness,來調整文件頁和匿名頁的回收傾向。當 Swap 變高時,你可以用 sar、/proc/zoneinfo、/proc/pid/status 等方法,查看系統和進程的內存使用情況,進而找出 Swap 升高的根源和受影響的進程。反過來說,通常,降低 Swap 的使用,可以提高系統的整體性能。也總結了幾種常見的降低方法。禁止 Swap,現在服務器的內存足夠大,所以除非有必要,禁用 Swap 就可以了。隨着雲計算的普及,大部分雲平台中的虛擬機都默認禁止 Swap。如果實在需要用到 Swap,可以嘗試降低 swappiness 的值,減少內存回收時 Swap 的使用傾向。響應延遲敏感的應用,如果它們可能在開啟 Swap 的服務器中運行,你還可以用庫函數 mlock() 或者 mlockall() 鎖定內存,阻止它們的內存換出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM