EJB 容器

EJB 容器

EJB容器中最昂貴的操作當然是數據庫調用――裝載和存儲實體bean。容器也因此提供了各種各樣的參數以便減少數據庫的訪問次數。但不管怎樣,除非是在特殊情況下,否則在每個bean的每次交易中,至少都得有一次裝載操作和一次存儲操作。這些特殊情況是:
1. Bean是隻讀的。此時,bean只需在第一次訪問時裝載一次,從來不需要存儲操作。當然,如果超出參數read-timeout-seconds的設置,bean將被再次裝載。

2. Bean 有專門的或積極的併發策略,且參數db-is-shared 設置爲假。此參數在WebLogic Server 7.0中被重新命名爲cache-between-transactions。參數db-is-shared 設置爲假相當於參數cache-between-transactions設置爲真。

3. Bean在交易中未被修改過,此時,容器會將存儲操作優化掉。

如果不屬於上述任何一種情況,則code path中的每個實體bean在每次交易時,至少會被裝載和存儲一次。有些特徵能夠減少數據庫的調用或者降低數據庫調用的開銷,如:高速緩存技術、域(field)分組、併發策略以及緊密關聯緩存(eager relationship caching)等,其中的某些特徵是WebLogic Server 7.0新增的。
高速緩存:實體bean緩存空間的大小由weblogic-ejb-jar.xml中的參數max-beans-in-cache定義。容器在交易中第一次裝載bean時是從數據庫調用的,此時bean也被放在緩存中。如果緩存的空間太小,有些bean就被滯留在數據庫中。這樣,如果不考慮前面提到的前兩種特殊情況的話,這些bean在下次調用時就必須重新從數據庫裝載。從緩存調用bean也意味着此時不必調用setEntityContext()。如果bean的關鍵(主)鍵是組合域或者比較複雜,也能省卻設置它們的時間。

域分組:域分組是對於查找方法指定從數據庫加載的域。如果實體bean與一個較大的BLOB域(比方說,一幅圖像)相聯繫,且很少被訪問,則可以定義一個將此域排除在外的域組,該域組與一個查找方法相關聯,這樣查找時,BLOB域即不會被裝載。這種特徵只對EJB2.0的bean 適用。

併發策略:在WebLogic Server 7.0中,容器提供了四種
併發控制機制。它們是獨佔式、數據庫式、積極式和只讀式。併發策略與交易進行時的隔離級別緊密相關。併發控制並不是真正意義上的提高性能的措施,它的主要目的是確保實體bean所表示的數據的一致性,該一致性由bean的部署器所強制要求。無論如何,某些控制機制使得容器處理請求的速度比其它的要快一些,但這種快速是以犧牲數據的一致性爲代價的。
最嚴格的併發策略是獨佔式,利用特殊主鍵對bean的訪問是經過系列化的,因此每次只能有一個交易對bean進行訪問。這雖然在容器內提供了很好的併發控制,但性能受到限制。在交易之間允許互爲緩存的時候,這種方法很有用,但在集羣環境中不能使用,此時,裝載操作被優化掉,因此可能導致喪失並行性。

數據庫式的併發策略不同於數據庫的併發控制。實體bean在容器中並未被鎖定,允許多個交易對相同的實體bean併發操作,因此能夠提高性能。當然,這樣對隔離的級別也許要求較高,以便確保數據的一致性。

積極式併發策略與數據庫的併發控制也不同。不同之處在於對數據一致性的檢查發生在對已設定的更新操作進行存儲時而非在裝載時將整行鎖定。如果應用內對同一個bean訪問的衝突不是很激烈的情況下,本策略比數據庫式的策略要快一些,雖然兩個提供了相同的數據一致性保護級別。但是在有衝突發生的時候,本策略要求調用者要重新發起調用。本特徵也只對EJB 2.0 適用。

只讀式策略只能用於只讀bean。Bean只在應用第一次訪問時或者超出參數read-timeout-seconds所指定的值時才被裝載。Bean從來不需要被存儲。當基本數據改變時,也會通過read-mostly格式通知bean,從而引起重新裝載。

緊密關聯緩存: 如果兩個實體bean, bean A 和bean B 在CMR(容器關係管理)內關聯,兩個在同一個交易中被訪問,且由同樣的數據庫調用裝載,我們稱爲緊密關聯緩存。這是WebLogic Server 7.0的新特徵,同樣只適用於EJB2.0。

除了上面列出的通過優化容器內對數據庫的訪問從而達到性能增加的特徵外,另有一些在容器之外,針對會話bean和實體bean的參數能夠幫助提升性能。

