国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于事件驅(qū)動(dòng)的高性能WebSocket服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn)

2018-02-27 03:06曹文彬譚新明劉傳文
關(guān)鍵詞:隊(duì)列進(jìn)程消息

曹文彬 譚新明 劉 備 劉傳文

(武漢理工大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院 湖北 武漢 430063)

0 引 言

隨著互聯(lián)網(wǎng)Web 2.0技術(shù)的高速發(fā)展,基于瀏覽器的Web應(yīng)用已經(jīng)成為用戶獲取互聯(lián)網(wǎng)信息的主要途徑之一。Web技術(shù)在不同領(lǐng)域的深入應(yīng)用和信息時(shí)代高并發(fā)連接請(qǐng)求下海量數(shù)據(jù)的不斷產(chǎn)生,使得Web應(yīng)用程序?qū)g覽器與服務(wù)器間的數(shù)據(jù)實(shí)時(shí)傳遞有了更高的要求[1],主要體現(xiàn)在數(shù)據(jù)傳遞的實(shí)時(shí)性和高并發(fā)帶來的海量數(shù)據(jù)這兩個(gè)方面。傳統(tǒng)的即時(shí)通信大多基于“拉取”方式,比如文獻(xiàn)[2],通過輪詢查看服務(wù)器是否有新消息,缺點(diǎn)是定期輪詢?cè)诘托畔⒙实那闆r下,可能打開或者關(guān)閉許多不必要的連接造成資源的浪費(fèi)。文獻(xiàn)[3]對(duì)輪詢進(jìn)行了改進(jìn),會(huì)對(duì)通信雙方建立的連接保持一段時(shí)間,但是還會(huì)存在通信效率低下、資源浪費(fèi)的情況。文獻(xiàn)[4]提出的是基于Iframe的流(streaming)技術(shù),缺點(diǎn)是這種方式不可跨域,并且錯(cuò)誤處理可控性不強(qiáng)。以上方式不僅沒有提高數(shù)據(jù)傳遞的實(shí)時(shí)性,反而制約了實(shí)時(shí)Web應(yīng)用的性能。與傳統(tǒng)方式相比,基于WebSocket協(xié)議的“推送”方式則是由服務(wù)器將消息主動(dòng)地發(fā)送給瀏覽器用戶。這種通信取代了單個(gè)TCP套接字,通過第一次請(qǐng)求連接就建立起雙向通信實(shí)時(shí)響應(yīng)的Socket連接,可以減少瀏覽器與服務(wù)器之間的交互次數(shù),從而降低網(wǎng)絡(luò)通信的負(fù)擔(dān),提高實(shí)時(shí)通信效率。

目前,主流語言都支持WebSocket協(xié)議在服務(wù)器端的實(shí)現(xiàn),而本文采用基于Node.js平臺(tái)的JavaScript語言來實(shí)現(xiàn),主要原因有:1) W3C標(biāo)準(zhǔn)化的WebSocket API和Node.js平臺(tái)支持的語言都是JavaScript,并且都是基于事件驅(qū)動(dòng)模式編程,可以減低開發(fā)難度,縮短開發(fā)周期。2) Node.js的事件驅(qū)動(dòng)和非阻塞I/O模型在相對(duì)低系統(tǒng)資源耗用下性能突出,負(fù)載能力出眾,十分適合在分布式設(shè)備上運(yùn)行的數(shù)據(jù)密集型的實(shí)時(shí)Web應(yīng)用[5-6]??偟膩碚f,正是因?yàn)镹ode.js在處理高并發(fā)的用戶連接請(qǐng)求時(shí)處理能力出色,所以才選擇Node.js作為WebSocket服務(wù)器的實(shí)現(xiàn)平臺(tái),解決高并發(fā)所帶來的問題。

本文考慮到實(shí)時(shí)數(shù)據(jù)傳輸?shù)男屎涂赡苊鎸?duì)的大量用戶,基于Node.js設(shè)計(jì)了一款WebSocket服務(wù)器,可以應(yīng)對(duì)高并發(fā)場(chǎng)景下實(shí)時(shí)數(shù)據(jù)的推送問題。在服務(wù)器的實(shí)現(xiàn)過程中,首先對(duì)WebSocket技術(shù)應(yīng)用和Node.js平臺(tái)進(jìn)行了研究分析,根據(jù)WebSocket服務(wù)器應(yīng)該具有的功能進(jìn)行關(guān)鍵技術(shù)的選擇。其次進(jìn)行了WebSocket服務(wù)器的框架設(shè)計(jì),并對(duì)其中的功能模塊進(jìn)行了詳細(xì)說明。緊接著詳細(xì)闡述了WebSocket服務(wù)器的實(shí)現(xiàn)細(xì)節(jié),并將改善后的Node.js應(yīng)用其中。最后通過功能測(cè)試和性能測(cè)實(shí)驗(yàn)證了WebSocket服務(wù)器實(shí)時(shí)數(shù)據(jù)推送的可行性。

1 相關(guān)工作

1.1 WebSocket服務(wù)器的研究

