60,000 毫秒內對 Linux 的效能診斷
當你為了解決一個效能問題登入到一臺 Linux 伺服器:在第一分鐘你應該檢查些什麼?
在 Netflix,我們有一個巨大的 EC2 Linux 雲,以及大量的效能分析工具來監控和診斷其效能。其中包括用於雲監控的 Atlas,以及用於按需例項分析的 Vector。雖然這些工具可以幫助我們解決大多數問題,但我們有時仍需要登入到一個伺服器例項,並執行一些標準 Linux 效能工具。
在這篇文章中,Netflix Performance Engineering 團隊將會向你講解在命令列中進行一次最佳的效能分析的前 60 秒要做的事,使用的是你應該可以得到的標準 Linux 工具。
前六十秒:總覽
通過執行下面十個命令,你就能在六十秒內粗略地瞭解系統正在執行的程式及資源使用情況。通過檢視這些命令輸出的錯誤資訊和資源飽和度(它們都很容易看懂),你可以接下來對資源進行優化。飽和是指某個資源的負載超出了其能夠處理的限度。一旦出現飽和,它通常會在請求佇列的長度或等待時間上暴露出來。
1 2 3 4 5 6 7 8 9 10 |
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 軟體包。這些命令展示出來的資訊能夠幫你實施 USE 方法(一種用於定位效能瓶頸的方法),比如檢查各種資源(如 CPU、記憶體、磁碟等)的使用率、飽和度和錯誤資訊。另外在定位問題的過程中,你可以通過使用這些命令來排除某些導致問題的可能性,幫助你縮小檢查範圍,為下一步檢查指明方向。
下面的章節將以在一個生產環境上執行這些命令作為例子,簡單介紹這些命令。若想詳細瞭解這些工具的使用方法,請參考它們的 man 文件。
1. uptime
1 2 |
$ uptime 23:51:26 up 21:31, 1 user, load average: 30.02, 26.43, 19.02 |
這是一種用來快速檢視系統平均負載的方法,它表明了系統中有多少要執行的任務(程式)。在 Linux 系統中,這些數字包含了需要在 CPU 中執行的程式以及正在等待 I/O(通常是磁碟 I/O)的程式。它僅僅是對系統負載的一個粗略展示,稍微看下即可。你還需要其他工具來進一步瞭解具體情況。
這三個數字展示的是一分鐘、五分鐘和十五分鐘內系統的負載總量平均值按照指數比例壓縮得到的結果。從中我們可以看到系統的負載是如何隨時間變化的。比方你在檢查一個問題,然後看到 1 分鐘對應的值遠小於 15 分鐘的值,那麼可能說明這個問題已經過去了,你沒能及時觀察到。
在上面這個例子中,系統負載在隨著時間增加,因為最近一分鐘的負載值超過了 30,而 15 分鐘的平均負載則只有 19。這樣顯著的差距包含了很多含義,比方 CPU 負載。若要進一步確認的話,則要執行 vmstat 或 mpstat 命令,這兩個命令請參考後面的第 3 和第 4 章節。
2. dmesg | tail
1 2 3 4 5 |
$ 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-killer,以及 TCP 丟棄一個請求。
千萬不要錯過這一步!dmesg 命令永遠值得一試。
3. vmstat 1
1 2 3 4 5 6 7 8 |
$ vmstat 1procs ---------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(8) 是虛擬記憶體統計的簡稱,其是一個常用工具(幾十年前為了 BSD 所建立)。其在每行列印一條關鍵的伺服器的統計摘要。
vmstat 命令指定一個引數 1 執行,來列印每一秒的統計摘要。(這個版本的 vmstat)輸出的第一行的那些列,顯式的是開機以來的平均值,而不是前一秒的值。現在,我們跳過第一行,除非你想要了解並記住每一列。
檢查這些列:
- r:CPU 中正在執行和等待執行的程式的數量。其提供了一個比平均負載更好的訊號來確定 CPU 是否飽和,因為其不包含 I/O。解釋:“r”的值大於了 CPU 的數量就表示已經飽和了。
- free:以 kb 為單位顯式的空閒記憶體。如果數字位數很多,說明你有足夠的空閒記憶體。“free -m” 命令,是下面的第七個命令,其可以更好的說明空閒記憶體的狀態。
- si, so:Swap-ins 和 swap-outs。如果它們不是零,則代表你的記憶體不足了。
- us, sy, id, wa, st:這些都是平均了所有 CPU 的 CPU 分解時間。它們分別是使用者時間(user)、系統時間(核心)(system)、空閒(idle)、等待 I/O(wait)、以及佔用時間(stolen)(被其他訪客,或使用 Xen,訪客自己獨立的驅動域)。
CPU 分解時間將會通過使用者時間加系統時間確認 CPU 是否為忙碌狀態。等待 I/O 的時間一直不變則表明了一個磁碟瓶頸;這就是 CPU 的閒置,因為任務都阻塞在等待掛起磁碟 I/O 上了。你可以把等待 I/O 當成是 CPU 閒置的另一種形式,其給出了為什麼 CPU 閒置的一個線索。
對於 I/O 處理來說,系統時間是很重要的。一個高於 20% 的平均系統時間,可以值得進一步的探討:也許核心在處理 I/O 時效率太低了。
在上面的例子中,CPU 時間幾乎完全花在了使用者級,表明應用程式佔用了太多 CPU 時間。而 CPU 的平均使用率也在 90% 以上。這不一定是一個問題;檢查一下“r”列中的飽和度。
4. mpstat -P ALL 1
1 2 3 4 5 6 7 8 9 |
$ mpstat -P ALL 1Linux 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ pidstat 1Linux 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 |
1 2 |
pidstat 命令有點像 top 命令對每個程式的統計摘要,但迴圈列印一個滾動的統計摘要來代替 top 的刷屏。其可用於實時檢視,同時也可將你所看到的東西(複製貼上)到你的調查記錄中。 上面的例子表明兩個 Java 程式正在消耗 CPU。%CPU 這列是所有 CPU 合計的;1591% 表示這個 Java 程式消耗了將近 16 個 CPU。 |
6. iostat -xz 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ iostat -xz 1Linux 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 |
這是用於檢視塊裝置(磁碟)情況的一個很棒的工具,無論是對工作負載還是效能表現來說。檢視個列:
- r/s, w/s, rkB/s, wkB/s:這些分別代表該裝置每秒的讀次數、寫次數、讀取 kb 數,和寫入 kb 數。這些用於描述工作負載。效能問題可能僅僅是由於施加了過大的負載。
- await:以毫秒為單位的 I/O 平均消耗時間。這是應用程式消耗的實際時間,因為它包括了排隊時間和處理時間。比預期更大的平均時間可能意味著裝置的飽和,或裝置出了問題。
- avgqu-sz:向裝置發出的請求的平均數量。值大於 1 說明已經飽和了(雖說裝置可以並行處理請求,尤其是由多個磁碟組成的虛擬裝置。)
- %util:裝置利用率。這個值是一個顯示出該裝置在工作時每秒處於忙碌狀態的百分比。若值大於 60%,通常表明效能不佳(可以從 await 中看出),雖然它取決於裝置本身。值接近 100% 通常意味著已飽和。
如果該儲存裝置是一個面向很多後端磁碟的邏輯磁碟裝置,則 100% 利用率可能只是意味著當前正在處理某些 I/O 佔用,然而,後端磁碟可能遠未飽和,並且可能能夠處理更多的工作。
請記住,磁碟 I/O 效能較差不一定是程式的問題。許多技術通常是非同步 I/O,使應用程式不會被阻塞並遭受延遲(例如,預讀,以及寫緩衝)。
7. free -m
1 2 3 4 5 |
$ free -m total used free shared buffers cached Mem: 245998 24545 221453 83 59 541 -/+ buffers/cache: 23944 222053 Swap: 0 0 0 |
右邊的兩列顯式:
- buffers:用於塊裝置 I/O 的緩衝區快取。
- cached:用於檔案系統的頁面快取。
我們只是想要檢查這些不接近零的大小,其可能會導致更高磁碟 I/O(使用 iostat 確認),和更糟糕的效能。上面的例子看起來還不錯,每一列均有很多 M 個大小。
比起第一行,-/+ buffers/cache 提供的記憶體使用量會更加準確些。Linux 會把暫時用不上的記憶體用作快取,一旦應用需要的時候就立刻重新分配給它。所以部分被用作快取的記憶體其實也算是空閒的記憶體。為了解釋這一點, 甚至有人專門建了個網站: linuxatemyram。
如果你在 Linux 上安裝了 ZFS,這一點會變得更加困惑,因為 ZFS 它自己的檔案系統快取不算入free -m。有時候發現系統已經沒有多少空閒記憶體可用了,其實記憶體卻都待在 ZFS 的快取裡。
8. sar -n DEV 1
1 2 3 4 5 6 7 8 9 10 11 12 |
$ sar -n DEV 1Linux 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 接收的流量達到 22Mbytes/s,也即 176Mbits/sec(限額是 1Gbit/sec)
我們用的版本中還提供了 %ifutil 作為裝置使用率(接收和傳送的最大值)的指標。我們也可以用 Brendan 的 nicstat 工具計量這個值。一如 nicstat,sar 顯示的這個值是很難精確取得的,在這個例子裡面,它就沒在正常的工作(0.00)。
9. sar -n TCP,ETCP 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ sar -n TCP,ETCP 1Linux 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:每秒本地發起 TCP 連線數(例如,通過 connect())。
- passive/s:每秒遠端發起的 TCP 連線數(例如,通過 accept())。
- retrans/s:每秒重傳 TCP 次數。
active 和 passive 的連線數往往對於描述一個粗略衡量伺服器負載是非常有用的:新接受的連線數(passive),下行連線數(active)。可以理解為 active 連線是對外的,而 passive 連線是對內的,雖然嚴格來說並不完全正確(例如,一個 localhost 到 localhost 的連線)。
重傳是出現一個網路和伺服器問題的一個徵兆。其可能是由於一個不可靠的網路(例如,公網)造成的,或許也有可能是由於伺服器過載並丟包。上面的例子顯示了每秒只有一個新的 TCP 連線。
10. top
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$ toptop - 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 的一個缺點是,很難看到資料隨時間變動的趨勢。vmstat 和 pidstat 提供的滾動輸出會更清楚一些。如果你不以足夠快的速度暫停輸出(Ctrl-S 暫停,Ctrl-Q 繼續),一些間歇性問題的線索也可能由於被清屏而丟失。
後續的分析
還有更多命令和方法可以用於更深入的分析。檢視 Brendan 在 Velocity 2015 大會上的 Linux 效能工具教程,其中包含了超過 40 個命令,涵蓋了可觀測性、標杆管理、調優、靜態效能調優、分析,和跟蹤等方面。
在全網規模應對系統的可靠性和效能問題是我們的愛好之一。如果你想要加入我們來一起應對這種挑戰,我們正在招聘!