緩衝池和高速緩存是EJB容器爲提高會話bean和實體bean性能所提供的主要特徵。然而,這些方法並非對所有類型的bean適用。它們的消極面是對
內存要求較高,雖然這不是主要的問題。緩衝池適用於無狀態會話bean(SLSB),消息驅動bean(MDB)以及實體bean。一旦爲SLSB和MDB設定了緩衝池的大小,這些bean的許多實例就會被創建並被放到緩衝池中,setSessionContext()/setMessageDriveContext()方法會被調用。爲這些bean設置的緩衝池的大小不必超過所配置的執行線程數(事實上,要求比此數要小)。如果方法setSessionContext()要做任何開銷昂貴的操作的話,此時JNDI查詢已經完成,使用緩衝池中的實例方法調用將會加快速度。對實體bean來說,在完成setEntityContext()方法調用之後,緩衝池與bean的匿名實例相連(沒有主鍵)。這些實例可以被查詢操作所使用,查詢方法從緩衝池中取出一個實例,爲其指定一個主鍵,然後從數據庫中裝載相應的bean。

高速緩存適用於有狀態會話bean(SFSB)和實體bean。實體bean已經在前面討論過。對於SFSB,緩存能夠避免向
硬盤串行化的操作。串行化到硬盤的操作非常昂貴,絕對應該避免。用於SFSB的緩存大小可以比連接到服務器的併發客戶端數略微大些,這是由於僅當緩存被佔用了85%以後,容器纔會設法將bean滯留在數據庫中待命。如果緩存大於實際所需,則容器不會通過緩存花費時間將bean待命。

EJB容器提供了兩種方法進行bean-to-bean 和 Web-tier-to-bean的調用操作:傳值調用和傳送地址調用。如果bean處在同一個應用之中,則缺省情況下,用的是傳送地址的方法,這比傳值要快一些。傳送地址的方法一般不應被禁止,除非有充足的理由要強制這樣做。強制使用傳送地址的另一種做法是使用本地接口。在WebLogic Server 7.0中引入了另一個特徵是對有狀態服務使用激活(activation)。雖然這種做法在某種程度上影響了性能,但由於對內存要求較低,因此極大地改進了擴展性。如果擴展性不值得關注,可以將參數noObjectAction傳送給ejbc從而關閉激活(activation)。

JDBC

對數據庫的訪問來說,調試JDBC與調試EJB容器同樣重要。比方說設置連接池的大小――連接池應大到足以容納所
有線程對連接的要求。如果所有對數據庫的訪問能夠在缺省的執行隊列中得以實現,則連接數應爲執行隊列中的線程數,比讀取socket的線程(缺省執行隊列中用來讀取進入請求的線程)數要少。爲了避免在運行期間對連接進行創建和刪除,可在初始時即將連接池設置爲其最大容量。如果可能的話,應確保參數TestConnectionsOnReserve被設置爲假(false,這是缺省設置)。如果此參數設置爲真(true),則在連接被分配給調用者之前,都要經過測試,這會額外要求與數據庫的反覆連接。

另一個重要的參數是PreparedStatementCacheSize。每個連接都爲宏語句設一個靜態的緩存,大小由JDBC連接池配置時指定。緩存是靜態的,時刻牢記這一點非常重要。這意味着如果緩存的大小是n的話,則只有放在緩存中的前n條語句得到執行。確保昂貴的SQL語句享受到緩存的方法是用一個
啓動類將這些語句存放到緩存中。儘管緩存技術從很大程度上改進了性能,但也不能盲目使用它。如果數據庫的格式有了變化,那麼在不重新啓動服務器的情況下,無法使緩存中的語句失效或者是用新的進行替換。當然,緩存中的語句會使數據庫中的光標得以保留。