隨著WebSocket技術(shù)的發(fā)展,對(duì)于Web實(shí)時(shí)通信系統(tǒng)、社交訂閱系統(tǒng)、監(jiān)控系統(tǒng)等實(shí)時(shí)場(chǎng)景中的數(shù)據(jù)推送問題,目前已經(jīng)逐步采用基于WebSocket的推送方式實(shí)現(xiàn),取代了傳統(tǒng)的拉取方式。通過研究發(fā)現(xiàn),WebSocket技術(shù)在服務(wù)器端已經(jīng)有了廣泛的研究應(yīng)用。文獻(xiàn)[7]中建立了一個(gè)Web應(yīng)用程序來測(cè)量實(shí)時(shí)風(fēng)傳感器數(shù)據(jù)的單向傳輸延遲,該Web應(yīng)用程序用WebSocket連接替代了HTTP連接,并與HTTP輪詢和長輪詢進(jìn)行了比較。文獻(xiàn)[8]提出了基于WebSocket的印刷包裝機(jī)遠(yuǎn)程監(jiān)控方法,并用MFC完成了服務(wù)端程序,有效提高了印刷包裝行業(yè)的生產(chǎn)流程數(shù)字化程度。文獻(xiàn)[9]將WebSocket運(yùn)用在云監(jiān)控系統(tǒng)中,實(shí)驗(yàn)結(jié)果表明WebSocket監(jiān)控系統(tǒng)的平均延遲時(shí)間通常低于輪詢,F(xiàn)lashSocket和Socket解決方案。文獻(xiàn)[10]設(shè)計(jì)了基于B/S架構(gòu)的實(shí)時(shí)監(jiān)測(cè)Web可視化系統(tǒng),利用WebSocket在客戶端和服務(wù)器端間建立全雙工通信,實(shí)現(xiàn)生產(chǎn)數(shù)據(jù)實(shí)時(shí)推送,有效降低了網(wǎng)絡(luò)吞吐量,提高了通信效率。文獻(xiàn)[11]設(shè)計(jì)并實(shí)現(xiàn)了一種基于WebSocket推送技術(shù)和SVG技術(shù)的B/S模式下的實(shí)時(shí)監(jiān)控系統(tǒng),提高了監(jiān)視系統(tǒng)的實(shí)時(shí)性、穩(wěn)定性。文獻(xiàn)[12]提出了一種基于WebSocket協(xié)議的服務(wù)器推送技術(shù),利用了復(fù)雜時(shí)間處理技術(shù)對(duì)數(shù)據(jù)進(jìn)行快速處理。

總的來說:1) 上述文獻(xiàn)只提及到WebSocket技術(shù)在數(shù)據(jù)實(shí)時(shí)推送方面的優(yōu)勢(shì),對(duì)于高并發(fā)請(qǐng)求可能帶來的大量實(shí)時(shí)數(shù)據(jù),并沒有說明如何處理;2) 上述文獻(xiàn)只是在服務(wù)器端引入了WebSocket技術(shù),以實(shí)現(xiàn)某個(gè)場(chǎng)景下數(shù)據(jù)實(shí)時(shí)推送的功能,沒有以WebSocket技術(shù)為核心,從服務(wù)器角度去設(shè)計(jì)、實(shí)現(xiàn)一款WebSocket服務(wù)器。綜合以上分析,本文以Node.js、Redis、RabbitMQ等開源項(xiàng)目為基礎(chǔ),設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)基于事件驅(qū)動(dòng)的WebSocket服務(wù)器,不僅考慮到了傳統(tǒng)的拉取方式難以保障數(shù)據(jù)的實(shí)時(shí)性,而且從服務(wù)器性能角度考慮,引入第三方框架,解決實(shí)時(shí)數(shù)據(jù)的緩存問題。

WebSocket服務(wù)器利用Node.js平臺(tái)是因?yàn)镹ode.js本身就適用于高并發(fā)的Web系統(tǒng),可以給服務(wù)器的處理性能提供保障。利用緩存數(shù)據(jù)庫Redis設(shè)計(jì)了分層的緩存層,實(shí)現(xiàn)數(shù)據(jù)的內(nèi)部級(jí)存儲(chǔ)。引入的異步消息隊(duì)列RabbitMQ,降低了WebSocket服務(wù)器的壓力,提高了吞吐量。具體來說,本文的主要貢獻(xiàn)如下:1) 在Web系統(tǒng)中的數(shù)據(jù)實(shí)時(shí)推送方面,引入第三方框架,設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)WebSocket推送服務(wù)器;2) 對(duì)于實(shí)時(shí)推送服務(wù)器的運(yùn)行平臺(tái)Node.js在單進(jìn)程方面存在的不足進(jìn)行優(yōu)化改進(jìn),使實(shí)時(shí)推送服務(wù)器在穩(wěn)定和高并發(fā)性能方面更加突出。

1.2 Node.js的高并發(fā)和穩(wěn)定性研究

對(duì)于本文研究的高性能WebSocket服務(wù)器來說,高并發(fā)是服務(wù)器應(yīng)該達(dá)到的首要性能指標(biāo),其次服務(wù)器在運(yùn)行的過程中要保障穩(wěn)定性。通過Marc Fasel從CouchDB上讀取JSON數(shù)據(jù)來比較Node.js和JavaEE之間的性能,以及雷凱等對(duì)Node.js和Apache下的Python和PHP所做的性能對(duì)比實(shí)驗(yàn)可知,Node.js在高并發(fā)的場(chǎng)景下表現(xiàn)穩(wěn)定,并且可以對(duì)連接進(jìn)行很好的響應(yīng)[13-14]。

