Linux性能調優--Swap變高

上一篇總結了內存泄漏。
那麼當發生了內存泄漏時,或者運行了大內存的應用程序,導致系統的內存資源緊張時,系統會如何應對呢?
會導致兩種可能結果,內存回收和 OOM 殺死進程
OOM指的是系統殺死佔用大量內存的進程,釋放這些內存,再分配給其他更需要的進程。
內存回收指的是系統釋放掉可以回收的內存,比如我前面講過的緩存和緩衝區,就屬於可回收內存。它們在內存管理中,通常被叫做文件頁(File-backed Page)。
沒有被修改過的直接回收,以後從硬盤直接讀取就可以了。而那些被應用程序修改過的髒頁必須要刷回硬盤,然後才能進行從內存釋放。
刷回硬盤的兩種方式:
1 可以在應用程序中,通過系統調用 fsync ,把髒頁同步到磁盤中;
2 也可以交給系統,由內核線程 pdflush 負責這些髒頁的刷新。
緩存和緩衝區,通過內存映射獲取的文件映射頁,都是可以釋放的。而應用程序動態分配的堆內存,也就是我們在內存管理中說到的匿名頁(Anonymous Page)。由於下次有可能還要訪問,所以不能釋放。但是可以暫時存在硬盤裏面,下次要用的時候從硬盤直接讀取。釋放內存給其他需要的進程使用。這個就是Llinux的swap機制。
Swap 把這些不常訪問的內存先寫到磁盤中,然後釋放這些內存,給其他更需要的進程使用。再次訪問這些內存時,重新從磁盤讀入內存就可以了。
原理
Swap 就是把一塊磁盤空間或者一個本地文件(以下講解以磁盤爲例),當成內存來使用。它包括換出和換入兩個過程
換出,就是把進程暫時不用的內存數據存儲到磁盤中,並釋放這些數據佔用的內存。
換入,則是在進程再次訪問這些內存的時候,把它們從磁盤讀到內存中來。
現在的機器動不動就幾G的內存,相比與以前幾M的空間已經大了很多了。那是不是SWAP沒有用處了嗎?
內存在大,都有不夠用的時候。
一個很典型的場景就是,即使內存不足時,有些應用程序也並不想被 OOM 殺死,而是希望能緩一段時間,等待人工介入,或者等系統自動釋放其他進程的內存,再分配給它。
既然 Swap 是爲了回收內存,那麼 Linux 到底在什麼時候需要回收內存呢?前面一直在說內存資源緊張,又該怎麼來衡量內存是不是緊張呢?
直接內存回收,比如有新的大塊內存分配請求,但是剩餘內存不足。這個時候系統就需要回收一部分內存(比如前面提到的緩存),進而儘可能地滿足新內存請求。
kswapd0,一個專門的內核線程用來定期回收內存。kswapd0 定義了三個內存閾值(watermark,也稱爲水位),分別是頁最小閾值(pages_min)、頁低閾值(pages_low)和頁高閾值(pages_high)。
剩餘內存小於頁最小閾值,說明進程可用內存都耗盡了,只有內核纔可以分配內存。
剩餘內存落在頁最小閾值和頁低閾值中間,說明內存壓力比較大,剩餘內存不多了。這時 kswapd0 會執行內存回收,直到剩餘內存大於高閾值爲止。
剩餘內存落在頁低閾值和頁高閾值中間,說明內存有一定壓力,但還可以滿足新內存請求。
剩餘內存大於頁高閾值,說明剩餘內存比較多,沒有內存壓力。
可以通過內核選項 /proc/sys/vm/min_free_kbytes 來間接設置min_free_kbytes
pages_low = pages_min5/4
pages_high = pages_min
3/2
NUMA 與 Swap
NUMA架構圖:
在這裏插入圖片描述
在 NUMA 架構下,多個處理器被劃分到不同 Node 上,且每個 Node 都擁有自己的本地內存空間。而同一個 Node 內部的內存空間,實際上又可以進一步分爲不同的內存域(Zone),比如直接內存訪問區(DMA)、普通內存區(NORMAL)、僞內存區(MOVABLE)等。
可以通過 numactl 命令,來查看處理器在 Node 的分佈情況,以及每個 Node 的內存使用情況。
numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3
node 0 size: 7934 MB
node 0 free: 1621 MB
node distances:
node 0
0: 10
這跟SWAP有什麼關係呢?
前面提到的三個內存閾值(頁最小閾值、頁低閾值和頁高閾值),都可以通過內存域在 proc 文件系統中的接口 /proc/zoneinfo 來查看。
cat /proc/zoneinfo
輸出有大量的指標,解釋其中幾個比較常用的
pages 處的 min、low、high,就是上面提到的三個內存閾值,
free 是剩餘內存頁數,它跟後面的 nr_free_pages 相同。
nr_zone_active_anon 和 nr_zone_inactive_anon,分別是活躍和非活躍的匿名頁數。
nr_zone_active_file 和 nr_zone_inactive_file,分別是活躍和非活躍的文件頁數。
如果某個 Node 內存不足時,系統可以從其他 Node 尋找空閒內存,也可以從本地內存中回收內存。具體選哪種模式,你可以通過 /proc/sys/vm/zone_reclaim_mode 來調整。它支持以下幾個選項:
默認的 0 ,也就是剛剛提到的模式,表示既可以從其他 Node 尋找空閒內存,也可以從本地回收內存。
1、2、4 都表示只回收本地內存,2 表示可以回寫髒數據回收內存,4 表示可以用 Swap 方式回收內存。
swappiness
回收的內存既包括了文件頁,又包括了匿名頁。回收的方式有:
對文件頁的回收,當然就是直接回收緩存,或者把髒頁寫回磁盤後再回收。
而對匿名頁的回收,其實就是通過 Swap 機制,把它們寫入磁盤後再釋放內存。
既然有兩種不同的內存回收機制,那麼在實際回收內存時,到底該先回收哪一種呢?
Linux 提供了一個 /proc/sys/vm/swappiness 選項,用來調整使用 Swap 的積極程度。
雖然 swappiness 的範圍是 0-100,不過要注意,這並不是內存的百分比,而是調整 Swap 積極程度的權重,即使你把它設置成 0,當剩餘內存 + 文件頁小於頁高閾值時,還是會發生 Swap。
實驗環境
1 Ubuntu 18.04
2 你需要預先安裝 sysstat 等工具,如 apt install sysstat
步驟:
1 free查看
在這裏插入圖片描述
2 如果沒有開啓swap,開啓SWAP:

