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