天天看點

Linux 性能分析的前 60 秒Linux 性能分析的前 60 秒

Linux 性能分析的前 60 秒Linux 性能分析的前 60 秒

為了解決性能問題,你登入了一台 linux 伺服器,在最開始的一分鐘内需要檢視什麼?

在這篇文章裡,netflix performance engineering 團隊将使用居家常備的 linux 标準指令行工具,示範在性能調查最開始的60秒裡要幹的事,

<a></a>

運作下面10個指令,你可以在60秒内就對系統資源的使用情況和程序的運作狀況有大體上的了解。無非是先檢視錯誤資訊和飽和名額,再看下資源的使用量。這裡“飽和”的意思是,某項資源供不應求,已經造成了請求隊列的堆積,或者延長了等待時間。

<code>uptime</code>

<code>dmesg | tail</code>

<code>vmstat 1</code>

<code>mpstat -p all 1</code>

<code>pidstat 1</code>

<code>iostat -xz 1</code>

<code>free -m</code>

<code>sar -n dev 1</code>

<code>sar -n tcp,etcp 1</code>

<code>top</code>

接下來的章節裡我們将結合實際例子講解這些指令。如果你想了解更多的相關資訊,請檢視它們的 man page。

<code>$ uptime</code>

<code>23:51:26 up 21:31, 1 user, load average: 30.02, 26.43, 19.02</code>

這個指令顯示了要運作的任務(程序)數,通過它能夠快速了解系統的平均負載。在 linux 上,這些數值既包括正在或準備運作在 cpu 上的程序,也包括阻塞在不可中斷 i/o(通常是磁盤 i/o)上的程序。它展示了資源負載(或需求)的大緻情況,不過進一步的解讀還有待其它工具的協助。對它的具體數值不用太較真。

最右的三個數值分别是1分鐘、5分鐘、15分鐘系統負載的移動平均值。它們共同展現了負載随時間變動的情況。舉個例子,假設你被要求去檢查一個出了問題的伺服器,而它最近1分鐘的負載遠遠低于15分鐘的負載,那麼你很可能已經撲了個空。

在上面的例子中,負載均值最近呈上升态勢,其中1分鐘值高達30,而15分鐘值僅有19。這種現象有許多種解釋,很有可能是對 cpu 的争用;該系列的第3個和第4個指令——<code>vmstat</code>和<code>mpstat</code>——可以幫助我們進一步确定問題所在。

<code>$ dmesg | tail</code>

<code>[1880957.563150] perl invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0</code>

<code>[...]</code>

<code>[1880957.563400] out of memory: kill process 18694 (perl) score 246 or sacrifice child</code>

<code>[1880957.563408] killed process 18694 (perl) total-vm:1972392kb, anon-rss:1953348kb, file-rss:0kb</code>

<code>[2320864.954447] tcp: possible syn flooding on port 7001. dropping request. check snmp counters.</code>

這個指令顯示了最新的10個系統資訊,如果有的話。注意會導緻性能問題的錯誤資訊。上面的例子裡就包括對過多占用記憶體的某程序的死刑判決,還有丢棄 tcp 請求的公告。

不要漏了這一步!檢查<code>dmesg</code>總是值得的。

<code>$ vmstat 1</code>

<code>procs ---------memory---------- ---swap-- -----io---- -system-- ------cpu-----</code>

<code>r b swpd free buff cache si so bi bo in cs us sy id wa st</code>

<code>34 0 0 200889792 73708 591828 0 0 0 5 6 10 96 1 3 0 0</code>

<code>32 0 0 200889920 73708 591860 0 0 0 592 13284 4282 98 1 1 0 0</code>

<code>32 0 0 200890112 73708 591860 0 0 0 0 9501 2154 99 1 0 0 0</code>

<code>32 0 0 200889568 73712 591856 0 0 0 48 11900 2459 99 0 0 0 0</code>

<code>32 0 0 200890208 73712 591860 0 0 0 0 15898 4840 98 1 1 0 0</code>

<code>^c</code>

<code>vmstat(8)</code>,是 “virtual memory stat” 的簡稱,幾十年前就已經包括在 bsd 套件之中,一直以來都是居家常備的工具。它會逐行輸出伺服器關鍵資料的統計結果。

通過指定1作為 vmstat 的輸入參數,它會輸出每一秒内的統計結果。(在我們目前使用的)vmstat 輸出的第一行資料是從啟動到現在的平均資料,而不是前一秒的資料。是以我們可以跳過第一行,看看後面幾行的情況。

