張麗靜 冼學(xué)輝
摘要:Pushlet作為一個開源框架,是服務(wù)器推技術(shù)Comet的一個具體實現(xiàn)。研究了Pushlet推技術(shù),分析Pushlet推技術(shù)框架并描述其核心類職責(zé)。重點分析Pushlet消息推送機制及其Web容器占用問題。利用Servlet異步特性對Pushlet框架進行優(yōu)化,給出優(yōu)化方案,實驗證明優(yōu)化的有效性。
關(guān)鍵詞:服務(wù)器推送技術(shù);servlet容器;異步處理;性能優(yōu)化
中圖分類號:TP391文獻(xiàn)標(biāo)識碼:A文章編號:1009-3044(2012)22-5379-04
Research and Application of Servlet Asynchronous Characteristics in Pushlet Push Technology
ZHANG Li-jing1, XIAN Xue-hui2
(1. Information & Network Management Center, North China Electric Power University, Baoding 071003, China; 2. Department of Computer Science, North China Electric Power University, Baoding 071003, China)
Abstract: As an open source framework, pushlet is a concrete realization of the comet technology. Researched on the pushlet server push technology, analyzed the framework and described the function of core classes. Focused on the analysis of pushlet message pushing mechanism and the threads occupying problem in web container. Optimized pushlet framework by using the asynchronous characteristics of servlet, put forward optimization approaches. Studies show that this solution can effectively improve server performance and highly practical.
Key words: server push technology; servlet container; asynchronous processing; performance optimization
隨著Web技術(shù)的流行,越來越多的應(yīng)用從原有C/S模式轉(zhuǎn)變?yōu)锽/S模式。用戶對于數(shù)據(jù)實時性的需求也越來越多,很多應(yīng)用例如監(jiān)控、即時通信、即時報價系統(tǒng)都需要將后臺發(fā)生的變化實時傳送到客戶端而無須客戶端不停地刷新、發(fā)送請求[1]。最近幾年,因為AJAX (Asynchronous JavaScript and XML,異步JavaScript和XML)技術(shù)的普及,基于純?yōu)g覽器的服務(wù)器推技術(shù)受到較多關(guān)注。Comet技術(shù)的出現(xiàn),擺脫了以往采用插件技術(shù)(ActiveX、Flash、Applet等)進行Web應(yīng)用上的推送,解決了跨平臺和插件版本兼容性等問題。Comet技術(shù)被稱為反AJAX(Reverse AJAX)技術(shù),它通過實現(xiàn)服務(wù)器推來解決AJAX需要定時頻繁發(fā)送請求的問題。通過Com? et,客戶端所需要的響應(yīng)信息不再需要主動地去索取,而是在服務(wù)器端以事件(Event)的形式推至客戶端。
Pushlet是由Just Van Den Broecke設(shè)計并編寫的一個開源框架,是Comet的一個具體實現(xiàn)。Pushlet在Servlet機制下,將數(shù)據(jù)從Server端的Java對象直接推送到(動態(tài))HTML頁面,無需任何Java Applet或者插件的幫助,它使Server端可以主動、周期性地更新Client端的Web頁面[2]?;赑ushlet的主動推送框架構(gòu)建簡單,只需要使用支持Servlet的服務(wù)器即可,使用標(biāo)準(zhǔn)HTTP端口進行連接,不會被防火墻攔截[3]。然而,Pushlet存在著可伸縮性問題,其作者也承認(rèn)問題的存在[4]。Web容器已經(jīng)成為Web服務(wù)器的主流,它為Servlet和JSP(Java Server Page)組件提供了運行時環(huán)境,然而,Web Performance公司的Servlet性能報告結(jié)果顯示,提高Web容器(即Servlet容器)的性能仍是急需解決的問題,李洋等人提出了基于序列模式的Servlet容器緩存替換算法來提高性能[5]。本文則從Server的線程和Socket資源緊張并導(dǎo)致HTTP請求失效這一實際問題入手,結(jié)合Pushlet框架機制分析問題,研究基于異步特性的性能優(yōu)化問題,提出實現(xiàn)Servlet容器性能提高的辦法。
1 Pushlet原理分析
1.1總體架構(gòu)
Pushlet從功能上實現(xiàn)了無插件的服務(wù)器推技術(shù)[6],圖1給出了系統(tǒng)框架圖。其中,客戶端分為兩大類,瀏覽器和桌面應(yīng)用程序;服務(wù)器端采用Servlet技術(shù),監(jiān)聽客戶端請求,處理請求并將結(jié)果返回給客戶端。從圖1中可以看出服務(wù)器端返回響應(yīng)的接口只有一個即ClientAdapter,它根據(jù)不同的客戶端類型產(chǎn)生相應(yīng)的Adapter發(fā)送響應(yīng)結(jié)果。
當(dāng)發(fā)生一次用戶會話時,Session對象生成,同時生成與之對應(yīng)的Controller對象和Subscriber對象。在該會話中每次執(zhí)行命令都生成一個Command對象,封裝命令的類型和相關(guān)的數(shù)據(jù)。圖2給出了會話中上述四個類的對應(yīng)關(guān)系。
1.2核心類主要職責(zé)
Pushlet:是一個Servlet,負(fù)責(zé)接收所有用戶請求,并將請求包裝為Event對象,再根據(jù)Session、Event、Request、Response對象構(gòu)造一個Command對象,最后將Command對象交由Controller處理。
Session:代表一次用戶會話,此類不同于HttpSession,因為此Session的實現(xiàn)是使用類似URL重寫方式,在服務(wù)器分配了SessionId之后的每個請求中都加入這個參數(shù)以標(biāo)識會話。會話在其存活期內(nèi)有效。
Controller:是所有命令的執(zhí)行器,包括各種控制命令以及數(shù)據(jù)推送命令。不過對于數(shù)據(jù)推送的實際執(zhí)行并不是在Controller中實現(xiàn),而是委托給Subscriber執(zhí)行。
Subscriber:是Dispatcher與ClientAdapter之間的橋梁。它維護了一個阻塞的事件隊列。根據(jù)客戶端使用的不同模式,定義的模式有HTTP Streaming和Pull/Poll(長輪詢)。HTTP Streaming使用HTTP長連接。Pull/Poll通過服務(wù)器端維持長連接,客戶端處理完服
務(wù)器端的返回信息后重新建立連接來實現(xiàn)[7-8]。
Dispatcher:是事件分發(fā)器。事件來源可以是客戶(通過Publish命令發(fā)布事件),也可以是EventSource??梢詫崿F(xiàn)多播,廣播以及單播事件,具體采用哪種方式根據(jù)事件屬性決定。事件接收端即是Subscriber的事件隊列。
ClientAdapter:有3個具體實現(xiàn),BrowserAdapter、XMLAdapter、SerializedAdapter。分別用來發(fā)送Javascript、XML、序列化數(shù)據(jù),用于不同的客戶端。具體使用哪種Adapter需要根據(jù)用戶請求事件Format參數(shù)決定。
1.3 Pushlet消息推送機制
在Pull/Poll模式下,客戶端發(fā)送Join命令到Server,進行用戶會話注冊。Server產(chǎn)生唯一的ID分配給Client端,用于標(biāo)識這次會話的唯一性。此時Server會把SessionID作為Key,Session對象作為Value,存放到SessionManager的HashMap中,然后通過ClientAdapter的Push方法回調(diào)給客戶端。客戶端得到SessionID后,發(fā)送LISTEN命令,訂閱某一個Subject,提交給Server。Server收到后首先驗證HashMap里面有沒有這個SessionID,驗證通過后,回調(diào)給客戶端Listen_ack消息,并進行消息推送。當(dāng)客戶端離開,發(fā)送LEAVE命令給Server,Server將SessionManager的Session對象移除(Session超時同樣移除)。
消息推送時,Server取出Subscriber里的EventQueue消息,如果EventQueue不為NULL,從EventQueue取出數(shù)據(jù)封裝成一個數(shù)據(jù)傳輸命令,并附上REFRESH命令,發(fā)送給客戶端;如果EventQueue為NULL,設(shè)置一個最大等待時間,等待其他線程向EventQueue加入數(shù)據(jù),等待超時后,向客戶端發(fā)送REFRESH命令,進入下一次輪詢。
這里的EventQueue是典型的生產(chǎn)消費模式,EventSource是生產(chǎn)線程,它負(fù)責(zé)把數(shù)據(jù)入隊列,如果隊滿則等待,直到消費線程消費。由于EventSource是Sleep一段時間才進行入隊列操作,而消費線程沒有Sleep,需要通過判斷ALIVE一直循環(huán)等待,因此消費速度快于生產(chǎn)速度,造成消費線程大部分時間處于等待狀態(tài),導(dǎo)致出現(xiàn)Servlet線程占用問題。
圖1 Pushlet總體架構(gòu)圖
圖2核心類的對應(yīng)關(guān)系
2 Servlet線程占用問題
無論是Pull/Poll或者HTTP Streaming,保持連接長期處于打開狀態(tài)會消耗服務(wù)器資源。當(dāng)?shù)却隣顟B(tài)的Servlet持有一個持久性請求時,該Servlet會獨占一個線程。這將限制Pushlet對傳統(tǒng)Servlet引擎的可伸縮性,因為客戶機的數(shù)量會很快超過服務(wù)器能有效處理的線程數(shù)量。實際應(yīng)用中考慮系統(tǒng)的穩(wěn)定性和性能是非常重要的,必須要解決這些細(xì)節(jié)問題。
將Pushlet系統(tǒng)抽象簡化為三個元素:Client、WebContainer和PushletManager。處理請求的流程如圖3所示。首先,Client發(fā)送請求,WebContainer接收到請求之后,新建一個Servlet線程來處理這個請求;接著,調(diào)用PushletMannager方法,獲取當(dāng)前消息隊列中的消息,如果沒有消息,則等待直至超時;最后,根據(jù)處理的結(jié)果提交響應(yīng),Servlet線程結(jié)束。
圖3 Pushlet系統(tǒng)中Servlet請求時序圖
其中第二步的消息處理是最耗時的。在此過程中,Servlet線程一直處于阻塞狀態(tài),直到業(yè)務(wù)方法執(zhí)行完畢。在處理業(yè)務(wù)的過程中,Servlet資源一直被占用而得不到釋放,對于并發(fā)較大的應(yīng)用,會成為性能瓶頸,需考慮有效調(diào)用Servlet線程,及時釋放資源。
Servlet3.0作為JavaEE6規(guī)范體系中一員,隨著JavaEE6規(guī)范一起發(fā)布。該版本提供了若干新特性用于簡化Web應(yīng)用的開發(fā)和部署?;赟ervlet3.0的異步處理支持,Servlet線程不再需要一直阻塞,而是在接收到請求之后Servlet線程可以將耗時的操作委派給另一個線程來完成,自己在不生成響應(yīng)的情況下返回至容器。針對業(yè)務(wù)處理較耗時的情況,這將大大減少服務(wù)器資源的占用,并且提高并發(fā)處理速度。
3 Servlet異步特性及應(yīng)用
3.1原理
使用Servlet3.0之前,HTTP請求完全由WebContainer線程處理,其生命周期由業(yè)務(wù)處理時間決定。WebContainer的Http線程是很珍貴的,并發(fā)數(shù)量由容器線程決定。利用Servlet3.0異步特性進行優(yōu)化的基本思路就是將請求資源與消息處理線程分開,整個生命周期不完全由WebContainer管理。
將章節(jié)3中的流程圖3調(diào)整為如圖4所示。首先,Client發(fā)送請求,WebContainer接收到請求之后,首先需要對請求攜帶的數(shù)據(jù)進行一些預(yù)處理。接著,Servlet線程根據(jù)當(dāng)前時刻,消息隊列是否有消息分別進行處理,有消息則直接生成響應(yīng)數(shù)據(jù),并將響應(yīng)發(fā)送給客戶端;如果沒有將請求轉(zhuǎn)交給一個異步線程來執(zhí)行消息推送,線程本身返回至WebContainer,這樣便能縮短WebContainer生命周期,只處理連接請求和一些預(yù)處理。此時Servlet還沒有生成響應(yīng)數(shù)據(jù),在Servlet異步線程執(zhí)行過程中,有消息則直接生成響應(yīng)數(shù)據(jù)(異步線程擁有ServletRequest和ServletResponse對象的引用),無消息則等待線程超時,超時后發(fā)送超時消息給Client。如此一來,在消息隊列為null時,Servlet線程不再一直處于阻塞狀態(tài)以等待消息轉(zhuǎn)發(fā)邏輯的處理,而是啟動異步線程之后可以立即返回。
圖4優(yōu)化后Pushlet系統(tǒng)中Servlet請求時序圖
3.2應(yīng)用
優(yōu)化步驟如下:
1)使用支持Servlet3.0的Web應(yīng)用服務(wù),例如Apache Tomcat 7.0以上版本、Glassfish3.0以上版本。本文選用Glassfish3.1.1作為Web應(yīng)用服務(wù)。
2)使用注解或者配置Web.xml文件,對Pushlet這個Servlet的AsyncSupported屬性設(shè)置為true,使Pushlet成為支持異步的Servlet。
3)新建一個單例類AsyncContextManager,用于管理在進行異步請求中產(chǎn)生的AsyncContext對象。在AsyncContextManager中,使用線程的ConcurrentHashMap存放AsyncContext對象。
4)EventQueue類中,用LinkedBlockingDeque替換使用數(shù)組實現(xiàn)的消息隊列,以獲得更好的性能和安全性。
5)區(qū)分E_REFRESH事件和E_LISTEN事件的處理動作,將原來FetchEvents函數(shù)中處理E_LISTEN事件的代碼抽取出來,單獨寫成FetchListenEvents函數(shù)。使FetchEvents處理E_REFRESH事件,而FetchListenEvents處理E_LISTEN事件。
6)在4)的基礎(chǔ)上,對FetchEvents函數(shù)增加消息隊列是否為NULL的判斷,當(dāng)為NULL時,進行異步處理,將該請求的AsyncContext對象存放到AsyncContextManager中,留待響應(yīng)時候使用;否則直接將消息隊列中的消息返回給Client。
4性能比較
對Pushelt項目中自帶的nl.justobjects.pushlet.test.PushletPingApplication進行改寫,模擬N個客戶端對優(yōu)化前后的Pushelt發(fā)送請求,逐步提升個數(shù)N,判斷在客戶端個數(shù)N的情況下,客戶端能否得到正常響應(yīng),逼近并發(fā)性能的極限值。
使用兩臺配置均為Intel i5-2300處理器、物理內(nèi)存4G的PC進行測試。PC_A模擬N個客戶端向服務(wù)器PC_B分別進行10次發(fā)送消息的請求。
表1為測試結(jié)果,當(dāng)客戶端數(shù)量為20(并發(fā)請求為200)時,客戶端均能正常響應(yīng),當(dāng)客戶端數(shù)量為80(并發(fā)請求為800)時,優(yōu)化前Pushlet客戶端出現(xiàn)無法得到正常響應(yīng)的現(xiàn)象,而優(yōu)化后則正常運行。實驗結(jié)果表明,進行異步特性優(yōu)化后,服務(wù)器的并發(fā)吞吐能力得到較大提高。
表1并發(fā)性能測試對比
“-”表示未通過測試,“1%”表示通過測試且cpu占用率為1%
5結(jié)束語
雖然基于不同方案的服務(wù)器推送技術(shù)正在不斷成熟,尤其很多的開源項目在這個領(lǐng)域非?;钴S,但要解決的問題還有很多。經(jīng)過對Pushlet服務(wù)端源代碼的逐步分析,找到導(dǎo)致服務(wù)端并發(fā)吞吐性能較低的原因:HTTP請求完全由WebContainer線程完成進行同步處理,直至到整個業(yè)務(wù)生命周期結(jié)束,才釋放WebContainer線程,造成WebContainer線程利用率十分低下。Servlet的異步特性可以使Pushlet系統(tǒng)的WebContainer線程得到充分利用,使系統(tǒng)在處理HTTP請求的并發(fā)吞吐能力得到提升,在同等硬件條件下,能夠處理更多的HTTP請求。
本文利用Servlet異步特性對Pushlet系統(tǒng)并發(fā)吞吐性能進行了優(yōu)化,給出了一個并發(fā)性能優(yōu)化的切入點。對于Pushlet系統(tǒng)并發(fā)吞吐性能的進一步優(yōu)化,可以從Web服務(wù)器群集、使用線程池、優(yōu)化調(diào)度等方面加以研究應(yīng)用。
參考文獻(xiàn):
[1]景慎艷.基于Pushlet的服務(wù)器推技術(shù)的研究與應(yīng)用[J].現(xiàn)代計算機,2009(10):132-134.
[2]張曉芳,李國徽,蘭小玲.Java+Servlet模式的WebGIS性能優(yōu)化研究[J].計算機應(yīng)用研究, 2011,28(11): 4222-4224.
[3]梁昌勇,張怡遠(yuǎn),張俊嶺.基于Pushlet的RFID數(shù)據(jù)推送技術(shù)研究[J].計算機技術(shù)與發(fā)展,2009, 9(10): 85-88.
[4] JUST VAN DEN BROECKE. Pushlet Whitepaper[EB/OL].(2002-08-06).http://www.pushlets.com/.
[5]李洋,張文博,魏峻,等.基于序列模式的Servlet容器緩存替換[J].Journal of Software,2007, 18(7): 1592-1602.
[6]金玉善,黃永平,付慶興.Pushlet網(wǎng)絡(luò)推技術(shù)研究及應(yīng)用[J].吉林大學(xué)學(xué)報:信息科學(xué)版, 2009, 27(3): 248-253.
[7]孫清國,朱瑋,劉華軍,等.Web應(yīng)用中的服務(wù)器推送技術(shù)研究綜述[J].計算機系統(tǒng)應(yīng)用,2008, 11: 116-120.
[8]陳航,趙方.基于服務(wù)器推送技術(shù)和XMPP的Web IM系統(tǒng)實現(xiàn)[J].計算機工程與設(shè)計,2010, 31(5): 925-928.