對於WebLogic Server 7.0來說,由於jDriver性能的改進已使其速度遠遠快於
Oracle的廋驅動程序,尤其對於要完成大量SELECT操作的應用來說就更是如此。這可以從HP提交的利用WebLogic Server 7.0 Beta版的兩份Ecperf結果得到證明(http://ecperf.theserverside.com/ecperf/index.jsp?page=results/top_ten_price_performance)。

JMS

JMS子系統提供了很多的調試參數。JMS消息是由稱爲JMSDispatcher的獨立執行隊列處理的。因此,JMS子系統既不會由於運行在缺省或者其它執行隊列中的應用因爭奪資源而導致“營養匱乏”,反過來也不會搶奪其它應用的資源。對JMS來說,大多數的調試參數都是在服務的質量上進行折衷處理。如,利用文件式持續性目的地(file-persistent destnation)禁止同步寫操作(通過設置特性: -Dweblogic.JMSFileStore.SynchronousWritesEnabled =false)以後會引起性能急劇提高,但同時也會冒着丟失消息或者重複接收消息的風險。類似地,利用多點傳送發送消息會提升性能,同時也會有消息半途丟失的危險。

消息確認間隔不應設置得過短――發送確認的比率越大,處理消息的速度可能會越慢。同時,如果設置得過大,則意味着系統發生故障時,消息會丟失或者被重複發送。

一般說來,應在單個服務器上對多個JMS目的地進行配置,而不是將它們分散在多個JMS服務器,除非不再需要擴展。

關閉消息頁面調度(paging)可能會提高性能,但會影響可擴展性。如果打開消息頁面調度(paging),則需要額外的I/O操作以便將消息串行化到硬盤,在必要的時候再讀進來,但同時也降低了對內存的要求。

一般來說,異步過程比同步過程更好操作,更易於調節。

Web容器

Web層在應用中更多的是用來生成表達邏輯。廣泛使用的體系結構是從應用層讀取數據,然後使用servlet和JSP生成動態內容,其中應用層一般由EJB組成。在這種結構中,servlet 和JSP保留對EJB的引用,以防它們與數據庫或數據源直接對話。將這些引用保存起來是個不錯的主意。如果JSP和servlet沒有和EJB部署在同一臺應用服務器上,則利用JNDI進行查詢的費用是很昂貴的。

JSP緩存標記符可以用於存儲JSP頁面內的數據。這些標記符都支持對緩存的輸入和輸出。對緩存的輸出涉及到標記符內的代碼所生成的內容,對緩存的輸入涉及到標記符內的代碼對變量的賦值。如果不希望Web層頻繁變化,則可以通過將ServletReloadCheckSecs 設置爲-1,從而關閉自動裝載(auto-reloading)功能。使用這種方法以後,服務器將不再輪詢Web層是否有變化,如果JSP和servlet的數量很多,則效果是非常明顯的。

這裏也建議不要在HTTP會話中儲存過多的信息。如果信息是必須的,可以考慮使用有狀態會話bean來替代。

JVM調試

如今的大多數JVM具有自主調節功能,因爲它們能夠探測到代碼中的危險區域並對它們進行優化。開發和部署人員能夠考慮的調試參數大概就是堆設置了。設置這些並沒有一般的規則。JVM一般堆空間,按新空間或保留空間一般設置爲整個堆空間的三分之一或一半組織。整個堆空間不能指定得過大以致於無法支持併發的內存垃圾回收(GC)處理。在這種設置環境中,如果堆太大的話,垃圾回收的間隔應設爲一分鐘或更長。最後,需要引起注意的是這些設置在很大程度上依賴於部署在服務器上的應用使用內存的模式。有關調試JVM的其它信息可以參考:

http://edocs.bea.com/wls/docs70/perform/JVMTuning.html1104200。

服務器調試

除了由各個子系統提供的調試參數以外,還有適用於服務器的參數能夠幫助提升性能。其中最重要的是配置線程數和執行隊列數。增加線程數並非總能奏效,僅當下列情況成立時再考慮使用這種方法:預定的吞吐量沒有達到;等待隊列(未開始處理的請求)過長;
CPU仍有剩餘。當然,這樣做並不一定能改善性能。CPU使用率低可能是由於對服務器的其它資源競爭所致,如,沒有足夠的JDBC連接。當改變線程數時應考慮到這些類似的因素。

在WebLogic Server 7.0中,提供了配置多個執行隊列的功能,並且能夠在部署中定義處理特殊的EJB或JSP/servlet請求的執行隊列。要做到這些,只要在運行weblogic.ejbc時將標誌-dispatchPolicy <隊列名稱> 傳送給bean 即可。對於JSP/servlet,可將設置Web應用的weblogic部署描述符中初始化參數(init-param) wl-dispatch-policy的值設爲執行隊列的名字即可。有時應用中的某些bean/JSP對操作的響應時間比其它的要長,此時,可以對這些bean/JSP設置單獨的執行隊列。至於隊列的大小,要達到最好的性能,還取決於經驗。

另一個比較大的問題是決定在何種情況下應該使用WebLogic性能包(http://e-docs.bea.com/wls/docs70/perform/WLSTuning.html - 1112119)。如果socket數不太多(每個服務器上都有一個socket用於客戶端JVM的遠程方法調用連接),而且總是忙於讀取從客戶端發送過來的請求數據,那麼此時使用性能包恐怕不會有明顯的改進。也有可能不用性能包會導致相似或更好的結果,這取決於JVM在處理網絡I/O時的具體實現。

Socket讀取線程取自缺省執行隊列。在
Windows 環境下,每個CPU有兩個socket讀取線程,在solaris環境下,共有三個socket用於本地輸入輸出(native I/O)。對於Java 輸入輸出(I/O),讀取線程數由配置文件config.xml中的參數PercentSocketReaderThreads 進行設置。它的缺省值是33%, 上限是50%,這是顯而易見的,因爲如果沒有線程用於處理請求,則同樣不會有更多的讀取線程啦。對於Java I/O,應使讀取線程數儘量接近客戶端連接數,因爲在等待請求時,Java I/O會阻塞。這也是爲什麼當客戶端的連接數增加時,線程數不能一直同等增加的原因。

結論

我們上面只討論了調試服務器的部分方法。需要記住的是,一個
設計蹩腳,編寫欠佳的應用,通常都不會有好的性能表現,無論對服務器及其參數如何調試。貫穿應用開發週期的各個階段――從設計到部署,性能始終應該是考慮的關鍵因素。經常發生的情況是性能被放在了功能之後,等到發現了問題再去修改,已經很困難了。有關WebLogic Server 性能調試的其它信息可以參考:http://e-docs.bea.com/wls/docs70/perform/index.html。 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章