如何解決JAVA服務器性能問題 JAVA開發 摘要 改善JAVA服務器的性能需要模擬負載下的服務器。創建一個模擬環境、搜集數據并且分析結果可能是對許多開發人員的挑戰。這篇文章中的示例介紹了JAVA服務器 性能分析 的概念和工具。作者使用這個示例來研究超額請求次
摘要
改善JAVA服務器的性能需要模擬負載下的服務器。創建一個模擬環境、搜集數據并且分析結果可能是對許多開發人員的挑戰。這篇文章中的示例介紹了JAVA服務器
性能分析的概念和工具。作者使用這個示例來研究超額請求次數下內存使用和同步竟爭的影響。
項目團隊已經很熟悉如何組織一些具體的任務并完成他們。簡單的性能問題很容易由一個開發人員分離并解決。然而大的性能問題,通常在系統處于高負載情況下發生,就不是這么簡單能處理的了。這些問題需要一個獨立的
測試環境、一個模擬的負載,并且需要仔細地分析和跟蹤。
在這篇文章中,我使用比較通用的工具和設備創建了一個
測試環境。我會專注于兩個性能問題,內存和同步,他們很難用簡單的分析得到。通過一個具體的例子,我希望比較容易地解決復雜的性能問題而且可以提供處理問題過程中的細節。
改善服務器的性能
服務器的性能改善是依賴于數據的。沒有可靠的數據基礎而更改應用或環境會導致更差的結果。分析器提供有用的JAVA服務器應用信息,但由于從單用戶負載下的數據與多用戶負載下得到的數據是完全不同的,這導致分析器的數據并不精確。在開發階段使用分析器來優化應用的性能是一個好的方式,但在高負載下的應用分析可以取到更好的效果。
在負載下分析服務器應用的性能需要一些基本的元素:
1、可控的進行應用負載測試的環境。
2、可控的人造負載使得應用滿負荷運行。
3、來自監視器、應用和負載
測試工具自身的數據搜集。
4、性能改變的跟蹤。
不要低估最后一個
需求(性能跟蹤)的重要性因為如果不能跟蹤性能你就不能實際的管理項目。性能上10-20%的改善對單用戶環境來說并沒有什么不同,但對支持人員來說就不一樣了。20%的改善是非常大的,而且通過跟蹤性能的改善,你可以提供重要的反饋和持續跟蹤。
雖然性能跟蹤很重要,但有時為了使后續的測試更加精確而不得不拋棄先前的測試結果。在
性能測試中,改善負載測試的精確性可能需要修改模擬環境,而這些變化是必須的,通過變化前后的負載測試你可以觀察到其中的轉變。
可控的環境
可控的環境最少也需要兩臺獨立的機器和第三臺控制的機器。其中一臺用來生成負載,另一臺作為控制機與前一臺建立測試應用并接受反饋,第三臺機器運行應用。此外,負載和應用機器間的
網絡應該與局域網分開??刂茩C接受運行應用機器的反饋如操作系統、硬件使用率、應用(特別是VM)的狀態。
負載模擬
最精確的模擬通常用實際的用戶數據和WEB服務器端的訪問日志。如果你還沒有實際布署或者缺少實際的用戶數據,你可以通過構造類似的場景或詢問銷售和產品管理團隊或做一些有依據的猜想。協調負載測試和實際用戶體驗是一個持續的過程。
在模擬中一些用戶場景是必須的。如在一個通用地址薄應用中,你應該區分更新和查詢操作。在我的測試應用中GrinderServlet類只有一個場景。單用戶連接10次訪問這個servlet(在每一次訪問間有一段暫停)。雖然這個應用很小,我認為這可以重復一些常見的東西。用戶通常不會連接給服務器請求而沒有間斷。如果沒有間斷,我們可能不能得到更精確的實際用戶上限。
串行10個請求的另一個原因是實際應用中不會只有一個HTTP請求。單一而又分離的請求可以影響環境中的許多因素。對
Tomcat來說,會為每一個請求創建一個會話,并且HTTP協議允許不同的請求重用連接。我會修改一下負載測試來避免混洧。
GrinderServlet類不會執行任何排序操作,但這個需求在大部分應用中都很普通。在這些應用中,你需要創建模擬的數據集并且用他們來構造相關用例的負載測試。
例如,如果用例涉及到用戶登錄一個WEB應用,從可能的用戶列表中選取隨機的用戶會只使用一個用戶更精確。否則,你可能不經意地使用了系統緩存或其他的優化或一些微妙的東西,而這會使得結果不正確。
負載測試軟件
負載測試軟件可以構造測試場景并且對服務進行負載測試。我會在下面的示例中使用OpenSTA測試軟件。這軟件簡單易學,結果也很容易導出,并且支持參數化腳本,還可以監視信息的變化,他的主要缺點是基于
Windows,但在這兒不是個問題。當然還有很多可選項如Apache的
JMeter和
Mercury的
LoadRunner。
監視
在生成合理的用戶負載后,監視工具需要收集進程的運行狀況。在我的測試環境中可以收集到各種有用的信息:
1、所有計算機、網絡設備等等的使用率
2、JVM的統計數據。
3、個別JAVA方法所花費的時間。
4、
數據庫性能信息,包括
SQL查詢的統計。
5、其他應用相關的信息。
當然這些監視也會影響負載測試,但如果影響比較小也可以忽略?;旧先绻覀兿氆@取所有上面的信息,肯定會影響測試的性能。但如果不是一次獲取所有信息還是有可能保證負載測試的有效性。僅對特定的方法設置定時器,僅獲取低負載的硬件信息和低頻率地獲取樣例數據。當然不加載監視器來做測試是最好的,然后和加載監視器的測試來做比較。雖然有時候侵入式監視是個好主意,但就不可能有監視結果了。
獲取所有監視數據到一個中央控制器來做分析是最好的,但使用動態運行時工具也可以提供有用的信息。例如,命令行工具如PS、TOP、VMSTAT可以提供
UNIX機器的信息;性能監視器工具可以提供
WINDOWS機器的信息;而TeamQuest, BMC Patrol, SGI's Performance Co-Pilot, and ISM's PerfMan這樣的工具會在所有的測試環境中的機器安裝代理并且將需要的信息傳回中央控制機,這樣就可以提供文本或可視化的信息。在本文中,我使用
開源的Performance Co-Pilot作為測試統計的工具。我發現他對測試環境的影響最小,并且以相對直接的方式來提供數據。
JAVA分析器提供很多信息,但通常對負載測試來說影響太大而沒有太多的用處。工具甚至可以讓你在負載服務器上做一些分析,但這也很容易便測試無效。在這些測試中,我激活了詳細的垃圾收集器來收集內存信息。我也使用jconsole 和jstack工具(包含在J2SE 1.5中)來檢查高負載下的VM。我沒有保留這些
測試用例中負載測試的結果因為我認為這些數據不是很正確。
同步瓶頸
在診斷服務器問題時線程的信息是非常有用的,特別是對同步之類的問題。jstack工具可以連接到運行的進程并且保存每一個線程的堆棧信息。在UNIX系統可以用信號量3來保存線程的堆棧信息,在WINDOWS系統的控制臺中可以用Ctrl-Break。在第一項測試中,jstack指出許多線程在grindCPU()方法中被阻塞。
你可以已經注意到列表2中grindCPU()方法的同步修飾符實際上并不必須。我在后一項測試中刪除了他,如圖2顯示