1. 程式人生 > >Linux工具效能調優系列三:swap問題定位

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中包含的是哪些?(匿名頁還是檔案對映)

四,參考文獻

1, linuxperf.com/?p=142

2, cloud.tencent.com/developer/a…