檢查下面各列:

r:等待 cpu 的程序數。該名額能更好地判定 cpu 是否飽和,因為它不包括 i/o。簡單地說,r 值高于 cpu 數時就意味着飽和。

free:空閑的記憶體千位元組數。如果你數不清有多少位,就說明系統記憶體是充足的。接下來要講到的第7個指令,<code>free -m</code>,能夠更清楚地說明空閑記憶體的狀态。

si,so:交換分區換入和換出。如果它們不為零,意味着記憶體已經不足,開始動用交換空間的存糧了。

us,sy,id,wa,st:它們是所有 cpu 的使用百分比。它們分别表示 使用者态用時user time,系統态用時system time(處于核心态的時間),空閑idle,i/o 等待wait i/o和偷去的時間steal time(被其它租戶,或者是租戶自己的 xen 隔離裝置驅動域isolated driver domain所占用的時間)。

通過相加 us 和 sy 的百分比,你可以确定 cpu 是否處于忙碌狀态。一個持續不變的 i/o 等待意味着瓶頸在硬碟上,這種情況往往伴随着 cpu 的空閑,因為任務都卡在磁盤 i/o 上了。你可以把 i/o 等待當作 cpu 空閑的另一種形式,它額外給出了 cpu 空閑的線索。

i/o 處理同樣會消耗系統時間。一個高于20%的平均系統時間,往往值得進一步發掘:也許系統花在 i/o 的時間太長了。

在上面的例子中,cpu 基本把時間花在使用者态裡面,意味着跑在上面的應用占用了大部分時間。此外,cpu 平均使用率在90%之上。這不一定是個問題;檢查下“r”列,看看是否飽和了。

<code>$ mpstat -p all 1</code>

<code>linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 cpu)</code>

<code></code>

<code>07:38:49 pm cpu %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle</code>

<code>07:38:50 pm all 98.47 0.00 0.75 0.00 0.00 0.00 0.00 0.00 0.00 0.78</code>

<code>07:38:50 pm 0 96.04 0.00 2.97 0.00 0.00 0.00 0.00 0.00 0.00 0.99</code>

<code>07:38:50 pm 1 97.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 2.00</code>

<code>07:38:50 pm 2 98.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 1.00</code>

<code>07:38:50 pm 3 96.97 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3.03</code>

這個指令顯示每個 cpu 的時間使用百分比,你可以用它來檢查 cpu 是否存在負載不均衡。單個過于忙碌的 cpu 可能意味着整個應用隻有單個線程在工作。

<code>$ pidstat 1</code>

<code>linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 cpu)</code>

<code>07:41:02 pm uid pid %usr %system %guest %cpu cpu command</code>

<code>07:41:03 pm 0 9 0.00 0.94 0.00 0.94 1 rcuos/0</code>

<code>07:41:03 pm 0 4214 5.66 5.66 0.00 11.32 15 mesos-slave</code>

<code>07:41:03 pm 0 4354 0.94 0.94 0.00 1.89 8 java</code>

<code>07:41:03 pm 0 6521 1596.23 1.89 0.00 1598.11 27 java</code>

<code>07:41:03 pm 0 6564 1571.70 7.55 0.00 1579.25 28 java</code>

<code>07:41:03 pm 60004 60154 0.94 4.72 0.00 5.66 9 pidstat</code>

<code>07:41:03 pm uid pid %usr %system %guest %cpu cpu command</code>

<code>07:41:04 pm 0 4214 6.00 2.00 0.00 8.00 15 mesos-slave</code>

<code>07:41:04 pm 0 6521 1590.00 1.00 0.00 1591.00 27 java</code>

<code>07:41:04 pm 0 6564 1573.00 10.00 0.00 1583.00 28 java</code>

<code>07:41:04 pm 108 6718 1.00 0.00 0.00 1.00 0 snmp-pass</code>

<code>07:41:04 pm 60004 60154 1.00 4.00 0.00 5.00 9 pidstat</code>

<code>pidstat</code>看上去就像<code>top</code>,不過<code>top</code>的輸出會覆寫掉之前的輸出,而<code>pidstat</code>的輸出則添加在之前的輸出的後面。這有利于觀察資料随時間的變動情況,也便于把你看到的内容複制粘貼到調查報告中。

上面的例子表明,cpu 主要消耗在兩個 java 程序上。<code>%cpu</code>列是在各個 cpu 上的使用量的總和;<code>1591%</code>意味着 java 程序消耗了将近16個 cpu。

