今天為大家翻譯一篇來自Netflix技術部落格的 Linux Performance Analysis in 60,000 Milliseconds ,作者是著名linux核心工程師&性能優化專家Brendan D. Gregg和Netflix性能團隊。這篇文章會教你怎麼用10個常用的linux工具在60秒内完成對性能問題的初步診斷。
當你登入到linux伺服器處理性能問題的時候,最開始的一分鐘你會做些啥?
Netflix有大量的EC2雲服務主機,也有很多檢測和排查性能問題的工具。比如像雲監控工具
Atlas和執行個體分析工具
Vector。這些工具幫我們解決了大部分性能問題,但有時候我們仍需要登入到伺服器上運作一些标準的Linux性能排查工具。
綜述
在這篇文章中,Netflix團隊将展示如何用你随手可及的Linux指令行工具在60s内完成一次性能問題排查。通過以下10個指令,你可以在60秒内對系統的資源使用率和程序運作狀況有個整體的了解。首先檢視錯誤和飽和度名額,因為這兩者都很容易了解,其次就是檢視資源使用率。飽和度是指資源的負載是否超過了它所能承受的負載,這個名額可以反映出出任務隊列長度情況或者是任務等待時間的情況。
uptime
dmesg | tail
vmstat 1
mpstat -P ALL 1
pidstat 1
iostat -xz 1
free -m
sar -n DEV 1
sar -n TCP,ETCP 1
top
注意,有些指令需要安裝
sysstat
包。這些指令暴露出來的資料可以幫你完成一次
性能優化方法學的實踐,這套方法學包括檢查所有系統資源(cpu、記憶體、磁盤……)的使用率、飽和度和錯誤名額。這些指令也能讓你檢查所有的地方,通過排除法縮小排查範圍,為後續分析指明方向。
文章接下來的部分會介紹這些指令,并給出實際的例子。關于這些指令更詳細的介紹請參考相關手冊。
1. uptime
$ uptime
23:51:26 up 21:31, 1 user, load average: 30.02, 26.43, 19.02
uptime可以快速看到系統的平均負載情況。在Linux中,這些數字表示平均每秒鐘處于運作态、可執行态和不可中斷狀态(通常是磁盤IO)的任務數量。這些資料可以讓我們對整個系統資源有個整體的認識,但沒有其他工具我們依舊沒法了解根因,不過uptime依舊很值得快速瞄一眼。
那這三個數字究竟是什麼含義呢!其實這三個數字分别表示1分鐘、5分鐘、15分鐘内的平均負載情況,是通過過去某個時間視窗的資料通過指數衰減求和得到的。這三個數字可以讓你了解到過去某段時間的負載狀況。比如,如果你上線查性能問題,你看到load1遠低于load15,那你可能已經錯過這次性能問題了。
在上面的例子中,負載一直在增長,load1已經到30了,而load15隻有19,這給了我們很重要的資訊,有可能是CPU使用率高了,還得用vmstat和mpstat确認下,這兩個指令我們會在3和4中介紹。
2. dmesg|tail
$ dmesg | tail
[1880957.563150] perl invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0
[...]
[1880957.563400] Out of memory: Kill process 18694 (perl) score 246 or sacrifice child
[1880957.563408] Killed process 18694 (perl) total-vm:1972392kB, anon-rss:1953348kB, file-rss:0kB
[2320864.954447] TCP: Possible SYN flooding on port 7001. Dropping request. Check SNMP counters.
如果有的話,這條指令将會展示系統最近的10條資訊。 找出其中可能導緻性能問題的錯誤。上面這個例子中包含一條因為oom導緻程序被kill和tcp丢請求的資訊。
不要跳過這步,dmesg非常值得檢視。
3. vmstat 1
$ vmstat 1
procs ---------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
34 0 0 200889792 73708 591828 0 0 0 5 6 10 96 1 3 0 0
32 0 0 200889920 73708 591860 0 0 0 592 13284 4282 98 1 1 0 0
32 0 0 200890112 73708 591860 0 0 0 0 9501 2154 99 1 0 0 0
32 0 0 200889568 73712 591856 0 0 0 48 11900 2459 99 0 0 0 0
32 0 0 200890208 73712 591860 0 0 0 0 15898 4840 98 1 1 0 0
^C
vmstat是有個廣泛存在于各類linux系統中的指令(幾十年前為BSD所創造的),可以展出虛拟記憶體相關的概要資訊,每一行都是伺服器虛拟記憶體的關鍵統計資訊。
後面的參數
1
表示每隔1秒輸出一次。注意,輸出的第一行是自系統啟動以來的資料,而不是前一秒的,是以可以跳過第一行資料。
每列的含義
- r: 正在運作和等待運作的程序數量。這個名額可以比load更好的揭示出CPU的負載情況,因為這裡不包含I/O程序。如果r值大于CPU核數說明CPU已經飽和。
- free: 空閑記憶體的容量(機關kB),如果數字多的數不清說明你還有很多空閑記憶體可用。在下文第7條中的
指令可以更直覺看到空閑記憶體情況。free -m
- si,so: swap分區的換進和換出。如果數字不是0說明你記憶體已經不夠了,開始使用swap分區了。
- us,sy,id,wa,st: 這些是CPU平均使用時長的細緻劃分,分别是使用者時長、系統時長(核心)、空閑時長、等待IO時長、被盜用時長(被其他訪客或者Xen盜用,訪客有自己獨立的驅動域)。
對CPU時間(使用者時長+系統時長)的細緻劃分可以确認CPU是否繁忙。如果等待IO時長搞定不變,說明磁盤IO是瓶頸。這也能解釋為什麼CPU是空閑的,因為任務都因為等待IO被阻塞掉了。是以你可以将等待I/O看作是CPU空閑的另一種形式,它提供了有關為什麼它們是空閑的線索。
對于IO型的程序,系統時長非常重要,如果平均系統時長超過20%就很值得深入探究下了,這可能說明核心IO處理很低效。
上面的例子中,CPU幾乎都被使用者态所占用,平均CPU使用率也超過90%,這通常沒什麼大問題,還是重點關注下
r
這列資料吧。
4. mpstat -P ALL 1
$ mpstat -P ALL 1
Linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 CPU)
07:38:49 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
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
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
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
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
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
[...]
這個指令把每個CPU核的細緻劃分出來,從這份資料中可以看出CPU核心負載是否均衡,如果單個CPU核心出現熱點說明有單線程的應用。
5. pidstat 1
$ pidstat 1
Linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 CPU)
07:41:02 PM UID PID %usr %system %guest %CPU CPU Command
07:41:03 PM 0 9 0.00 0.94 0.00 0.94 1 rcuos/0
07:41:03 PM 0 4214 5.66 5.66 0.00 11.32 15 mesos-slave
07:41:03 PM 0 4354 0.94 0.94 0.00 1.89 8 java
07:41:03 PM 0 6521 1596.23 1.89 0.00 1598.11 27 java
07:41:03 PM 0 6564 1571.70 7.55 0.00 1579.25 28 java
07:41:03 PM 60004 60154 0.94 4.72 0.00 5.66 9 pidstat
07:41:03 PM UID PID %usr %system %guest %CPU CPU Command
07:41:04 PM 0 4214 6.00 2.00 0.00 8.00 15 mesos-slave
07:41:04 PM 0 6521 1590.00 1.00 0.00 1591.00 27 java
07:41:04 PM 0 6564 1573.00 10.00 0.00 1583.00 28 java
07:41:04 PM 108 6718 1.00 0.00 0.00 1.00 0 snmp-pass
07:41:04 PM 60004 60154 1.00 4.00 0.00 5.00 9 pidstat
^C
pidstat
有點像top指令關于每個程序的統計,和top指令不同的是它是滾動輸出而不是清屏輸出,這種模式可以很友善看過去的變化情況,也可以很友善的複制粘貼在你排查過程中。
上面的例子中,有兩個java程序消耗了大量的CPU,1591%說明這個java程序占用了将近16個核心。
6. iostat -xz 1
$ iostat -xz 1
Linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
73.96 0.00 3.73 0.03 0.06 22.21
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
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
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
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
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
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
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
[...]
^C
iostat
是檢視塊裝置負載和性能資訊最好用的工具,可以檢視以下資訊:
- r/s, w/s, rkB/s, wkB/s: 裝置每秒的讀、寫次數和讀、寫資料量(kB)。這些名額可以量化IO裝置負載,有些性能問題可能就是因為負載過高導緻的。
- await: 等待IO的毫秒數。這是應用程式所感受到的時間,包括排隊時間和等待時間。如果超過平均預期時間說明裝置已飽和或者裝置故障。
- avgqu-sz: 裝置的平均請求數。如果值大于1可能是裝置已飽和(盡管裝置通常可以并行操作請求,特别是位于多個後端磁盤前的虛拟裝置)。
- %util: 裝置的使用率。這是裝置真實忙碌的時間比例,展示了每秒裝置實際工作的時間。超過60%可能導緻裝置性能降低,當然這也取決于裝置自身。接近100%說明裝置已經飽和了。
如果儲存設備隻是由多塊磁盤組成的邏輯裝置,100%的使用率也僅僅意味着100%的時間用來處理IO了,後端實體磁盤遠遠沒有達到它們所能處理的性能極限。
請記住,磁盤I/O性能差不一定導緻應用程式出問題。許多技術通常使用了異步I/O,這樣應用程式就不會被阻塞也感受不到延遲(例如,預讀和寫Buffer)。
7. free -m
$ free -m
total used free shared buffers cached
Mem: 245998 24545 221453 83 59 541
-/+ buffers/cache: 23944 222053
Swap: 0 0 0
最右邊有兩列buffers和cached
- buffers: 緩沖區,用于塊裝置IO。
- cached: 記憶體頁緩存,用在檔案系統。
我們隻需要檢查下它們的大小是否接近于0,接近0可能導緻更高的磁盤I/O(使用iostat進行确認)和更差的性能。上面的例子看起來很好,每一項都有很多兆。
“-/+ buffers/cache” 為已使用和空閑記憶體大小提供了明确的值。linux用空閑記憶體作為cache,如果應用需要更多記憶體也可以很快釋放掉,是以cached部分的記憶體也應當包含在free列裡,這一行資料就是這樣,這裡可能讓人摸不着頭腦,更詳細内容可以檢視這個網頁
linuxatemyram.com/。
如果linux系統用了ZFS會更讓人迷惑,因為ZFS有自己的檔案系統緩存,
free -m
并不能反映出這些檔案緩存的大小。是以可能出現看起來記憶體不足,但實際上可以按需從ZFS cache裡釋放一些記憶體。
8. sar -n DEV 1
$ sar -n DEV 1
Linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 CPU)
12:16:48 AM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
12:16:49 AM eth0 18763.00 5032.00 20686.42 478.30 0.00 0.00 0.00 0.00
12:16:49 AM lo 14.00 14.00 1.36 1.36 0.00 0.00 0.00 0.00
12:16:49 AM docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
12:16:49 AM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
12:16:50 AM eth0 19763.00 5101.00 21999.10 482.56 0.00 0.00 0.00 0.00
12:16:50 AM lo 20.00 20.00 3.25 3.25 0.00 0.00 0.00 0.00
12:16:50 AM docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
^C
這個指令可以檢視網絡吞吐量,rxkB/s和txkB/s,可以度量工作負載,也可以檢視是否達到了限制。在上面的例子中,eth0接收達到了22MB/s,也就是176Ms/S(遠低于1Gb/s的限制)。
這個版本也有個%ifutil來表示裝置使用率(全雙工的兩個方向的最大值),我們用Brendan的
nicstat也可以檢視。就像使用nicstat一樣,很難得到正确的結果,而且在本例中似乎不能正常工作(0.00)。
9. sar -n TCP,ETCP 1
$ sar -n TCP,ETCP 1
Linux 3.13.0-49-generic (titanclusters-xxxxx) 07/14/2015 _x86_64_ (32 CPU)
12:17:19 AM active/s passive/s iseg/s oseg/s
12:17:20 AM 1.00 0.00 10233.00 18846.00
12:17:19 AM atmptf/s estres/s retrans/s isegerr/s orsts/s
12:17:20 AM 0.00 0.00 0.00 0.00 0.00
12:17:20 AM active/s passive/s iseg/s oseg/s
12:17:21 AM 1.00 0.00 8359.00 6039.00
12:17:20 AM atmptf/s estres/s retrans/s isegerr/s orsts/s
12:17:21 AM 0.00 0.00 0.00 0.00 0.00
^C
這個指令可以檢視tcp名額資料,包括:
- active/s: 每秒鐘本地發起的主動連接配接數(比如調用 connect())。
- passive/s: 每秒鐘收到的遠端被動連接配接數(比如調用accept())。
- retrans/s: 每秒鐘tcp重傳數。
主動和被動連接配接數通常可以作為伺服器負載的粗略度量:新接受連接配接的數量(被動)和下遊連接配接的數量(主動)。可以簡單将active視為出,将passive視為入,但這并不完全正确(例如,localhost發起到localhost的連接配接)。
重傳數可以看做是網絡或者服務問題的一個信号,可能是網絡不可靠(比如公網),或者是因為服務已經過載而導緻的丢包。上面這個例子中每秒隻有一個建立連接配接。
10. top
$ top
top - 00:15:40 up 21:56, 1 user, load average: 31.09, 29.87, 29.92
Tasks: 871 total, 1 running, 868 sleeping, 0 stopped, 2 zombie
%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
KiB Mem: 25190241+total, 24921688 used, 22698073+free, 60448 buffers
KiB Swap: 0 total, 0 used, 0 free. 554208 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20248 root 20 0 0.227t 0.012t 18748 S 3090 5.2 29812:58 java
4213 root 20 0 2722544 64640 44232 S 23.5 0.0 233:35.37 mesos-slave
66128 titancl+ 20 0 24344 2332 1172 R 1.0 0.0 0:00.07 top
5235 root 20 0 38.227g 547004 49996 S 0.7 0.2 2:02.74 java
4299 root 20 0 20.015g 2.682g 16836 S 0.3 1.1 33:14.42 java
1 root 20 0 33620 2920 1496 S 0.0 0.0 0:03.82 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:05.35 ksoftirqd/0
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
6 root 20 0 0 0 0 S 0.0 0.0 0:06.94 kworker/u256:0
8 root 20 0 0 0 0 S 0.0 0.0 2:38.05 rcu_sched
top指令中包含很多我們前面已經提到過的名額,可以友善地運作它來檢視名額的變化。
top的一個缺點是,top不像vmstat和pidstat等提供滾動輸出的工具一樣,它看不到之前的資料。如果你沒有足夠快地暫停輸出(Ctrl-S暫停,Ctrl-Q繼續),螢幕上的資料就會被清除,你很難截取到證據。
後續分析
還有很多指令行工具和方法可以深入挖掘,參見Brendan的
Linux性能工具指南,裡面列出了超過40種工具,包含了觀測、基準測試、調優、靜态性能調優、概要分析和追蹤。