Node.js作為WebSocket服務(wù)器中的關(guān)鍵技術(shù),采用基于事件驅(qū)動(dòng)的異步I/O模型[15]。異步I/O是指如果調(diào)用線程執(zhí)行I/O操作,線程只是發(fā)送I/O請(qǐng)求給操作系統(tǒng),線程本身不被阻塞而繼續(xù)執(zhí)行,當(dāng)I/O完成操作系統(tǒng)將會(huì)以事件的形式通知線程。事件驅(qū)動(dòng)是指為了能夠處理異步I/O,線程一直在執(zhí)行一個(gè)事件循環(huán),循環(huán)檢查是否有未處理的事件,并調(diào)用相應(yīng)的事件處理函數(shù)。在Node.js整個(gè)異步I/O的執(zhí)行回調(diào)過程中,事件循環(huán)類似于一個(gè)生產(chǎn)者/消費(fèi)者模型,首先通過觀察者來判斷是否有事件需要處理,而不同的底層操作系統(tǒng)所提供的線程池部分正是通過libuv來消除差異。Node.js提供的這一套處理機(jī)制,保證了用戶的請(qǐng)求能夠被整個(gè)異步I/O模型高效、快速的處理。Node.js異步I/O的回調(diào)流程如圖1所示。

圖1 Node.js異步I/O的回調(diào)流程圖

圖1的回調(diào)過程是在Node.js的單進(jìn)程模式下完成的,通過研究發(fā)現(xiàn),Node.js的單進(jìn)程模式在帶來好處的同時(shí)也存在一些缺陷。首先,Node.js的單線程無法利用多核CPU,造成了多核CPU的浪費(fèi);其次,一旦單線程停止響應(yīng)或者崩潰退出,錯(cuò)誤會(huì)引起整個(gè)應(yīng)用退出,服務(wù)器就會(huì)立即停止工作。在Node.js的現(xiàn)行版本中,官方內(nèi)置了一個(gè)Cluster模塊,該模塊可以直接運(yùn)行多個(gè)進(jìn)程實(shí)現(xiàn)Node.js多核處理,能夠提高CPU利用率。但是通過對(duì)Cluster模塊源碼的研究發(fā)現(xiàn)了一些問題:1) Cluster模塊在進(jìn)程管理方面十分有限,判斷子進(jìn)程是否正常工作的方式是:給子進(jìn)程分配新任務(wù)時(shí),查看子進(jìn)程是否有響應(yīng)。隨著失效的子進(jìn)程越來越多時(shí),可能出現(xiàn)所有的子進(jìn)程都無法處理任務(wù)的情況。2) Cluster在任務(wù)分配的策略上采用的是Round-Robin方式,雖然實(shí)現(xiàn)起來簡單,但僅提供這一種分派策略在選擇方案上顯得單一,其次在不同的應(yīng)用環(huán)境中因?yàn)榇嬖诟鞣N細(xì)節(jié)上的差異,僅通過這一種方式無法保證每次任務(wù)分配達(dá)到的效果是合理的。

本文對(duì)Node.js的多進(jìn)程模塊進(jìn)行了改進(jìn)和優(yōu)化,提高了Node.js的并發(fā)處理能力和穩(wěn)定性,為WebSocket服務(wù)器的高性能提供了保障。

2 WebSocket服務(wù)器的設(shè)計(jì)

整個(gè)服務(wù)器采用了三層架構(gòu)方式,分別是用戶服務(wù)層、中間層和數(shù)據(jù)服務(wù)層。用戶服務(wù)層負(fù)責(zé)接收用戶獲取實(shí)時(shí)數(shù)據(jù)的連接請(qǐng)求,并將用戶信息傳遞給中間層。中間層負(fù)責(zé)接收用戶服務(wù)層傳遞過來的用戶信息,并對(duì)數(shù)據(jù)服務(wù)層提供的實(shí)時(shí)數(shù)據(jù)進(jìn)行處理。然后再把實(shí)時(shí)數(shù)據(jù)通過用戶服務(wù)層推送給用戶,數(shù)據(jù)服務(wù)層則會(huì)調(diào)用數(shù)據(jù)中心提供的API獲取實(shí)時(shí)數(shù)據(jù)。用戶服務(wù)層主要包括連接建立與維護(hù)、消息推送模塊。中間層主要由任務(wù)分派、緩存數(shù)據(jù)庫、進(jìn)程監(jiān)控、實(shí)時(shí)數(shù)據(jù)處理等功能模塊組成。數(shù)據(jù)服務(wù)層包括實(shí)時(shí)數(shù)據(jù)的獲取和消息隊(duì)列,具體的分層架構(gòu)設(shè)計(jì)如圖2所示。

結(jié)合圖2中的WebSocket服務(wù)器架構(gòu),對(duì)WebSocket服務(wù)器的處理流程進(jìn)行了設(shè)計(jì),如圖3所示,主要包括以下部分:

(1) 用戶請(qǐng)求連接

服務(wù)器在啟動(dòng)后,會(huì)一直監(jiān)聽來自用戶的WebSocket請(qǐng)求。當(dāng)用戶的WebSocket請(qǐng)求到來,請(qǐng)求所攜帶訂閱或取消訂閱信息將會(huì)被WebSocket服務(wù)器解析,并將解析的請(qǐng)求信息存儲(chǔ)到緩存數(shù)據(jù)庫中。

(2) 緩存數(shù)據(jù)庫

主要用來存儲(chǔ)用戶連接信息以及worker子進(jìn)程的相關(guān)信息。目前Redis,Memcached都是key-value型的高性能緩沖數(shù)據(jù)庫,但是Redis相比Memcached來說,支持更多服務(wù)器端的數(shù)據(jù)操作和更加豐富的數(shù)據(jù)結(jié)構(gòu)[16]。本文中將采用Redis作為WebSocket服務(wù)器的緩存數(shù)據(jù)庫,用以減少程序中內(nèi)存泄露的風(fēng)險(xiǎn)。