<code>$ iostat -xz 1</code>

<code>avg-cpu: %user %nice %system %iowait %steal %idle</code>

<code>73.96 0.00 3.73 0.03 0.06 22.21</code>

<code>device: rrqm/s wrqm/s r/s w/s rkb/s wkb/s avgrq-sz avgqu-sz await r_await w_await svctm %util</code>

<code>xvda 0.00 0.23 0.21 0.18 4.52 2.08 34.37 0.00 9.98 13.80 5.42 2.44 0.09</code>

<code>xvdb 0.01 0.00 1.02 8.94 127.97 598.53 145.79 0.00 0.43 1.78 0.28 0.25 0.25</code>

<code>xvdc 0.01 0.00 1.02 8.86 127.79 595.94 146.50 0.00 0.45 1.82 0.30 0.27 0.26</code>

<code>dm-0 0.00 0.00 0.69 2.32 10.47 31.69 28.01 0.01 3.23 0.71 3.98 0.13 0.04</code>

<code>dm-1 0.00 0.00 0.00 0.94 0.01 3.78 8.00 0.33 345.84 0.04 346.81 0.01 0.00</code>

<code>dm-2 0.00 0.00 0.09 0.07 1.35 0.36 22.50 0.00 2.55 0.23 5.62 1.78 0.03</code>

這個指令可以弄清塊裝置(磁盤)的狀況,包括工作負載和處理性能。注意以下各項:

r/s,w/s,rkb/s,wkb/s:分别表示每秒裝置讀次數,寫次數,讀的 kb 數,寫的 kb 數。它們描述了磁盤的工作負載。也許性能問題就是由過高的負載所造成的。

await:i/o 平均時間,以毫秒作機關。它是應用中 i/o 處理所實際消耗的時間,因為其中既包括排隊用時也包括處理用時。如果它比預期的大,就意味着裝置飽和了,或者裝置出了問題。

avgqu-sz:配置設定給裝置的平均請求數。大于1表示裝置已經飽和了。(不過有些裝置可以并行處理請求,比如由多個磁盤組成的虛拟裝置)

%util:裝置使用率。這個值顯示了裝置每秒内工作時間的百分比,一般都處于高位。低于60%通常是低性能的表現(也可以從 await 中看出),不過這個得看裝置的類型。接近100%通常意味着飽和。

如果某個儲存設備是由多個實體磁盤組成的邏輯磁盤裝置,100%的使用率可能隻是意味着 i/o 占用。

請牢記于心,磁盤 i/o 性能低不一定是個問題。應用的 i/o 往往是異步的(比如預讀read-ahead和寫緩沖buffering for writes),是以不一定會被阻塞并遭受延遲。

<code>$ free -m</code>

<code>total used free shared buffers cached</code>

<code>mem: 245998 24545 221453 83 59 541</code>

<code>-/+ buffers/cache: 23944 222053</code>

<code>swap: 0 0 0</code>

右邊的兩列顯示:

buffers:用于塊裝置 i/o 的緩沖區緩存

cached:用于檔案系統的頁緩存

它們的值接近于0時,往往導緻較高的磁盤 i/o(可以通過 <code>iostat</code> 确認)和糟糕的性能。上面的例子裡沒有這個問題,每一列都有好幾 m 呢。

如果你在 linux 上安裝了 zfs,正如我們在一些服務上所做的,這一點會變得更加迷惑,因為 zfs 它自己的檔案系統緩存不算入<code>free -m</code>。有時系統看上去已經沒有多少空閑記憶體可用了,其實記憶體都待在 zfs 的緩存裡呢。

<code>$ sar -n dev 1</code>

<code>linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 cpu)</code>

<code>12:16:48 am iface rxpck/s txpck/s rxkb/s txkb/s rxcmp/s txcmp/s rxmcst/s %ifutil</code>

<code>12:16:49 am eth0 18763.00 5032.00 20686.42 478.30 0.00 0.00 0.00 0.00</code>

<code>12:16:49 am lo 14.00 14.00 1.36 1.36 0.00 0.00 0.00 0.00</code>

<code>12:16:49 am docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00</code>

<code>12:16:49 am iface rxpck/s txpck/s rxkb/s txkb/s rxcmp/s txcmp/s rxmcst/s %ifutil</code>

<code>12:16:50 am eth0 19763.00 5101.00 21999.10 482.56 0.00 0.00 0.00 0.00</code>

<code>12:16:50 am lo 20.00 20.00 3.25 3.25 0.00 0.00 0.00 0.00</code>

