隨著在企業級環境對高可擴展性J2EE應用的需求,需要在多處理器平台上執行線程的並行處理。在JVM堆中對線程處理所需要的內存和並發處理已經成為這些J2EE應用在部署時的性能和可擴展性的瓶頸。這篇文章探討了J2EE應用在多處理器平台上訪問JVM堆中的內存的線程同步問題。
J2EE應用的內存需求
當前布署在企業級環境中的J2EE應用都需要在一秒中能夠處理成千上萬的用戶請求。這種來自大量並發用戶的數據請求就產生了更大堆空間的需求,也就需要更多的內存。有了更多的內存就可以提供更大的J2EE應用堆空間,而多處理器可以處理更多的並發線程,因而現在線程訪問內存的方式和訪問所花費的時間就成了瓶頸所在。
多處理器平台
處理器數目的增加可以提高可擴展性,但同時需要處理更多的線程。線程在處理數據、創建Java對象及其他Java操作時都有需要耗用內存。由於多個線程在多個處理器中運行,就需要保證在系統中數據的一致性和完整性。在處理器中的線程同時讀寫內存,這就需要同步這些線程來防止讀寫錯誤的數據。在圖1中,顯示單處理器與多處理器在訪問內存時的異同。在單處理器平台中,在任何給定的時間只有一個線程被執行,因此不需要同步。然而在多處理器平台,同一時間可能會有多個線程被執行,這就需要同步訪問內存來保證數據的正確性,而這就會導致爭用和瓶頸?
Figure 1. Single-processor versus multi-processor platforms accessing memory
“線程本地堆”嘗試通過為每一個線程在JVM堆中預分配一小塊內存來解決這個問題。然而這種方式下內存空間對高內存需求的J2EE應用來說是不夠的。
實驗和觀察
我們會在一個8CPU平台上為J2EE應用做一項實驗,下面是實驗的代碼:
String mem = request.getParameter("memory"); if (mem != null && !mem.equals("")) { int mem_kbytes = Integer.parseInt(mem); byte[] i = new byte[mem_kbytes*1024]; }
在每一次測試中,這些J2EE線程會請求創建一個特定內存大小的對象。在一個多用戶負載測試中,我們觀察到下列的數據:響應時間、吞吐量和資源利用率。
我們將JVM堆大小設置為一個較大的值這樣就可以減少垃圾回收的次數。我們注意到即使負載增加,“垃圾回收暫停時間”與“運行總時間”的比率始終在1:35左右,因此我們認為他在這項實驗中的影響較小。結果如下圖2。
這個實驗的環境如下:
1、應用服務器:WebLogic7
2、JVM:Sun JVM 1.3
3、操作系統:Windows 2000高級服務器版
4、硬件:Intel Dell PowerEdge 8450 (8Intel Xeon 800MHz 處理器, 4GB RAM)
5、網絡:100Mbps Cisco網絡
6、負載測試工具:WebLoad
我們觀察到在增加特定內存大小的對象的負載時,吞吐量增加的比率與CPU利率的增加比較並不相同。當然,響應時間的增加也不是線性的。這些實驗清晰地顯示了這些J2EE線程的高內存需求導致系統內的爭用並且成為J2EE可擴展性的瓶頸。我們還觀察到這些線程訪問內存和創建對象所花費的時間隨著處理利用率的增加而增加。這可以從負載的增加導致服務請求的增加中看出來,如圖3中特定內存大小的Java對象的創建圖表。
Figure 3. Increase in service demand versus load for Java objects of different memory sizes
擴展
內存爭用是系統架構所固有的,減輕這個問題的最佳方法是在布署配置中增加更多的系統來保證負載均衡,如下圖所示。在一個系統中增加更多的處理器並只會因為允許執行更多的並發線程而增加內存爭用,這對增加吞吐量和響應時間並沒有什麼幫助。
基礎結構大小
處理器中線程訪問內存的時間增加了處理器的時間,因此處理器使用率也增加了。在多處理器平台中訪問內存的線程越多,處理器的效率就越低。為了增加處理量而增加更多處理器在這種情況下並沒有什麼好處而且會導致J2EE應用低效的容量安排。為預測性能和基礎架構的定量或模擬模型在這兒可以派上用處。
應用的內存調優
減少這種問題的一個最重要的步驟就是調優J2EE應用中的不必要的和未回收的對象。任何的內存調試器都可以幫你定位內存瓶頸並且做一些優化,其中一個是JProbe。內存調試器會給出應用的內存分布圖,指示對象創建的位置和內存的使用量。他們也指出那些未回收的對象,這些對象會導致應用中的內存洩漏。對象重用也是內存優化的一個考慮因素,而這可以通過緩存框架如Apache JCS來幫忙。這些緩存框架有助於在特定的時間周期中為應用存儲特定的對象在緩存中並且可以被重用。
小結
在多處理器平台中保持數據的正確性需要在線程的處理過程中使用同步,這正是導致J2EE應用高內存需求的原因。內存爭用的可能解決方案包括:
1、通過為布署配置增加更多的系統。
2、調整應用處理不必要的對象來優化內存爭用。