(3) 主進(jìn)程進(jìn)行任務(wù)分派

WebSocket服務(wù)器在啟動(dòng)時(shí)就會(huì)創(chuàng)建多個(gè)worker進(jìn)程,通過負(fù)載均衡算法,主進(jìn)程將WebSocket服務(wù)器接收到的客戶端請(qǐng)求分發(fā)到各個(gè)worker子進(jìn)程處理。每個(gè)worker子進(jìn)程會(huì)處理多個(gè)任務(wù),在緩存數(shù)據(jù)庫中會(huì)有一個(gè)“子進(jìn)程任務(wù)信息表”,用來存放子進(jìn)程和任務(wù)之間的對(duì)應(yīng)關(guān)系,便于進(jìn)行消息推送。

(4) 進(jìn)程管理

主要是對(duì)“子進(jìn)程隊(duì)列表”中的子進(jìn)程進(jìn)行監(jiān)控、維護(hù)。緩存數(shù)據(jù)庫中會(huì)存放一張“子進(jìn)程隊(duì)列表”,保存的是當(dāng)前所有有效子進(jìn)程的相關(guān)信息,包括處理任務(wù)數(shù)、是否有效、運(yùn)行時(shí)間等。對(duì)于檢測(cè)到的失效進(jìn)程,會(huì)刪除表中相應(yīng)的進(jìn)程信息,而對(duì)于重啟的新進(jìn)程,會(huì)把相關(guān)信息添加到表中。每隔一段時(shí)間,會(huì)收集子進(jìn)程的狀態(tài)信息更新“子進(jìn)程隊(duì)列表”,確保表中信息的準(zhǔn)確性和時(shí)效性。

(5) 實(shí)時(shí)數(shù)據(jù)獲取

(6) 消息隊(duì)列

在數(shù)據(jù)獲取和數(shù)據(jù)處理單元之間設(shè)計(jì)一個(gè)消息隊(duì)列,主要是應(yīng)對(duì)某時(shí)刻出現(xiàn)大量的更新數(shù)據(jù),起到消峰減壓的效果。本文采用了RabbitMQ作為消息中間件,首先將“數(shù)據(jù)中心”的消息發(fā)送到RabbitMQ消息隊(duì)列中,再由用戶請(qǐng)求處理子進(jìn)程從RabbitMQ中進(jìn)行消息消費(fèi)。

(7) 子進(jìn)程進(jìn)行數(shù)據(jù)處理

根據(jù)不同的應(yīng)用場(chǎng)景,實(shí)時(shí)數(shù)據(jù)的處理規(guī)則需要進(jìn)行定制。WebSocket服務(wù)器發(fā)送的數(shù)據(jù)可能是文本、圖片、二進(jìn)制或者是其他數(shù)據(jù)類型的數(shù)據(jù),但是WebSocket協(xié)議只能處理文本數(shù)據(jù)消息和二進(jìn)制數(shù)據(jù)消息,所以要進(jìn)行數(shù)據(jù)類型的轉(zhuǎn)換。

(8) 消息推送

每個(gè)worker進(jìn)程都維護(hù)了自己服務(wù)的所有客戶端連接,并且這些連接信息都存儲(chǔ)在緩存數(shù)據(jù)庫中,進(jìn)程只需要將數(shù)據(jù)處理單元處理的數(shù)據(jù)發(fā)送到對(duì)應(yīng)的用戶連接中。

圖3 WebSocket服務(wù)器處理流程示意圖

通過對(duì)實(shí)際應(yīng)用中的大多數(shù)即時(shí)通信服務(wù)器的研究,本節(jié)對(duì)WebSocket服務(wù)器的整體架構(gòu)進(jìn)行了設(shè)計(jì)。在設(shè)計(jì)的過程中著重考慮了以下幾方面:1) 在工作場(chǎng)景中WebSocket服務(wù)器可能面臨的高并發(fā);2) 對(duì)于多進(jìn)程的管理,以保障WebSocket服務(wù)器的穩(wěn)定性;3) WebSocket服務(wù)器的跨平臺(tái)性和擴(kuò)展性。

3 WebSocket服務(wù)器的實(shí)現(xiàn)

3.1 用戶請(qǐng)求連接

WebSocket服務(wù)器的用戶請(qǐng)求處理包括:用戶請(qǐng)求連接和用戶發(fā)送的消息格式定義??蛻舳苏?qǐng)求WebSocket服務(wù)器建立連接的過程,就是打開階段的握手協(xié)議,可以選擇Socket.IO進(jìn)行實(shí)現(xiàn)。

摘 要:初中生的英語核心素養(yǎng)包括:語言能力、文化意識(shí)、思維品質(zhì)、學(xué)習(xí)能力,共四個(gè)維度。初中英語課堂設(shè)計(jì)提倡發(fā)展學(xué)生思維品質(zhì),采用既強(qiáng)調(diào)語言學(xué)習(xí)過程又有利于提高學(xué)生學(xué)習(xí)成效的語言教學(xué)途徑和方法?;谟⒄Z學(xué)科核心素養(yǎng)設(shè)計(jì)的英語課堂是教師特別是外國語學(xué)校教師值得重視和積極開展的。以牛津英語7B unit 5 welcome to the unit 教學(xué)為例,探討通過精心設(shè)計(jì)英語課堂教學(xué),提高學(xué)生核心素養(yǎng)。

