J2EE性能調優(轉載)
性能問題的最明顯表現是網頁的響應時間變慢。在J2EE系統中,經常體現有下面更為基本的癥狀:
????????這些現象表明J2EE應用依賴很多外部資源,并且是運行在一個層次化的執行模式的環境中:

????????由于Java虛擬機和應用服務器掩蓋了操作系統和硬件的特性,所以在設計軟件系統時,架構工程師更應該深刻理解整個操作環境。
????????在設計軟件系統時,架構工程師應把性能和可擴展性放在首位,然后開始尋找容易解決的問題,反應時間緩慢通常的原因是訪問數據庫效率低和過多地調用遠程對象和方法。接下來,架構工程師可繼續尋找不明顯的原因,例如算法的累積影響和不必要的開銷。
????????現在市場上的各個J2EE應用服務器有很多配置項目。這里只簡單介紹一些常見的性能優化配置項目。
????????很多應用服務器都有一些與J2EE規范有關的操作系統配置項目或非標準的特性,這可以提高系統性能。應該化時間來理解這些性能配置。
Java虛擬機堆和垃圾回收設置
????????任何Java應用的性能調整基礎都涉及到堆的大小和垃圾回收設置。(這里主要討論Sun HotSpor JVM).
????????堆可分為三代,年輕的(新的),年老的和持久的。Hotspot JVM的內存基本配置包括最大堆大小,初始堆大小和年輕一代堆的大小。當配置最大堆大小時可參考下面一些指導:
????????注意不要將最大堆大小設置得過大。堆越大,內存中保存的對象越多。內存中對象越多,回收過程時間越長。
????????配置初試堆大小的一般性策略包括:
????????對于年輕一代堆大小,Sun 推薦是設置為最大堆大小的1/3。
????????也可以選擇不同的垃圾回收算法。首先是增量垃圾回收。該算法的意思是減少單個對象回收停頓時間,這樣的結果是整體回收性能的下降。該算法將相互引用的對象分組,然后嘗試按組回收。嘗試回收的部分越小,回收處理的時間往往會越少。
????????1.4.1版的HotSpot JVM增加了兩個垃圾回收算法:并行算法和并發算法。
????????在年輕一代堆中實現了并行算法。在多處理器的機器上,這種回收算法使用了多線程來提高性能。雖然這個算法會暫停所有的應用線程,但是由于利用了多個CPU使得回收時間非常快。在年輕一代堆中,該算法顯著地減少了回收帶來的停頓。
????????在年老一代堆中實現了并發算法。在應用中最大限度地執行并發。回收過程分為4個階段,覆蓋了可回收對象的標記和清除操作。前兩個過程會暫停應用線程,后兩階段可與應用并發執行。并發垃圾回收算法的"最大限度并發"特點可以使JVM利用更大的堆和多個CPU。因此應關注由于采用缺省的mark-compact(標記-壓縮)和stop-the-world(停頓所有處理)等垃圾回收算法所帶來的延遲和吞吐量問題。
處理線程
????????J2EE應用服務器是多線程的應用。應用服務器的線程是一種資源池,處理請求和和應用服務器的內部功能等任務共享這些資源。
????????很多應用服務器允許為特定的任務或應用配置不同大小的線程池。通常需要增加這些線程池的大小以滿足應用負載的需要。
????????架構工程師應該避免將線程池大小設置過大,這是因為會增加上下文交換的次數,從而降低應用的性能。線程池的大小通常應該能最大利用機器上的CPU,同時又不能使CPU過載。
EJB配置項目
???????? 在應用服務器中,很多不同類型的EJB是以資源池的方式實現的。通常這些池大小和初始Bean的數量會明顯影響應用的性能。
????????架構工程師應該避免將這些池大小設置的過大,這樣會導致不必要地消耗JVM和操作系統內存。另外,將初始Bean數量設置過高會使得應用服務器的啟動時間長的難以接受。
????????在應用服務器中,緩存很多不同類型的EJB。緩存大小和超時設置通常也會對應用性能帶來顯著影響。
???????? 架構工程師應該避免將緩寸大小設置過大,這同樣會不必要地消耗大量JVM和操作系統內存。此外,應避免設置過長的超時--例如當EJB不用時,仍被緩存---,這也會導致不必要地消耗大量內存。
數據庫配置項目
????????J2EE規范要求應用服務器廠商必須提供數據庫連接資源池功能。通常增加數據庫連接池的大小會提高性能。架構工程師應該考慮不同類型的SQL操作(例如事務型和批處理型)應使用不同的連接池。如果一個消息Bean執行批處理操作,那么應該為此另創建一個連接池,而不要與事務型操作使用同一個連接池。
????????很多J2EE應用服務器提供了Prepared Statement 的緩存功能。創建Prepared Statement是很耗費資源的。在事務型的J2EE應用中通常執行很多同樣的SQL語句,只是參數不同而已。所以在應用中應發揮數據庫配置項目的作用,盡量使用Prepared Statement。
?
好的開始是成功的一半。對于J2EE同樣如此,我們知道當開發應用時,在架構設計階段的決定將對應用的性能和可擴展性產生深遠的影響。
????????現在當開發一個應用項目時,我們越來越多地注意到了性能和可擴展性的問題。應用性能的問題比應用功能的不豐富問題往往更為嚴重,前者會影響到所有用戶,而后者只會影響到碰巧使用該功能的那些用戶。
????????作為應用系統的負責人,一直被要求"要少花錢多辦事"----用更少的硬件,更少的網絡帶寬,以及更短的時間完成更多的任務。J2EE通過提供組件方式和通用的中間件服務是目前首選的最優方式。而要能夠構建一個具有高性能和可擴展性的J2EE應用,需要遵循一些基本的架構策略。
緩存(Caching):
????????簡單地說,緩存中存放著頻繁訪問的數據,在應用的整個生命周期中,這些數據存放在持久性存儲器或存放在內存中。在實際環境中,典型的現象是在分布式系統中每個JVM中有一個緩存的實例或者在多個JVM中有一個緩存的實例。
????????緩存數據是通過避免訪問持久性存儲器來提高性能的,否則會導致過多的磁盤訪問和過于頻繁網絡數據傳輸。
復制:
????????復制是通過在多臺物理機器上創建指定應用服務的多個拷貝來獲得整體更大吞吐效率。理論上看,如果一個服務被復制成兩個服務,那么系統將可處理兩倍的請求。
????????復制是通過單一服務的多個實例的方式從而減少每個服務的負載來提高性能的。
并行處理
????????并行處理將一個任務分解為更為簡單的子任務,并能夠同時在不同的線程中執行。
????????并行處理是通過利用J2EE層執行模式的多線程和多CPU特點來提高性能。與使用一個線程或CPU處理任務相比,以并行方式處理多個子任務可以使操作系統在多個線程或處理器中進行分配這些子任務。
異步處理
????????應用功能通常被設計為同步或串行方式。異步處理只處理那些非常重要的任務部分,然后將控制立即返回給調用者,其他任務部分將在稍后執行。
????????異步處理是通過縮短那些在將控制返回給用戶之前必須處理的時間來提高性能的。雖然都做同樣多的事情,但是用戶不必等到整個過程完成就可以繼續發出請求了。
資源池
????????資源池技術使用的是一套準備好的資源。與在請求和資源之間維持1:1的關系的不同,這些資源可被所有請求所共享。
????????資源池的使用是有條件的,需要衡量下面兩種方式的代價:
????????A,維持一套可被所有請求共享資源的代價
????????B,為每個請求都重新創建一個資源的代價
????????當前者小于后者時,使用資源池才是有效率的。
????????構建高性能的J2EE應用不但需要了解常用的實施技巧。下面介紹最常用的10種有效方法,可幫助架構設計師們快速成為這方面的專家。
Java性能的基礎----內存管理
????????任何Java應用,單機的或J2EE的性能基礎都可歸結到你的應用是如何管理內存的問題。Java的內存管理包括兩個重要任務:內存的分配和內存的回收。在內存的分配中,目標是要減少需要創建的對象。 內存回收是導致性能下降的普遍原因。也就是說,內存中的對象越多,垃圾回收越困難。所以我們對創建對象的態度應該越保守越好。
????????在J2EE應用中常見的兩個內存有關的問題是:游離的對象(也被稱為內存泄露)和對象循環(指大量頻繁創建和刪除-在Java中體現為解除引用---對象)。
????????我們應注意確保所有可到達的對象實際是活的,即這些對象不但在內存中,而且也要在執行的代碼中是存在的。當對象在應用中已經沒有用了,而我們卻忘記了刪除對該對象的引用時,游離的對象就出現了。
????????我們知道垃圾回收會占用CPU時間。短期對象的大量創建增加了垃圾回收的頻率會造成性能下降。
不要在Servlet中實現業務邏輯
????????在構建J2EE應用時,架構工程師通常會使用到J2EE的基本部分,Servlet。
????????如果架構師不使用Session Beans, Entity Beans, 或 Message Beans, 那么改進性能的方法就很少。只能采用增加CPU或更多的物理服務器等方法。EJB使用了緩存(cache)和資源池等方法可以提高性能和擴展性。
盡可能使用本地接口訪問EJB
????????在早期的J2EE (遵循EJB1.X規范)應用中,訪問EJB是`通過RMI使用遠程接口實現的。隨著EJB2.0的出現,可以通過本地接口訪問EJB,不再使用RMI,在同一個JVM中使用遠程方法已經少多了。但是現在還是有一些使用EJB1.X實現的應用和不知道使用本地接口的一些EJB新手。為說明這點,我們作個比較:
????????1. 客戶端應用調用本地Stub
????????2. 該Stub裝配參數
????????3. 該Stub傳到skeleton
????????4. 該skeleton分解參數
????????5. 該skeleton調用EJB對象
????????6. EJB對象執行容器服務
????????7. EJB對象調用企業BEAN實例
????????8. 企業BEA執行操作
????????9. 執行組裝/分解步驟然后返回
????????與遠程接口處理相比較,本地接口的EJB方法是:
????????????????1. 客戶端調用本地對象
????????????????2. 本地對象執行容器服務
????????????????3. 本地對象調用企業Bean實例
????????????????4. 企業Bean實例執行操作
????????????????5. 沒有其他返回步驟!!
????????如果你不需要從遠程的客戶端訪問一個特殊EJB,就應該使用本地方法。
在實現Session Bean的服務中封裝對實體EJB的訪問
????????從Servlet訪問實體EJB不但效率低而且難于維護。使用Session Fa?ade(會話外觀)模式可把對實體EJB的訪問封裝在會話EJB中,在該會話EJB中通過使用本地接口訪問實體EJB而避免過多的遠程調用。
????????這項技術會有額外的性能和擴展方面的好處,這是因為會話和實體EJB可以使用緩存和資源池技術來進行改進。另外,由于負載的需要,會話和實體EJB可被擴展部署到其他硬件設備上,這比將Servlet層復制擴展到其他硬件設備上要簡單的多。
盡量粗粒度訪問遠程EJB
???????? 當訪問遠程EJB時,調用set/get方法將產生過多的網絡請求,同時也導致遠程接口處理的過載。為避免這種情況,可考慮將數據屬性集中在一個對象中,這樣通過一次對遠程EJB的調用就可以傳遞所有數據。這項技術就是數據傳輸對象(Data Transfer Object)模式。
優化SQL
????????J2EE的架構設計工程師和開發人員通常不是SQL專家或經驗豐富的數據庫管理員。首先應該確保SQL使用了數據庫提供的索引支持。在某些情況下,將數據庫的索引和數據分開存放會提高性能。但要知道,增加額外的索引可以提高SELECT性能但也會降低INSERT的性能。對于某些數據庫,關聯表之間的排序會嚴重影響性能。可以多向數據庫管理員咨詢。
避免在實體EJB中過多執行SQL
????????有時候,通過實體EJB訪問數據會執行多個SQL語句。根據J2EE 規范,第一步,將調用實體Bean的find(發現)方法;第二步,在第一次調用實體EJB的業務方法時,容器會調用ejbLoad()從數據庫中獲得信息。
????????很多CMP(容器管理持久性)在調用發現方法時就緩存了實體數據,所以在調用ejbLoad()時就不再訪問數據庫了。應該避免使用BMP(Bean管理的持久性)或者自己實現緩存算法避免二次訪問數據庫。
使用Fast Lane Reader 模式訪問只讀數據
????????J2EE應用經常要以只讀方式訪問大量長時間不變的數據,而不是訪問單個實體,例如瀏覽在線產品目錄。在這種只讀情況下,使用實體EJB訪問數據會導致嚴重過載并且實現很麻煩。實體EJB 適合于對單個實體的粗粒度訪問,訪問大量的列表只讀數據時效率不高。不管是使用CMP還是BMP,一定需要編寫代碼操作多個實體EJB及其關聯。這將導致訪問多個數據庫并存在大量的也是不必要的事務開銷。
利用Java Messaging Servce(消息服務)
????????J2EE規范在JMS中提供了內置的異步處理服務。當涉及到系統需求時,應該了解在什么情況下應該采用JMS進行異步處理的設計。一旦確定要執行一些異步處理,那么同步處理的任務就應該越少越好,將數據庫密集的操作安排在稍后的異步處理中完成。
緩存JNDI Lookup查找
????????很多操作在進行JNDI查找時要消耗大量資源。通常應該緩存JNDI資源避免網絡調用和某些處理的過載。可以緩存的JNDI查找包括:
????????EJB Home Interfaces
????????Data Sources
????????JMS Connection Factories
????????JMS Destinations/Topics
????????一些JNDI包實現了緩存功能。但是調用對EJB主接口的narrow方法時,這種功能作用有限。
????????緩存查找的設計應該使用共享的IntialContext實例,盡管構建它很麻煩。這是因為需要訪問多種數據源,包括應用資源文件JNDI.properties,系統屬性的各項參數,傳入到構造函數的各項參數。
posted on 2006-09-02 14:31 zdygis 閱讀(636) 評論(0) 編輯 收藏 所屬分類: Java