Web應用中實時消息技術總結

在互聯網應用中,不少時候咱們須要在客戶端和服務端之間進行實時的消息交互,好比下面這些常見的應用場景:html

  • SNS網站用戶互動消息通知(weibo/twitter/qzone)
  • 門戶網站實時滾動新聞(突發事件)、文字直播(體育賽事)
  • 在線聊天室(在線客服)
  • 實時數據展現(實時股價,實時商品價格,服務器實時監控等)

接下來的內容裏,我羅列了在web開發中常見的實時消息的實現技術方案,每種方案都各有優缺點,在不一樣的應用場景下有不一樣的選擇。(聲明:附圖來源於網絡,http://stackoverflow.com/questions/11077857/what-are-long-polling-websockets-server-sent-events-sse-and-comet,我上傳到百度圖庫了:D)html5

###1. 客戶端輪詢模式(polling) 客戶端定時請求服務器來詢問是否有新的消息產生,這種狀況下客戶端每次請求都要創建一次http鏈接,服務器都要產生一個響應信息。java

優勢:實現簡單,使用方便,開發成本很低,適合剛起步的小型應用或是其它方案的備用方案。
缺點:消息有延遲,網絡通訊消耗大(特別是移動網絡下),服務器容易產生峯值請求。
實現:瀏覽器裏用js定時請求,或是移動設備上native app裏定時發http請求。

polling

###2. 長輪詢模式(long polling)nginx

客戶端與服務器創建鏈接後,服務器並不立刻返回消息,而是不斷去查詢後臺(如:數據庫)是否有新消息產生,直到有新消息產生時,服務器才返回。客戶端接收響應信息處理完後關閉當前連接,並立刻發起一個新的請求,繼續等待服務返回新的消息,如此循環下去。因此,這個long polling也能夠叫作服務端的輪詢。web

跟上面的polling模式相比:
優勢:消息到達客戶端更及時;減小了http請求不停地建立、關閉形成的沒必要要浪費。
缺點:服務端須要保持大量鏈接,http鏈接的維護開銷較大;每次產生消息後都須要從新建立鏈接。
實現:客戶端只要簡單的發送請求,等待響應便可。服務器端須要作兩方面的工做:一是保持大量的鏈接(Non-Blocking I/O);二是讀取後臺的消息更新(異步定時輪詢或由事件觸發)。

long polling

###3. 基於流的模式(http streaming) 在這種狀況下,客戶端與服務器端保持一個持久的鏈接,服務器端有新消息產生時經過這個持久鏈接不斷地返回給客戶端。這種模式與上面的long polling差很少,差異就是隻須要建立一次鏈接就能夠了。另外,要注意http header中須要設置Connection: keep-alive和Transfer-Encoding: chunked這兩個屬性。ajax

跟上面long polling模式相比:
優勢:消息能夠實時到達客戶端;客戶端與服務端之間只須要創建一次鏈接。
缺點:服務器端也要維持大量鏈接,開銷很大。
實現:客戶端通常有兩種方式:一是隱藏iframe的src指向服務器端url,不斷地進行dom渲染;二是使用ajax裏的XMLHttpRequest對象來實現。對於服務端來講,和long polling同樣,要保持大量鏈接和處理後臺的消息更新。

streaming

###4. WebSocket WebSocket是HTML5開始提供的一種瀏覽器與服務器間進行全雙工通信的網絡技術,瀏覽器和服務器只須要要作一個握手的動做,而後,瀏覽器和服務器之間就造成了一條快速通道。二者之間就直接能夠數據互相傳送。數據庫

優勢:實時通信,雙向交互,節省服務器資源和帶寬。
缺點:瀏覽器支持不足。
實現:客戶端須要html5來實現,服務器端通常的web服務器都有支持。

socket

那在咱們實際的應用中,上面幾種方案應該怎麼選擇呢?api

  • polling輪詢機制很簡單,使用方便,都是http短鏈接,在應用架構上跟普通接口api一致,很是適合小型應用和剛起步的應用,能夠節省不少開發成本。瀏覽器

  • 當咱們的用戶量上升到必定程度後(好比日活躍百萬級),產品作得愈來愈受歡迎了,咱們對消息到達的及時性也就有更高的要求了,並且這種輪詢機制對服務器壓力也是一種考驗,這時候咱們就能夠考慮long polling或http streaming的方式了,這兩種方式其實在服務端實現上差很少,主要是保持大量長鏈接和異步(或事件觸發)獲取消息。在保持鏈接方面,在java的nio出現後,爲咱們提供了便利,主流的應用服務器像tomcat和jetty都有支持,可是,工做在jvm上的服務器保持大量socket鏈接時gc是個很嚴重的問題。因此,這裏我要介紹一下藉助nginx的push模塊來實現保持鏈接以及消息實時推送。tomcat

    這兩個模塊工做在nginx上,能夠維持大量的http鏈接,實現了pub/sub協議來支持消息發送,基本流程是下圖這樣的,發送者(publisher)把消息推送到nginx服務器上,而後push模塊負責把消息發送給訂閱者(client):

    pub/sub

    藉助nginx的這個push模塊,咱們能夠省去大量的工做,應用程序只須要關注業務邏輯(也就是publisher作的事),簡化了應用架構,同時nginx的高性能也有不錯的表現。

  • 當咱們的產品發展到千萬級的日活躍時,咱們可能就要考慮更好的方案了,好比上面的提到的WebSocket,可是由於瀏覽器兼容的問題,這個方案並非主流的解決方案。通常這種狀況下,咱們就要考慮基於tcp的socket長鏈接模式了,經過某種消息推送協議(xmpp/mqtt/自定議協議等)來實現客戶端和服務器端的實時交互。

實時消息技術在互聯網應用中很普遍,涉及的內容也不少,我這裏只是作了一些歸納性的總結。其實每一種業務場景都有好多細節要考慮,好比消息的傳播方式(廣播、單播)就對業務邏輯的處理有很大的影響。在這裏,歡迎各位路過的朋友指點,分享!

參考文章:
http://zh.wikipedia.org/zh/Comet_(web%E6%8A%80%E6%9C%AF)
http://zh.wikipedia.org/wiki/WebSocket

推薦閱讀: HTTP協議理解與應用總結

相關文章
相關標籤/搜索