當(dāng)用戶與WebSocket服務(wù)器建立連接后,用戶發(fā)送的消息體格式要滿足一定規(guī)則:一種是數(shù)據(jù)信息的訂閱請(qǐng)求,另外一種就是數(shù)據(jù)信息的取消訂閱請(qǐng)求。訂閱請(qǐng)求為“subscribe”,取消訂閱請(qǐng)求為“unSubscribe”。當(dāng)WebSocket服務(wù)器應(yīng)用于多應(yīng)用多租戶模式中,用appID識(shí)別符區(qū)分不同的應(yīng)用,每個(gè)請(qǐng)求攜帶的信息用“msg”識(shí)別符進(jìn)行識(shí)別。每個(gè)請(qǐng)求可能訂閱或取消訂閱多個(gè)數(shù)據(jù)信息,若請(qǐng)求多個(gè)數(shù)據(jù)信息,數(shù)據(jù)信息之間用“,”隔開。最終訂閱請(qǐng)求發(fā)送的字符串格式為″{appID:″+appID+″,cmd:′subscribe′,msg:[″+message+″]}″,取消訂閱請(qǐng)求發(fā)送的字符串格式為″{appID:″+appID+″,cmd:“unSubscribe”,msg:[″+message+″]}″。

3.2 實(shí)時(shí)數(shù)據(jù)獲取和數(shù)據(jù)處理

實(shí)時(shí)數(shù)據(jù)獲取是指WebSocket服務(wù)器從數(shù)據(jù)中心獲取實(shí)時(shí)更新的數(shù)據(jù),數(shù)據(jù)中心提供獲取實(shí)時(shí)數(shù)據(jù)的接口getRealTimeData(int appID,List ids),其中appID是應(yīng)用編號(hào),ids是用戶請(qǐng)求訂閱的數(shù)據(jù)id的集合。WebSocket服務(wù)器采用每隔一定時(shí)間間隔調(diào)用一次接口,來保證數(shù)據(jù)的實(shí)時(shí)性。在這一部分的實(shí)現(xiàn)過程中,采取了“主動(dòng)通知”模式。所謂主動(dòng)通知,就是當(dāng)數(shù)據(jù)發(fā)送更改時(shí),主動(dòng)通知子進(jìn)程。在實(shí)現(xiàn)的過程中,需要?jiǎng)?chuàng)建一個(gè)獨(dú)立的通知進(jìn)程,為了不混合業(yè)務(wù)邏輯,此進(jìn)程只用來發(fā)送數(shù)據(jù)更新的通知和查詢狀態(tài)是否更改。主動(dòng)通知模式相比于所有的子進(jìn)程都去定時(shí)輪詢,降低了查詢狀態(tài)的開銷,并且由于不會(huì)涉及多個(gè)進(jìn)程進(jìn)行狀態(tài)查詢,狀態(tài)響應(yīng)處的壓力也不會(huì)過大,所以可以降低輪詢時(shí)間,提升數(shù)據(jù)的準(zhǔn)確性。

數(shù)據(jù)處理部分主要是指數(shù)據(jù)類型的轉(zhuǎn)換,WebSocket服務(wù)器發(fā)送的數(shù)據(jù)可能是文本、圖片、二進(jìn)制或者是其他數(shù)據(jù)類型的數(shù)據(jù),然而WebSocket協(xié)議只能處理文本數(shù)據(jù)消息和二進(jìn)制數(shù)據(jù)消息[17]。因此WebSocket服務(wù)器從數(shù)據(jù)中心獲得實(shí)時(shí)更新的數(shù)據(jù)后,需要對(duì)不同類型的實(shí)時(shí)數(shù)據(jù)進(jìn)行處理統(tǒng)一轉(zhuǎn)換為成二進(jìn)制。

Node.js提供了一個(gè)全局構(gòu)造函數(shù)Buffer,可以對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行操作,實(shí)現(xiàn)string、int、Json等格式的轉(zhuǎn)換。具體接口和說明如表1所示。

表1 WebSocket服務(wù)器數(shù)據(jù)處理接口

3.3 緩存數(shù)據(jù)庫

WebSocket服務(wù)器接收客戶端發(fā)送的消息體時(shí),能夠獲取客戶端和WebSocket服務(wù)器之間的連接信息connection。同時(shí)客戶端向WebSocket服務(wù)器發(fā)送的是滿足一定格式的消息體,WebSocket服務(wù)器通過解析消息體,可以獲取到{“appID”+“msg”}信息??蛻舳丝赡馨l(fā)送多個(gè)消息體,WebSocket服務(wù)器會(huì)將客戶端發(fā)送的消息體進(jìn)行拆分,以{“appid”+“msg”}為key,以訂閱該key的所有connection的集合connections為value存儲(chǔ)到Redis中。例如,一個(gè)用戶發(fā)送了多個(gè)消息體,通過解析得到信息{“appID1”+“UserOneGetMsg1”}、{“appID1”+“UserOneGetMsg2”}、{“appID2”+“UserOneGetMsg1”}。Redis首先會(huì)判斷Key集合中是否存在這些信息,假如通過判斷匹配到了{(lán)“appID1”+“UserOneGetMsg1”},就把該用戶的connection添加到對(duì)應(yīng)的集合connections中;假如通過判斷沒有匹配到{“appID1”+“UserOneGetMsg2”},則會(huì)新建一個(gè)對(duì)應(yīng)的集合connections,然后把用戶連接信息connection再添加到新建集合中。消息體的解析過程以及生成的新數(shù)據(jù)在Redis中的存儲(chǔ)流程如圖4所示。