<code>12:16:50 am docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00</code>

這個指令可以用于檢查網絡流量的工作負載:rxkb/s 和 txkb/s,以及它是否達到限額了。上面的例子中,<code>eth0</code>接收的流量達到 22mbytes/s,也即 176mbits/sec(限額是 1gbit/sec)

<code>$ sar -n tcp,etcp 1</code>

<code>12:17:19 am active/s passive/s iseg/s oseg/s</code>

<code>12:17:20 am 1.00 0.00 10233.00 18846.00</code>

<code>12:17:19 am atmptf/s estres/s retrans/s isegerr/s orsts/s</code>

<code>12:17:20 am 0.00 0.00 0.00 0.00 0.00</code>

<code>12:17:20 am active/s passive/s iseg/s oseg/s</code>

<code>12:17:21 am 1.00 0.00 8359.00 6039.00</code>

<code>12:17:20 am atmptf/s estres/s retrans/s isegerr/s orsts/s</code>

<code>12:17:21 am 0.00 0.00 0.00 0.00 0.00</code>

這個指令顯示一些關鍵tcp名額的彙總。其中包括:

active/s:本地每秒建立的 tcp 連接配接數(比如 concept() 建立的)

passive/s:遠端每秒建立的 tcp 連接配接數(比如 accept() 建立的)

retrans/s:每秒 tcp 重傳次數

主動連接配接數active和被動連接配接數passive通常可以用來粗略地描述系統負載。可以認為主動連接配接是對外的,而被動連接配接是對内的,雖然嚴格來說不完全是這個樣子。(比如,一個從 localhost 到 localhost 的連接配接)

重傳是網絡或系統問題的一個信号;它可能是不可靠的網絡(比如公網)所造成的,也有可能是伺服器已經過載并開始丢包。在上面的例子中,每秒隻建立一個新的 tcp 連接配接。

<code>$ top</code>

<code>top - 00:15:40 up 21:56, 1 user, load average: 31.09, 29.87, 29.92</code>

<code>tasks: 871 total, 1 running, 868 sleeping, 0 stopped, 2 zombie</code>

<code>%cpu(s): 96.8 us, 0.4 sy, 0.0 ni, 2.7 id, 0.1 wa, 0.0 hi, 0.0 si, 0.0 st</code>

<code>kib mem: 25190241+total, 24921688 used, 22698073+free, 60448 buffers</code>

<code>kib swap: 0 total, 0 used, 0 free. 554208 cached mem</code>

<code>pid user pr ni virt res shr s %cpu %mem time+ command</code>

<code>20248 root 20 0 0.227t 0.012t 18748 s 3090 5.2 29812:58 java</code>

<code>4213 root 20 0 2722544 64640 44232 s 23.5 0.0 233:35.37 mesos-slave</code>

<code>66128 titancl+ 20 0 24344 2332 1172 r 1.0 0.0 0:00.07 top</code>

<code>5235 root 20 0 38.227g 547004 49996 s 0.7 0.2 2:02.74 java</code>

<code>4299 root 20 0 20.015g 2.682g 16836 s 0.3 1.1 33:14.42 java</code>

<code>1 root 20 0 33620 2920 1496 s 0.0 0.0 0:03.82 init</code>

<code>2 root 20 0 0 0 0 s 0.0 0.0 0:00.02 kthreadd</code>

<code>3 root 20 0 0 0 0 s 0.0 0.0 0:05.35 ksoftirqd/0</code>

<code>5 root 0 -20 0 0 0 s 0.0 0.0 0:00.00 kworker/0:0h</code>

<code>6 root 20 0 0 0 0 s 0.0 0.0 0:06.94 kworker/u256:0</code>

<code>8 root 20 0 0 0 0 s 0.0 0.0 2:38.05 rcu_sched</code>

<code>top</code>指令包括很多我們之前檢查過的名額。它适合用來檢視相比于之前的指令輸出的結果,負載有了哪些變動。

不能清晰顯示資料随時間變動的情況,這是<code>top</code>的一個缺點。相較而言,<code>vmstat</code>和<code>pidstat</code>的輸出不會覆寫掉之前的結果,是以更适合檢視資料随時間的變動情況。另外,如果你不能及時暫停<code>top</code>的輸出(<code>ctrl-s</code> 暫停,<code>ctrl-q</code> 繼續),也許某些關鍵線索會湮滅在新的輸出中。

本文來自雲栖社群合作夥伴“linux中國”

原文釋出時間為:2013-04-02.