Linux工具效能調優系列三: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,再繼續,程式碼和文件歸檔在:ofollow,noindex">歸檔 。
3.1.1 執行程式和分析
(1) 執行
root@szdc-calic-2-6:/www/linuxperformancetool/swap# ./swapexample1 複製程式碼
由於上面說的命令都可以用於分析,大家根據喜好搭配使用即可。我這裡用top,vmstat和pidstat搭配使用進行分析,可以開多幾個終端一起看。
(2) 分析 首先是使用vmstat,從下面可以看出,當程式佔用記憶體越來越大時候,出現了很高的swap io和block io,想一下,為什麼這兩個同時都增高?
root@szdc-calic-2-6:~# vmstat -a 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- rbswpdfreeinact activesisobiboincs us sy id wa st 10 1240208 18816440 715216 12702360001180000 9900 10 1240208 18086504 715220 134319880000 2223 319214 9600 10 1240208 17343176 715220 1417344400060 1906 309914 9500 10 1240208 16618392 715260 1489714000060 2351 355214 9600 10 1240208 15883220 715280 156325720000 2187 354714 9600 02 1240300 15276012 806532 1615186809202088 2365 337313 9520 02 1265792 15270100 2023920 1494620056 25500100 27536 5102 918911 9350 03 1265784 15274476 2023856 14944732400402572 2162 242500 90 100 09 1287036 15276116 2022816 1494423288 2127688 22228 2074 313600 79 210 09 1287020 15273676 2024776 14946436920922288 3563 582200 79 200 23 1286912 15271708 2024844 1494653212801281432 2989 490700 84 160 03 1286912 15271692 2024572 149465200002344 3098 454300 87 130 04 1312096 15265788 2022444 149510640 251880 26628 4946 975211 9090 複製程式碼
發現了系統問題後,我們就需要對問題進行定位了,這裡可以使用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 USERPRNIVIRTRESSHR S%CPU %MEMTIME+ COMMANDSWAP 45466 root200 10.076g216242520 S12.90.17881:36 etcd19636 146 root200000 D9.20.02:28.44 kswapd00 14179 root200 31.136g 0.029t4316 S3.3 94.80:31.86 main11.375g 147 root200000 S1.70.01:52.23 kswapd10 10737 root200 3067756606885968 S0.70.23364:41 dockerd60380 10750 root200 2898452387243096 S0.70.1 629:49.22 docker-containe79288 複製程式碼
從top的變化可以看出,pid=14179的程序一直swap一直在增高,而且記憶體佔用越來越高,其他程序雖然有出現swap增多,但是記憶體使用並沒有增高,可以判斷,該程序是導致出現swap的原因。那麼,我們再進一步進行確認。
使用pidstat判斷該pid的io情況,可以看出,是存在很大的IO
root@szdc-calic-2-6:~# 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 CSTUIDPIDkB_rd/skB_wr/s kB_ccwr/s iodelayCommand 12:55:41 CST01417971920.000.000.000main1 12:55:42 CST01417972796.040.000.000main1 12:55:43 CST01417985664.000.000.000main1 12:55:44 CST01417978128.000.000.000main1 12:55:45 CST01417969660.000.000.000main1 12:55:46 CST01417959892.000.000.000main1 複製程式碼
3.1.2 問題
這些問題都不會直接進行解答,實在想不出來的,可以到歸檔專案下面提issue或者在下面評論
(1) 為什麼例子中,只是簡單的申請記憶體,會造成swap io和block io同時增高? (2) 例子中,明明還有剩餘記憶體未被使用,可是已經開始頻繁進行swap和回收大量記憶體。 (3) golang gc時候,會把已經swap出去的記憶體再swap到實體記憶體中,再進行gc嗎? (4) 上一節中的buffer和cache中包含的是哪些?(匿名頁還是檔案對映)