圖4 Redis中的存儲(chǔ)流程圖

3.4 消息隊(duì)列

RabbitMQ是AMQP(高級(jí)消息隊(duì)列)協(xié)議的一個(gè)開源實(shí)現(xiàn),作為老牌的消息中間件不僅功能完善、性能穩(wěn)定,還有很多監(jiān)聽插件可以選擇,提供了豐富的API。本文選用RabbitMQ作為WebSocket服務(wù)器的消息隊(duì)列中間件,以期達(dá)到以下兩個(gè)方面的效果:1) 減少程序中隊(duì)列消費(fèi)不及時(shí)造成的內(nèi)存泄露問題。2) 提升服務(wù)器的性能。

在Node.js中提供了一個(gè)amqp模塊,該模塊為所有遵循AMQP協(xié)議的消息隊(duì)列服務(wù)器提供Node.js環(huán)境下的客戶端。具體的實(shí)現(xiàn)步驟:1) 安裝RabbitMQ消息服務(wù)器,進(jìn)行環(huán)境變量和權(quán)限的設(shè)置。2) 用瀏覽器打開http://localhost:15672,檢測(cè)是否能夠訪問RabbitMQ管理控制臺(tái)。3) 安裝Node.js與RabbitMQ交互所需要的node-amqp模塊。4) 通過amqp.createConnection()函數(shù)建立連接,生成隊(duì)列并進(jìn)行隊(duì)列初始化。

3.5 消息的推送

WebSocket服務(wù)器提供了兩個(gè)消息推送接口,具體接口和說明如表2所示,它們分別支持文本類型和二進(jìn)制類型的數(shù)據(jù)推送。

表2 WebSocket服務(wù)器數(shù)據(jù)推送接口

WebSocket服務(wù)器從數(shù)據(jù)中心獲得實(shí)時(shí)更新的數(shù)據(jù)后,執(zhí)行實(shí)時(shí)數(shù)據(jù)的推送,其具體執(zhí)行流程如圖5所示。

圖5 數(shù)據(jù)推送流程圖

3.6 進(jìn)程管理

WebSocket服務(wù)器的Node.js平臺(tái)雖然最初版本采用的是單進(jìn)程工作模式,但在隨后的發(fā)行版本中引入了多進(jìn)程模式,以改善單進(jìn)程對(duì)多核CPU利用率低、單進(jìn)程崩潰等問題。進(jìn)程管理模塊就是對(duì)WebSocket服務(wù)器的多個(gè)工作子進(jìn)程進(jìn)行監(jiān)控、維護(hù),一旦發(fā)現(xiàn)有失效的工作子進(jìn)程,就會(huì)創(chuàng)建新的工作子進(jìn)程替代失效子進(jìn)程繼續(xù)工作,并將任務(wù)按負(fù)載均衡策略分派給不同的工作子進(jìn)程處理,為WebSocket服務(wù)器的穩(wěn)定性提供保障。在進(jìn)程管理模塊的實(shí)現(xiàn)過程中,對(duì)原有的進(jìn)程管理模塊進(jìn)行了優(yōu)化,分別增加了“心跳機(jī)制”和最小連接策略。

首先,對(duì)多進(jìn)程的管理模式進(jìn)行了重新設(shè)計(jì),主進(jìn)程根據(jù)配置創(chuàng)建若干個(gè)子進(jìn)程,并將創(chuàng)建的子進(jìn)程信息存入到“子進(jìn)程隊(duì)列表”中,然后通過“心跳機(jī)制”對(duì)子進(jìn)程進(jìn)行監(jiān)控,并根據(jù)收集到的子進(jìn)程信息對(duì)“子進(jìn)程隊(duì)列表”進(jìn)行更新。若是在監(jiān)控中發(fā)現(xiàn)有失效進(jìn)程,主進(jìn)程會(huì)創(chuàng)建新的子進(jìn)程,并將已失效的子進(jìn)程從“子進(jìn)程隊(duì)列表”中刪除。監(jiān)控子進(jìn)程是否失效是通過“心跳機(jī)制”來實(shí)現(xiàn):worker進(jìn)程定時(shí)發(fā)送心跳給master進(jìn)程,若master進(jìn)程在一定時(shí)間內(nèi)未能收到worker進(jìn)程的心跳,則可以認(rèn)為此worker進(jìn)程已經(jīng)停止響應(yīng),否則會(huì)重啟一個(gè)新的worker進(jìn)程繼續(xù)提供服務(wù)。通過引入這種監(jiān)控機(jī)制,可以保障一直有工作進(jìn)程響應(yīng)客戶請(qǐng)求,提升了服務(wù)器的穩(wěn)定性,能夠?qū)崿F(xiàn)持續(xù)、健壯地為客戶提供服務(wù),改進(jìn)后的進(jìn)程管理模塊如圖6所示。

圖6 改進(jìn)后的進(jìn)程管理模塊功能流程圖

