Linux工具效能調優系列三:swap問題定位
一,預備知識
1.1 什麼是swap
swap當我們指的名詞的時候,它可以是一個分割槽,也可以是一個檔案,是作業系統中一個存放從記憶體中置換出的資料的地方。 當我們指的是一個動詞時候,代表的是從實體記憶體交換資料到swap分割槽這個動作。
1.2 為什麼會swap
(1) 當實體記憶體不夠用時候,會根據特定的演算法,把一部分記憶體交換到swap分割槽(此時還會伴隨著高IO)。但是並不是所有的記憶體都可以被交換到swap分割槽。 (2) kswapd程序週期性對記憶體進行檢查,如果發現高於水位線,則觸發swap,此舉是為了不讓系統剩餘記憶體很少,防止出現突然的大記憶體申請。這塊暫不深入講解,後續再補充。
1.3 swap的到底是什麼
首先我們要知道,記憶體管理將記憶體分為active和inactive,程序使用者空間使用的對映包括了匿名對映(anon)和檔案對映(file)。所有一共有active anon,inactive anon,active file,inactive file。對於檔案對映,由於本身是磁碟空間中的檔案,所有它不會被swap,當需要釋放時候,髒資料直接寫回磁碟,其他資料直接釋放即可。記憶體交換到swap,肯定是交換不活躍的資料,所有,inactive anon是最主要的被交換的記憶體。那麼對於作業系統來說,當我需要回收記憶體時候,你說它是針對檔案對映好,還是針對匿名對映好,這就涉及到了一個引數:swapiness
1.3.1 swapiness
swapiness是設定記憶體回收時候,更傾向於回收檔案對映還是匿名對映,在/proc/sys/vm/swappiness設定值。對於swapiness=100,那麼兩者之間的權重是一致的,值越小,越傾向於回收檔案對映,不過如果達到系統高水位線,還是會swap,除非直接使用swapoff -a等手段關閉系統swap。
1.3 swap的好壞
swap的好處是當記憶體不足時候,可以將一部分交換出去,不會觸發oom-killer。跑得慢總比不能跑好。 swap的壞處是交換時候,會觸發高IO,同時會降低系統的效能。對於我們隔離做的不好的時候,會影響到其他應用的效能。
二,工具選擇
一個工具往往具有多種用途,但是本文只說明針對swap問題
工具名稱 | 使用姿勢 | 採集指標來源 |
---|---|---|
free | free -h | /proc/meminfo |
top | 按f,選擇swap | /proc/$pid/smaps |
vmstat | vmstat | /proc/meminfo |
iotop | iotop | |
iostat | iostat -xdm | |
pidstat | pidstat -d 1 | /proc/$pid/io |
三,案例分析
3.1 應用一直申請記憶體
本次的案例是使用golang編寫,在一個死迴圈裡面,每次迴圈申請記憶體,並且不釋放,然後達到一定次數後釋放記憶體,等待GC,再繼續,程式碼和文件歸檔在:歸檔。
3.1.1 執行程式和分析
(1) 執行
[email protected]:/www/linuxperformancetool/swap# ./swapexample1
複製程式碼
由於上面說的命令都可以用於分析,大家根據喜好搭配使用即可。我這裡用top,vmstat和pidstat搭配使用進行分析,可以開多幾個終端一起看。
(2) 分析 首先是使用vmstat,從下面可以看出,當程式佔用記憶體越來越大時候,出現了很高的swap io和block io,想一下,為什麼這兩個同時都增高?
[email protected]:~# vmstat -a 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free inact active si so bi bo in cs us sy id wa st
1 0 1240208 18816440 715216 12702360 0 0 1 18 0 0 0 0 99 0 0
1 0 1240208 18086504 715220 13431988 0 0 0 0 2223 3192 1 4 96 0 0
1 0 1240208 17343176 715220 14173444 0 0 0 60 1906 3099 1 4 95 0 0
1 0 1240208 16618392 715260 14897140 0 0 0 60 2351 3552 1 4 96 0 0
1 0 1240208 15883220 715280 15632572 0 0 0 0 2187 3547 1 4 96 0 0
0 2 1240300 15276012 806532 16151868 0 92 0 2088 2365 3373 1 3 95 2 0
0 2 1265792 15270100 2023920 14946200 56 25500 100 27536 5102 9189 1 1 93 5 0
0 3 1265784 15274476 2023856 14944732 40 0 40 2572 2162 2425 0 0 90 10 0
0 9 1287036 15276116 2022816 14944232 88 21276 88 22228 2074 3136 0 0 79 21 0
0 9 1287020 15273676 2024776 14946436 92 0 92 2288 3563 5822 0 0 79 20 0
2 3 1286912 15271708 2024844 14946532 128 0 128 1432 2989 4907 0 0 84 16 0
0 3 1286912 15271692 2024572 14946520 0 0 0 2344 3098 4543 0 0 87 13 0
0 4 1312096 15265788 2022444 14951064 0 25188 0 26628 4946 9752 1 1 90 9 0
複製程式碼
發現了系統問題後,我們就需要對問題進行定位了,這裡可以使用top,pidstat,iotop等工具進行定位,我這邊直接使用top,按f選擇swap。
top - 00:52:38 up 253 days, 14:23, 3 users, load average: 6.44, 2.60, 1.23
Tasks: 359 total, 1 running, 358 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.6 us, 0.6 sy, 0.0 ni, 67.0 id, 31.7 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 32895096 total, 236100 free, 32011520 used, 647476 buff/cache
KiB Swap: 31250428 total, 28358956 free, 2891472 used. 261616 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND SWAP
45466 root 20 0 10.076g 21624 2520 S 12.9 0.1 7881:36 etcd 19636
146 root 20 0 0 0 0 D 9.2 0.0 2:28.44 kswapd0 0
14179 root 20 0 31.136g 0.029t 4316 S 3.3 94.8 0:31.86 main1 1.375g
147 root 20 0 0 0 0 S 1.7 0.0 1:52.23 kswapd1 0
10737 root 20 0 3067756 60688 5968 S 0.7 0.2 3364:41 dockerd 60380
10750 root 20 0 2898452 38724 3096 S 0.7 0.1 629:49.22 docker-containe 79288
複製程式碼
從top的變化可以看出,pid=14179的程序一直swap一直在增高,而且記憶體佔用越來越高,其他程序雖然有出現swap增多,但是記憶體使用並沒有增高,可以判斷,該程序是導致出現swap的原因。那麼,我們再進一步進行確認。
使用pidstat判斷該pid的io情況,可以看出,是存在很大的IO
[email protected]:~# pidstat -p 14179 -d 1
Linux 4.4.0-87-generic (szdc-calic-2-6.meitu-inc.com) Wednesday, December 12, 2018 _x86_64_ (24 CPU)
12:55:40 CST UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
12:55:41 CST 0 14179 71920.00 0.00 0.00 0 main1
12:55:42 CST 0 14179 72796.04 0.00 0.00 0 main1
12:55:43 CST 0 14179 85664.00 0.00 0.00 0 main1
12:55:44 CST 0 14179 78128.00 0.00 0.00 0 main1
12:55:45 CST 0 14179 69660.00 0.00 0.00 0 main1
12:55:46 CST 0 14179 59892.00 0.00 0.00 0 main1
複製程式碼
3.1.2 問題
這些問題都不會直接進行解答,實在想不出來的,可以到歸檔專案下面提issue或者在下面評論
(1) 為什麼例子中,只是簡單的申請記憶體,會造成swap io和block io同時增高? (2) 例子中,明明還有剩餘記憶體未被使用,可是已經開始頻繁進行swap和回收大量記憶體。 (3) golang gc時候,會把已經swap出去的記憶體再swap到實體記憶體中,再進行gc嗎? (4) 上一節中的buffer和cache中包含的是哪些?(匿名頁還是檔案對映)