說個案例:一臺Apache服務器,由于其MaxClients參數設置過大,并且恰好又碰到訪問量激增,結果內存被耗光,從而引發SWAP,進而負載攀升,最終導致宕機。
正所謂:SWAP,性能之大事,死生之地,存亡之道,不可不察也。
最容易想到的就是free命令了,它指明了當前SWAP的使用情況:
shell> free -m total used freeSwap: 34175 11374 22801
另一個常用的是sar命令,它能列出系統在各個時間的SWAP使用情況:
shell> sar -rkbswpfree 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 so11647532 123664 305064 7193168 0 011647532 123672 305064 7193172 0 011647532 125728 305064 7193468 0 011647532 125376 305064 7193476 0 011647532 124508 305068 7193624 0 0
每秒刷新一次結果,在SWAP一欄里列出了相關數據,至于si和so的解釋,大致如下:
如果它們一直是零當然最好不過了,偶爾不為零也沒啥,糟糕的是一直不為零。
前面介紹的方法,看到的都是SWAP的整體情況,可是如果我想查看到底是哪些進程使用了SWAP,應該如何操作呢?這個問題有點棘手,我們來研究一下:
好消息是top命令能提供這個信息,不過缺省并沒有顯示,我們需要激活一下:
壞消息是top命令提供的SWAP信息只是一個理論值,或者更直白一點兒來說它根本就是不可信的(在top里SWAP的計算公式是:SWAP=VIRT-RES)。
BTW:相比之下,top里的「nFLT」字段更有價值,它表示PageFault的次數。
那到底我們能不能獲取到進程的SWAP情況呢?別著急,看代碼:
#!/bin/bashcd /procfor 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}" fidone
說明:請使用root權限來運行此腳本。
內存不足無疑會SWAP,但有些時候,即便看上去內存很充裕,還可能會SWAP,這種現象被稱為SWAP Insanity,罪魁禍首主要有以下幾點:
Swappiness的迷失
實際上,當可用內存不足時,系統有兩個選擇:一個是通過SWAP來釋放內存,另一個是刪除Cache中的Page來釋放內存。一個很常見的例子是:當拷貝大文件的時候,時常會發生SWAP現象。這是因為拷貝文件的時候,系統會把文件內容在Cache中按Page來緩存,此時一旦可用內存不足,系統便會傾向于通過SWAP來釋放內存。
內核中的swappiness參數可以用來控制這種行為,缺省情況下,swappiness的值是60:
shell> sysctl -a | grep swappinessvm.swappiness = 60
它的含義是:如果系統需要內存,有百分之六十的概率執行SWAP。知道了這一點,我們很自然的會想到用下面的方法來降低執行SWAP的概率:
shell> echo "vm.swappiness = 0" >> /etc/sysctl.confshell> sysctl -p
這樣做的確可以降低執行SWAP的概率,但并不意味著永遠不會執行SWAP。
NUMA的詛咒
NUMA在MySQL社區有很多討論,這里不多說了,直擊NUMA和SWAP的恩怨糾葛。
大概了解一下NUMA最核心的numactl命令:
shell> numactl --hardwareavailable: 2 nodes (0-1)node 0 size: 16131 MBnode 0 free: 100 MBnode 1 size: 16160 MBnode 1 free: 10 MBnode 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.confshell> sysctl -p
另:網絡上有一些關于MySQL和SWAP的討論,對于理解SWAP有一定意義,推薦:
補:Memcached在啟動的時候如果帶上了k選項,就能避免使用SWAP,但要慎用。
…
早些年,YouTube曾經被SWAP問題困擾過,他們當時的解決方法很極端:刪除SWAP!不得不說這真是藝高人膽大,可惜對蕓蕓眾生的我們而言,這實在是太危險了,因為如此一來,一旦內存耗盡,由于沒有SWAP的緩沖,系統會立即開始OOM,結果可能會讓問題變得更加復雜,所以大家還是安分守己做個老實人吧。
新聞熱點
疑難解答