WebSocket服務(wù)器接收到的新請(qǐng)求首先會(huì)被主進(jìn)程監(jiān)聽到,然后才會(huì)分派給子進(jìn)程。任務(wù)分派的方式是通過進(jìn)程間的通信來實(shí)現(xiàn)的,在進(jìn)行任務(wù)分派時(shí),主進(jìn)程會(huì)按照制定的負(fù)載均衡策略分派任務(wù)給某一個(gè)子進(jìn)程處理。Node.js原有的任務(wù)分配策略只有靜態(tài)的輪轉(zhuǎn)算法,本文增加了針對(duì)長連接的最少連接策略。最小連接算法解決了靜態(tài)輪轉(zhuǎn)算法只能保證請(qǐng)求數(shù)量均衡的弱點(diǎn),考慮了各個(gè)工作子進(jìn)程當(dāng)前的負(fù)載信息,相對(duì)靜態(tài)輪轉(zhuǎn)算法具有較好的均衡效果。

最少連接算法原理簡單易懂,在本文中主要是通過對(duì)比“子進(jìn)程隊(duì)列表”中每個(gè)子進(jìn)程的當(dāng)前連接數(shù)目,選擇其中連接數(shù)最少的子進(jìn)程接收新來的任務(wù),然后在一個(gè)更新周期結(jié)束之后,對(duì)隊(duì)列表中的連接數(shù)進(jìn)行更新。例如一個(gè)由n個(gè)子進(jìn)程組成的進(jìn)程隊(duì)列P={P(0),P(1),P(2),…,P(i),…,P(n-1)},其中變量i(0≤i

圖7 Node.js進(jìn)程管理模塊最少連接算法流程圖

4 實(shí)驗(yàn)及結(jié)果

4.1 實(shí)驗(yàn)環(huán)境

操作系統(tǒng):64位Windows 10;處理器:Core i5-4590 @ 3.30 GHz 四核;內(nèi)存:8 GB。

4.2 功能測(cè)試

將WebSocket服務(wù)器應(yīng)用在多應(yīng)用、多租戶的實(shí)際場(chǎng)景中,由此在實(shí)驗(yàn)中設(shè)計(jì)了兩種不同的應(yīng)用,不同的應(yīng)用發(fā)送不同的數(shù)據(jù)。數(shù)據(jù)由Node.js自身循環(huán)產(chǎn)生,產(chǎn)生的兩種數(shù)據(jù),用Json形式表示如下:模擬的A應(yīng)用的數(shù)據(jù)格式為{appID:1,sensorNum:′001′,data:[″+Math.round(Math.random()*100)+″]},B應(yīng)用的數(shù)據(jù)格式為{appID:2,deviceNum:′001′,lng:?+lng+?,lat:?+lat+?}。原始數(shù)據(jù)如圖8所示。

圖8 功能測(cè)試部部分原始數(shù)據(jù)包

這里產(chǎn)生的數(shù)據(jù)相當(dāng)于WebSocket服務(wù)器運(yùn)行中從數(shù)據(jù)中心獲得的實(shí)時(shí)數(shù)據(jù),將數(shù)據(jù)直接推送到RabbitMQ消息隊(duì)列中。在RabbitMQ網(wǎng)頁管理后臺(tái),可以查看RabbitMQ消息,如圖9所示,即表示消息已經(jīng)成功進(jìn)入了消息隊(duì)列。

圖9 RabbitMQ消息隊(duì)列后臺(tái)管理

頁面一打開就會(huì)發(fā)送WebSocket連接請(qǐng)求到WebSocket服務(wù)器,WebSocket服務(wù)器接收到用戶請(qǐng)求并且連接成功后,會(huì)根據(jù)用戶訂閱消息把數(shù)據(jù)信息實(shí)時(shí)地推送給客戶端瀏覽器。頁面的訂閱按鈕模擬用戶發(fā)送WebSocket訂閱請(qǐng)求,頁面的取消按鈕模擬用戶發(fā)送WebSocket取消訂閱請(qǐng)求,如圖10所示。

圖10 取消訂閱后重新訂閱

圖10中框出表示:用戶在取消訂閱后,瀏覽器客戶端將不再接收到sensorNum為002的數(shù)據(jù)信息,而sensorNum為001的數(shù)據(jù)信息會(huì)持續(xù)接收到。通過實(shí)驗(yàn)也表明,WebSocket服務(wù)器是可以達(dá)到基本功能需求的。

4.3 性能測(cè)試

WebSocket服務(wù)器的性能測(cè)試采用Jmeter2.0.11作為測(cè)試工具,并安裝支持WebSocket協(xié)議的JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar插件。安裝好插件后創(chuàng)建一個(gè)WebSocket服務(wù)器測(cè)試線程組,并在線程組中添加測(cè)試線程WebSocketTest,同時(shí)添加察看結(jié)果樹、Summary-Report、聚合報(bào)告等多個(gè)監(jiān)聽器。

通過表3可知當(dāng)并發(fā)連接數(shù)低于750時(shí),錯(cuò)誤率為0;當(dāng)連接數(shù)達(dá)到1 500時(shí),錯(cuò)誤率在1.52%左右,是可以滿足在多應(yīng)用多租戶模式下的實(shí)時(shí)數(shù)據(jù)推送需求的。

表3 系統(tǒng)性能測(cè)試

5 結(jié) 語

本文回顧了即時(shí)通信領(lǐng)域發(fā)展過程中的技術(shù)方案,進(jìn)行了詳細(xì)的對(duì)比分析,歸納總結(jié)了WebSocket的特性,并推薦在實(shí)時(shí)系統(tǒng)中采用WebSocket技術(shù)。分析了國內(nèi)外WebSocket技術(shù)在服務(wù)器端的應(yīng)用,總結(jié)出目前并沒有從服務(wù)器角度去設(shè)計(jì)一款WebSocket服務(wù)器,用以解決在高并發(fā)、穩(wěn)定性等方面可能存在的問題。研究總結(jié)了Node.js、Redis、RabbitMQ等開源項(xiàng)目

的特點(diǎn),設(shè)計(jì)出了WebSocket服務(wù)器的架構(gòu)圖,詳細(xì)闡述了各模塊的實(shí)現(xiàn)方案。為了進(jìn)一步提高WebSocket服務(wù)器的高并發(fā)和穩(wěn)定性,對(duì)Node.js多進(jìn)程模塊進(jìn)行改進(jìn)和優(yōu)化。最后對(duì)WebSocket服務(wù)器進(jìn)行實(shí)驗(yàn)測(cè)試,驗(yàn)證結(jié)果表明該WebSocket服務(wù)器在功能和性能上達(dá)到了預(yù)期設(shè)計(jì)的目標(biāo)。在下一階段的研究中,將會(huì)在WebSocket服務(wù)器中加入日志管理模塊,通過日志回放服務(wù)器的運(yùn)行狀態(tài)。

[1] 陸晨,馮向陽,蘇厚勤.HTML5 WebSocket握手協(xié)議的研究與實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用與軟件,2015,32(1):128-131.

[2] Takagi H,Kleinrock L.Analysis of polling systems[J].Performance Evaluation,1985,5(3):206.

[3] Loreto S,Saintandre P,Salsano S,et al.Known Issues and Best Practices for the Use of Long Polling and Streaming in Bidirectional HTTP[J].Choice Current Reviews for Academic Libraries,2011,4(1846):4.

[4] Loreto S,Saintandre P,Salsano S,et al.Known Issues and Best Practices for the Use of Long Polling and Streaming in Bidirectional HTTP[J].Choice Current Reviews for Academic Libraries,2011,4(1846):4.

[5] 許會(huì)元,何利力.NodeJS的異步非阻塞I/O研究[C]//全國工業(yè)控制計(jì)算機(jī)技術(shù)年會(huì),2014.

[6] Tilkov S,Vinoski S.Node.js:Using JavaScript to Build High-Performance Network Programs[J].IEEE Internet Computing,2010,14(6):80-83.

[7] Pimentel V,Nickerson B G.Communicating and Displaying Real-Time Data with WebSocket[J].IEEE Internet Computing,2012,16(4):45-53.

[8] 蔡錦達(dá),蔣振飛.基于WebSocket的印刷包裝機(jī)械遠(yuǎn)程監(jiān)控方法的研究[J].包裝工程,2013(15):87-90.

[9] Ma K,Zhang W.Introducing browser-based high-frequency cloud monitoring system using WebSocket Proxy[J].International Journal of Grid & Utility Computing,2015,6(1).

[10] 劉維峰,左澤軍,趙利強(qiáng),等.基于HTML5的生產(chǎn)裝置實(shí)時(shí)監(jiān)測(cè)可視化[J].計(jì)算機(jī)工程與設(shè)計(jì),2015(3):809-813.

[11] 金豐,張悅,雍鵬.基于雙服務(wù)器的B/S模式監(jiān)測(cè)系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)仿真,2014,31(2):201-205.

