程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java 性能分析工具 , 第 1 部分: 操作系統工具,java操作系統

Java 性能分析工具 , 第 1 部分: 操作系統工具,java操作系統

編輯:JAVA綜合教程

Java 性能分析工具 , 第 1 部分: 操作系統工具,java操作系統


引言

性能分析的前提是將應用程序內部的運行狀況以及應用運行環境的狀況以一種可視化的方式更加直接的展現出來,如何來達到這種可視化的展示呢?我們需要配合使用操作系統中集成的程序監控工具和 Java 中內置的監控分析工具來進行 Java 程序的性能分析。本文為系列文章,共三篇分別介紹這幾類工具。在本文中將介紹操作系統中的性能監控工具。

操作系統中的程序性能監控工具並非只針對於 Java 程序,適用於所有運行其中的程序。在基於 UNIX 的操作系統中,有許多命令行工具可以用來監控程序的運行狀況,例如 sar, vmstat, iostat,prstat 等等。在 Windows 操作系統中,既有圖形化用戶界面的資源監控器 Perfmon(Performance Monitor),也有如 typeperf 的命令行工具。

進行性能測試時,我們需要通過操作系統提供的工具收集操作系統中的各類資源監控數據,包括 CPU、內存和硬盤的使用數據,如果被測試程序使用了網絡,還需要收集網絡使用數據。只有收集的數據足夠完整和充分,性能測試的結果才會更准確,性能分析也會更加容易進行。下面將首先介紹在 UNIX/類 UNIX 系統中各類資源的監控和分析的方法。

Linux 系統資源的監控

CPU 使用率

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)。

清單 1. vmstat 5 命令結果
 procs -----------memory--------------- ----swap---- ---io--- -----system------ ----------CPU-------
 r b swpd free buff cache si so bi bo in cs us sy id wa st
 2 0 236456 2259632 200052 730348 0 0 1 6 1 1 37 8 55 0 0
 2 0 236456 2259624 200052 730348 0 0 0 10 179 332 40 7 53 0 0
 2 0 236456 2259624 200052 730348 0 0 0 20 180 356 56 7 37 0 0

以下三點原因會造成 CPU 閒置:

  1. 應用程序被線程的同步操作阻塞,直到鎖被釋放;

  2. 應用程在等待某些請求的響應,例如等待數據查詢請求的響應;

  3. 應用程序無事可做;

前兩種情況比較容易理解,也有對應的調優方式。針對原因一,如果能夠減少鎖的競爭,或者調整數據庫返回請求資源的性能,那麼應用程序會運行的更快;對於原因二,優化請求響應方,提高響應速度;那麼在其他條件不變的情況下,應用程序會運行的更快,CPU 使用率也會提高。

第三種情況當應用程序有事去做時,CPU 將利用 CPU 周期去執行應用程序的代碼。這是一條通用的規則。當執行一段無限循環的代碼(如下所示)時,它將會再消耗一個 CPU 100%的時間。如果 CPU 的使用率並沒有達到 100%,意味著操作系統應該執行無限循環,但它並沒有去做而是處於閒置狀態。這種情況對於無限循環並沒有多少影響,但是如果我們的程序是用來計算一個表達式的結果,那麼這種情況將會導致計算的速度變慢。

清單 2. 無限循環示例
#!/bin/bash
while true
do
 echo“In the loop…”
done

當在一台單核機器上運行清單 2 中的代碼,絕大多數時間我們不會注意到它在運行。但是如果啟動另一個程序或者監控另一個程序的性能時,這種影響就會體現出來。操作系統善於利用時間切片程序來競爭 CPU 周期,但是最新啟動的程序只能獲得極少的的可用 CPU 周期。有一種解決問題的方案,那就是留出一定比例的閒置 CPU 周期以防有其他程序需要使用 CPU。但是這種方案暴露出來的問題就是操作系統無法知曉下一步操作,操作系統只能去執行當前所有的操作而不會留出閒置的 CPU 周期。

Java 和單 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 使用率盡可能高。

Java 和多 CPU 使用率

調優多線程程序的目標依然是盡可能的提高每個 CPU 的使用率,使 CPU 盡可能少的被阻塞。在多核多線程環境中,當 CPU 處於閒置狀態時需要多考慮的是即使應用程序有作業未完成,CPU 依然會處於閒置狀態,因為該應用程序中沒有可用的線程來處理作業。最典型的例子為一個擁有固定大小線程池的應用程序運行數量變化的任務。每個線程每次只能處理一個任務,如果此線程被某些操作阻塞,這個線程不能轉而去處理另一個任務。在這種情況下就會出現沒有可用線程來處理未完成的任務。因此會導致 CPU 處於閒置狀態。對於此種情形應該考慮如何增加線程池的大小來完成更多的任務。

監控 CPU 使用率只是理解應用程序性能的第一步,這只能確定代碼的 CPU 使用率是否達到開發人員的期望,或者找到代碼中存在的同步問題和資源問題。

CPU Run Queue

在 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 中的數據:

清單 3. iostat –xm 5 命令結果一
 avg-CPU: %user %nice %system %iowait %steal %idle
 18.20 0.00 40.20 0.00 0.00 51.60
 Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s 
 sda 0.00 0.20 0.00 34.60 0.10 0.23
 avgrq-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 操作。

清單 4. iostat –xm 5 命令結果二
 avg-CPU: %user %nice %system %iowait %steal %idle
 40.20 0.00 5.70 49.81 0.00 54.10
 Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s 
 sda 0.00 0.20 0.00 134.60 0.10 60.45
 avgrq-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 數據,通過這些數據,可以明確得出網絡接口的帶寬以及使用率。

清單 5. nicstat 5 命令結果
 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 系統資源的監控

下面將主要介紹 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 自帶的性能分析工具的使用,在使用這些工具的時候請大家銘記一點,

沒有一個完美的工具來幫您完全理解應用程序的整體性能問題,實際工作中我們可能需要結合多種工具來完成一個應用程序的性能分析。不同的工具有不同的方向,全方面的理解和使用才能夠更好的完成分析任務。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved