性能分析的前提是將應用程序內部的運行情況以及應用運行環境的情況以一種可視化的方式更加直接的展示出來,如何來達到這種可視化的展現呢?咱們須要配合使用操做系統中集成的程序監控工具和 Java 中內置的監控分析工具來進行 Java 程序的性能分析。本文爲系列文章,共三篇分別介紹這幾類工具。在本文中將介紹操做系統中的性能監控工具。html
操做系統中的程序性能監控工具並不是只針對於 Java 程序,適用於全部運行其中的程序。在基於 UNIX 的操做系統中,有許多命令行工具能夠用來監控程序的運行情況,例如 sar, vmstat, iostat,prstat 等等。在 Windows 操做系統中,既有圖形化用戶界面的資源監控器 Perfmon(Performance Monitor),也有如 typeperf 的命令行工具。java
進行性能測試時,咱們須要經過操做系統提供的工具收集操做系統中的各種資源監控數據,包括 CPU、內存和硬盤的使用數據,若是被測試程序使用了網絡,還須要收集網絡使用數據。只有收集的數據足夠完整和充分,性能測試的結果纔會更準確,性能分析也會更加容易進行。下面將首先介紹在 UNIX/類 UNIX 系統中各種資源的監控和分析的方法。ios
CPU 使用時間分爲兩類:用戶時間(User Time)和系統時間(System Time),系統時間在 Windows 系統中被稱爲特權時間(Privileged Time)。用戶時間爲 CPU 執行應用程序代碼的時間,而系統時間則爲 CPU 執行操做系統內核代碼的時間比例。系統時間與應用程序自己有關,例如當應用程序執行 I/O 操做時,操做系統內核將會執行從硬盤讀取文件的代碼,或者執行向網絡數據緩存中寫入數據的代碼。應用程序中任何須要使用操做系統底層資源的行爲都會致使應用程序佔用更多的系統時間。數據庫
性能調優的終極目標是在單位時間內最大限度提升 CPU 使用率。CPU 使用率是在一個特定時間間隔內的平均值,這個時間間隔能夠是 30 秒,也能夠是 1 秒。好比,一個程序須要 10 分鐘執行完成,在此期間該程序的 CPU 使用率爲 50%。當對程序代碼優化以後,CPU 使用率提升爲 100%,那麼該程序的性能將提高一倍,只須要 5 分鐘執行完成。當該程序再次優化代碼使用 2 個 CPU,CPU 的使用率依然爲 100%,那麼該程序將只須要 2.5 分鐘執行結束。從這個例子能夠看出,CPU 使用率可以反應程序使用 CPU 的效率,CPU 使用率越高程序性能越好,反之亦然。緩存
在 Linux 操做系統中執行 vmstat 5 命令,將會獲得如清單 1 中的數據(每 5 秒增長一行)。爲了易於理解,此例中的程序只使用單線程運行,在多線程環境中一樣適用。從示例數據中第一行數據能夠知道,在 5 秒內,CPU 一共被使用了 2.25 秒(5*(37%+8%)),其中 37%的時間用於執行用戶代碼,8%的時間用戶執行系統代碼。剩餘的 2.75 秒 CPU 處於閒置狀態(idle)。安全
procs -----------memory--------------- ----swap---- ---io--- -----system------ ----------CPU-------r b swpd free buff cache si so bi bo in cs us sy id wa st2 0 236456 2259632 200052 730348 0 0 1 6 1 1 37 8 55 0 02 0 236456 2259624 200052 730348 0 0 0 10 179 332 40 7 53 0 02 0 236456 2259624 200052 730348 0 0 0 20 180 356 56 7 37 0 0
如下三點緣由會形成 CPU 閒置:bash
前兩種狀況比較容易理解,也有對應的調優方式。針對緣由一,若是可以減小鎖的競爭,或者調整數據庫返回請求資源的性能,那麼應用程序會運行的更快;對於緣由二,優化請求響應方,提升響應速度;那麼在其餘條件不變的狀況下,應用程序會運行的更快,CPU 使用率也會提升。服務器
第三種狀況當應用程序有事去作時,CPU 將利用 CPU 週期去執行應用程序的代碼。這是一條通用的規則。當執行一段無限循環的代碼(以下所示)時,它將會再消耗一個 CPU 100%的時間。若是 CPU 的使用率並無達到 100%,意味着操做系統應該執行無限循環,但它並無去作而是處於閒置狀態。這種狀況對於無限循環並無多少影響,可是若是咱們的程序是用來計算一個表達式的結果,那麼這種狀況將會致使計算的速度變慢。網絡
#!/bin/bashwhile truedo echo「In the loop…」done
當在一臺單核機器上運行清單 2 中的代碼,絕大多數時間咱們不會注意到它在運行。可是若是啓動另外一個程序或者監控另外一個程序的性能時,這種影響就會體現出來。操做系統善於利用時間切片程序來競爭 CPU 週期,可是最新啓動的程序只能得到極少的的可用 CPU 週期。有一種解決問題的方案,那就是留出必定比例的閒置 CPU 週期以防有其餘程序須要使用 CPU。可是這種方案暴露出來的問題就是操做系統沒法知曉下一步操做,操做系統只能去執行當前全部的操做而不會留出閒置的 CPU 週期。多線程
咱們回到 Java 應用程序,週期性的 CPU 閒置意味着什麼呢?這取決於應用程序的類型。對於有固定做業量的批處理程序,除非所有做業完成,不然 CPU 不會有閒置時間。提升 CPU 的使用率可使批處理程序更快地完成。若是 CPU 使用率已經達到 100%,咱們能夠在保持 CPU 使用率 100%的前提下從其餘方面進行優化使程序完成地更快。
對於接收請求的服務器類型的應用程序,在沒有請求到來的時候,CPU 會處於閒置狀態。舉例來講,當 Web 服務器處理完當前全部 HTTP 請求處於等待下一個請求的狀態時,CPU 爲閒置狀態。從這裏能夠理解 CPU 使用率爲什麼爲必定時間間隔內的平均數值。上文 vmstat 示例中的數據採集自一個應用服務器的運行過程當中,這個服務器每 5 秒接收到一個請求,花費 2.25 秒處理,這意味着在這 2.25 秒內 CPU 的使用率爲 100%,而在剩下的 2.75 內使用率爲 0。由此計算得出 CPU 使用率爲 45%。
這種狀況老是發生在很是短的時間間隔內,所以很難被發現,可是這種相似應用服務器的程序老是按照此方式運行。當咱們下降時間間隔,上述應用服務每 2.5 秒接受一個請求同時花費 1.125 秒處理請求,剩餘的 1.375 秒 CPU 處於閒置狀態。平均下來,CPU 平均使用率依然爲 45%,55%的時間處於閒置狀態。
優化應用服務器以後,處理每一個請求只須要 2 秒,CPU 使用率將降至 40%。下降 CPU 使用率是咱們優化程序代碼的目標。只有在單位時間內,沒有外部資源約束的應用程序負載固定。從另外一方面來說,優化這種應用程序能夠適當增長程序負載來提高 CPU 使用率。這樣一來,能夠看出這種優化策略依然遵循前文的規則,即在儘量短的時間內使 CPU 使用率儘量高。
調優多線程程序的目標依然是儘量的提升每一個 CPU 的使用率,使 CPU 儘量少的被阻塞。在多核多線程環境中,當 CPU 處於閒置狀態時須要多考慮的是即便應用程序有做業未完成,CPU 依然會處於閒置狀態,由於該應用程序中沒有可用的線程來處理做業。最典型的例子爲一個擁有固定大小線程池的應用程序運行數量變化的任務。每一個線程每次只能處理一個任務,若是此線程被某些操做阻塞,這個線程不能轉而去處理另外一個任務。在這種狀況下就會出現沒有可用線程來處理未完成的任務。所以會致使 CPU 處於閒置狀態。對於此種情形應該考慮如何增長線程池的大小來完成更多的任務。
監控 CPU 使用率只是理解應用程序性能的第一步,這隻能肯定代碼的 CPU 使用率是否達到開發人員的指望,或者找到代碼中存在的同步問題和資源問題。
在 Windows 和 UNIX 系統中均可以監控當前能夠執行任務的線程數。UNIX 系統中稱爲 Run Queue,有不少工具能夠查到此數據。例如前文中的 vmstat,每行的第一個數字便是 Run Queue 的長度。Windows 系統中稱之爲 Processor Queue,能夠經過 typeperf 命令查到。
Windows 與 UNIX 的區別是:在 UNIX 中,Run Queue 長度爲當前正在運行和能夠運行的線程數,因此這個長度最小爲 1;而在 Windows 中,Processor Queue 長度並不包括正在運行的線程數,所以 Processor Queue 長度最小值爲 0。
當可用線程數大於可用 CPU 數量,性能就會降低。因此在 Windows 中 Processor Queue 長度爲 0,在 UNIX 中 Run Queue 長度等於 CPU 數的狀況性能達到最好。但這並不絕對,由於系統程序中會週期性運行致使此數值增大,單對應用程序的影響不大。若是 Run Queue 長度長時間遠遠大於 CPU 數,表示機器負載過大,應該適當減小當前機器的做業量。
監控硬盤使用率有兩個重要的目標,一是應用程序自己,若是應用程序進行了很是多的硬盤 I/O 操做,很容易推斷出應用程序的性能瓶頸在於 I/O。
須要進行詳細的監控才能發現應用程序的性能瓶頸在於 I/O。當應用程序沒有高效地使用緩存來進行硬盤寫操做時,硬盤 I/O 的數據將會很是低。可是當應用程序進行的 I/O 操做數超出了硬盤可以處理的數量,硬盤 I/O 數據將會很是高。這兩種狀況都須要進行調優。
在 Linux 系統中執行 iostat -xm 5 命令能夠獲得清單 3 中的數據:
avg-CPU: %user %nice %system %iowait %steal %idle18.20 0.00 40.20 0.00 0.00 51.60Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s sda 0.00 0.20 0.00 34.60 0.10 0.23avgrq-sz avgqu-sz await svctm %util 8.35 0.00 5.04 0.04 2.02
應用程序在向硬盤 sda 中寫入數據,看上去硬盤寫入的時間狀況還不錯,每次寫入等待時間(await)爲 5.04 毫秒,硬盤使用率也僅爲 2.02%。但仔細來看,系統執行內核代碼用掉 40.2%的時間,這是意味着應用程序中存在低效的寫操做。系統每秒進行 34.60(w/s)次寫操做,可是隻寫入了 0.23MB(wMB/s) 數據。能夠判斷 I/O 是應用程序的性能瓶頸所在。下一步將分析應用程序如何進行寫操做。
再看另外一組數據(清單 4),硬盤使用率(%util)達到 100%,等待硬盤的時間佔到了 49.81%(%iowait),應用程序每秒寫入 60.45mb 數據,這些數據共同證實 I/O 是應用程序的性能瓶頸所在,必須減小如此大量的 I/O 操做。
avg-CPU: %user %nice %system %iowait %steal %idle40.20 0.00 5.70 49.81 0.00 54.10Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s sda 0.00 0.20 0.00 134.60 0.10 60.45avgrq-sz avgqu-sz await svctm %util 727.24 68.46 798.04 5.67 100
監控硬盤使用率的另外一個做用是得知系統是否在進行交換(swapping),計算機擁有固定數量的物理內存,可是它能夠運行使用內存遠遠大於其物理內存的一些應用程序。應用程序佔有的內存每每多於它們真正須要的內存,在這種狀況下,操做系統將這些沒有被用到內存挪入硬盤,當須要的時候將它們經過換頁換進物理內存中。對於大多數應用程序,這種內存管理方式是不錯的,可是對於服務器類型的應用程序而言,這種方式就顯得尤其糟糕,由於因爲 Java 內存堆的存在,服務器類型的應用每每須要用到很是多的物理內存。
因爲須要將硬盤中的數據與物理內存中的數據進行交換,會嚴重影響系統性能。vmstat 命令的結果中 si,so 兩列數據表示了換入物理內存和換出物理內存的數據量。經過這些數據能夠知道系統是否在進行交換。
若是應用程序運行過程當中使用了網絡,在進行性能監控時必須監控系統網絡傳輸使用率。網絡傳輸相似於硬盤傳輸,低效地使用網絡傳輸會形成網絡帶寬不足;若是網絡傳輸的數據量超過了其所能負載的上限一樣會形成網絡傳輸性能瓶頸。
操做系統內置的網絡監控工具只能得到某個網絡接口接收和發送的包數和字節數。經過這些信息還不足以肯定網絡負載正常仍是負載過大。
在 UNIX 系統中,基本的網絡監控工具是 netstat。
固然,還有很是多的第三方網絡監控工具,nicstat 就是 UNIX 系統中使用很普遍的一個命令行工具,經過這個工具能夠獲得指定網絡接口的使用率。
執行 nicstat 5 命令,獲得清單 5 中的數據,從數據中能夠看到,網絡接口 e1000g1 爲 1000MB 接口,該接口使用率只有 2.98%(%Util),每秒鐘經過此接口讀入 156.4Kb 數據,寫入 256.9Kb 數據,經過這些數據,能夠明確得出網絡接口的帶寬以及使用率。
Time Int rKB/s wKB/s rPk/s wPk/s rAvs wAvs %Util Sat 17:05:17 e1000g1 156.4 256.9 875.0 909.5 215.4 175.3 2.98 0.00
若是隻用 netstat 命令,能夠得到每秒讀寫的數據量,可是必須知道網絡帶寬而且經過額外的腳本才能計算得出網絡接口的使用率。在計算過程當中須要注意,帶寬單位爲位每秒(bps),所以 1000Mb 帶寬每秒能夠傳輸 125MB 數據。而在 nicstat 已經幫咱們作了相似的計算。
網絡傳輸沒法支撐 100%的使用率,在本地以太網網絡,超過 40%的使用率就被認爲接口飽和。使用其餘媒介進行網絡傳輸的飽和使用率須要諮詢網絡架構師。Java 程序只是使用操做系統的網絡接口進行傳輸,並不能決定網絡使用率的飽和值。
下面將主要介紹 Windows 系統的系統監控工具 Perfmon。Perfmon 是 Windows 系統自帶的性能監控工具,能夠監控包括上文所述的各種系統資源的使用狀況,並提供圖形化的用戶展現界面。Perfmon 包括性能監視器、計數器日誌、跟蹤日誌和警報四個部分。
1. 性能監視器
在 Windows 系統的命令行中運行 perfmon.msc 命令便可啓動 Perfmon 的性能監視器的用戶界面。經過性能監視器,能夠對 CPU、硬盤、網絡的資源進行實時監控。具體的分析方式與 Linux 系統中相似,在此再也不贅述。使用下面將要介紹的計數器日誌能夠保存這些監控數據
性能監視器的另外一個功能是將計數器日誌保存的數據以圖形化的形式展示給用戶。經過「查看當前活動」或者「查看日誌數據」功能來指定監控的資源。
2. 計數器日誌
雖然性能監視器能夠實時監控系統資源,但並不能保存監控數據,若是須要持續對系統的監控數據採樣,必須使用 Perfmon 的計數器日誌功能。用戶可使用系統監視器或者其餘工具對計數器日誌保存的數據的進行分析。
3. 跟蹤日誌
經過跟蹤日誌功能,用戶能夠跟蹤某些重要的系統事件,能夠跟蹤指定的應用程序。跟蹤日誌默認被保存爲擴展名爲.etl 二進制文件,可使用 tracert 命令對文件進行分析,並生成 CSV 格式的 Dump 文件。
目前必須經過編輯系統註冊表的形式配置跟蹤的應用程序以及保存日誌文件的路徑。
4. 警報
當某個計數器的性能監控數據達到預先設定的閥值時,將會觸發 Perfmon 的警報,警報是指預先設定的動做,如發送電子郵件、運行指定的命令等動做。也能夠將警報動做設置爲將警報做爲系統事件記錄,這樣就能夠在事件查看器中查看警報的內容。針對不一樣的應用能夠指定不一樣的警報策略。例如當 CPU 的閒置時間低於 80%時觸發警報,將發送郵件給系統維護人員;或者當內存使用率高於 90%時出發警報,執行 typeperf 命令收集保存數據。
必須是管理員用戶才能使用 Perfmon,Perfmon 有兩種部署方式:本地監控模式和遠程監控模式。
在本地監控模式中,日誌文件被默認保存在 C:\perflogs 目錄中,能夠在「日誌文件」下修改此目錄。本地監控生成的日誌文件既能夠在本機使用性能監視器進行分析,也能夠傳輸到其餘分析平臺中分析。
在遠程監控模式中,在創建監控主機與被監控主機之間信任關係並打開遠程訪問控制的前提下,能夠對局域網內的多臺目標監控機器進行集中採樣監控。但隨之而來的是安全隱患,因此在訪問控制比較嚴格的環境下,遠程監控模式難以實施。
在部署過程當中還需考慮日誌文件存儲問題,設置合適的採樣間隔時間,若是設置太小,日誌文件會快速遞增,若是設置過大,監控數據會出現較大偏差。
Perfmon 有兩種管理方式:控制檯管理和命令行管理,如前文所述,經過運行 perfmon.msc 能夠打開控制檯管理器,並根據監控策略管理控制檯。經過命令 Logman 能夠在命令行中建立、啓動、中止日誌 Session。主要包括 create, start, stop, delete, query, update 這些參數,具體的使用方法參考 Logman 幫助文檔。除了 Logman 命令,Typeperf 命令也是 Windows 中經常使用的系統功能監控命令,經過此命令能夠得到 Perfmon 中全部資源當前的性能數據,但不能生成日誌和設置警報。咱們將 Typeperf 的輸出重定向至文本文件中,使用第三方工具進行分析。Typeperf 能夠配合其餘性能工具一塊兒使用,經過定製計劃任務執行此命令能夠定時得到系統的性能數據。
本文在性能監測和優化方面給出了多種方法,並結合 CPU 時間特性闡述了其性能影響的因素和緣由。整體上講,性能監測首先應當從應用程序運行時所消耗的 CPU 時間來入手,剖析其運行狀態,以及資源消耗的瓶頸在哪裏。其次,以 CPU 使用率的提高爲目標來優化代碼。
性能監測還能夠經過監測硬盤的使用狀況來得到,大量硬盤的讀寫將會產生應用程序的性能問題,這就要求咱們的程序設計人員在設計程序的時候儘可能下降減小磁盤的讀寫操做,以及讀寫的數據量,並採用緩存交換的數據的形式提高應用程序性能。
對基於網絡的應用程序,監測其網絡傳輸的開銷,也是性能監測的一種方法。大量數據在網絡層面上的交換也會帶來性能上的開銷。
最後,本文講解了 Java 自帶的性能分析工具的使用,在使用這些工具的時候請你們銘記一點,
沒有一個完美的工具來幫您徹底理解應用程序的總體性能問題,實際工做中咱們可能須要結合多種工具來完成一個應用程序的性能分析。不一樣的工具備不一樣的方向,全方面的理解和使用纔可以更好的完成分析任務。
原做者:李 偉軍, 宋 翰瀛, 和 楊 翔宇
原文連接: 操做系統工具
原出處:IBM Developer