[12] 張玲,張翠肖.WebSocket服務(wù)器推送技術(shù)的研究[J].河北省科學(xué)院學(xué)報(bào),2014,31(2):49-53.

[13] Lei K,Ma Y,Tan Z.Performance Comparison and Evaluation of Web Development Technologies in PHP,Python, and Node.js[C]//IEEE,International Conference on Computational Science and Engineering.IEEE Computer Society,2014:661-668.

[14] Marc Fasel.Performance Comparison Between Node.js and Java EE For Reading JSON Data from CouchDB[EB/OL].[2013-10-22].http://blog.shinetech.com/2013/10/22/performance-comparison-between-node-js-and-java-ee.

[15] O’reilly.Node:up and running:scalable server-side code with javascript[M].Oreilly Media,2012.

[16] 王心妍.Memcached和Redis在高速緩存方面的應(yīng)用[J].無線互聯(lián)科技,2012(9):8-9.

[17] Melnikov A.The WebSocket Protocol[OL].2011.https://www.rfc-editor.org/rfc/rfc6455.txt.

猜你喜歡
隊(duì)列進(jìn)程消息
隊(duì)列隊(duì)形體育教案
隊(duì)列里的小秘密
基于多隊(duì)列切換的SDN擁塞控制*
一張圖看5G消息
債券市場(chǎng)對(duì)外開放的進(jìn)程與展望
改革開放進(jìn)程中的國際收支統(tǒng)計(jì)
在隊(duì)列里
晚步見道旁花開
社會(huì)進(jìn)程中的新聞學(xué)探尋
俄羅斯現(xiàn)代化進(jìn)程的阻礙
社会| 弥渡县| 京山县| 华池县| 赞皇县| 凌云县| 景德镇市| 武鸣县| 新巴尔虎左旗| 大厂| 桐乡市| 年辖:市辖区| 兴文县| 中阳县| 沐川县| 手游| 南通市| 桐梓县| 星座| 文安县| 五大连池市| 华亭县| 乌兰察布市| 娄底市| 上思县| 方城县| 长葛市| 桂平市| 凤台县| 灌南县| 朔州市| 镇远县| 邓州市| 新竹市| 台中市| 灌南县| 凤庆县| 江阴市| 民乐县| 昔阳县| 任丘市|