創建Swap文件

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

3 使用dd模擬大文件讀取
dd if=/dev/sda1 of=/dev/null bs=1G count=2048
間隔1秒輸出一組數據
-r表示顯示內存使用情況,-S表示顯示Swap使用情況
sar -r -S 1
在這裏插入圖片描述
sar 的輸出兩個表格,
第一個表格表示內存的使用情況,
第二個表格表示 Swap 的使用情況
各個字段什麼意思?
kbcommit,表示當前系統負載需要的內存。它實際上是爲了保證系統內存不溢出,對需要內存的估計值。
%commit,就是這個值相對總內存的百分比。
kbactive,表示活躍內存,也就是最近使用過的內存,一般不會被系統回收。
kbinact,表示非活躍內存,也就是不常訪問的內存,有可能會被系統回收。
分析:
剛開始,剩餘內存(kbmemfree)不斷減少,而緩衝區(kbbuffers)則不斷增大,由此可知,剩餘內存不斷分配給了緩衝區。
一段時間後,剩餘內存已經很小,而緩衝區佔用了大部分內存。這時候,Swap 的使用開始逐漸增大,緩衝區和剩餘內存則只在小範圍內波動。
退出sar,使用cachetop 查看是誰使用了緩存
在這裏插入圖片描述
dd 進程的讀寫請求只有 50% 的命中率,並且未命中的緩存頁數(MISSES)爲 849864(單位是頁)。這說明,正是案例開始時運行的 dd,導致了緩衝區使用升高。
爲什麼 Swap 也跟着升高了呢?直觀來說,緩衝區佔了系統絕大部分內存,還屬於可回收內存,內存不夠用時,不應該先回收緩衝區嗎?
通過 /proc/zoneinfo ,觀察剩餘內存、內存閾值以及匿名頁和文件頁的活躍情況。
-d 表示高亮變化的字段
-A 表示僅顯示Normal行以及之後的15行輸出
watch -d grep -A 15 ‘Normal’ /proc/zoneinfo
在這裏插入圖片描述
剩餘內存(pages_free)在一個小範圍內不停地波動。當它小於頁低閾值(pages_low) 時,又會突然增大到一個大於頁高閾值(pages_high)的值。
當剩餘內存小於頁低閾值時,系統會回收一些緩存和匿名內存,使剩餘內存增大。其中,緩存的回收導致 sar 中的緩衝區減小,而匿名內存的回收導致了 Swap 的使用增大。緊接着,由於 dd 還在繼續,剩餘內存又會重新分配給緩存,導致剩餘內存減少,緩衝區增大。
有一個有趣的現象,如果多次運行 dd 和 sar,你可能會發現,在多次的循環重複中,有時候是 Swap 用得比較多,有時候 Swap 很少,反而緩衝區的波動更大。
系統回收內存時,有時候會回收更多的文件頁,有時候又回收了更多的匿名頁。
swappiness,正是調整不同類型內存回收的配置選項。
$ cat /proc/sys/vm/swappiness
在這裏插入圖片描述
另一個問題就是,剛纔的 Swap 到底影響了哪些應用程序呢?換句話說,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
當然,一開始配置了 Swap,不要忘記在案例結束後關閉。你可以運行下面的命令,關閉 Swap:
swapoff -a

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章