目錄
一、服務器推送技術
1、服務器推送技術的興起
一下部分內容摘自百科
隨着AJAX技術的興起,讓廣大開發人員又一次看到了使用瀏覽器來替代桌面應用的機會,並且這次機會非常大。AJAX將整個頁面的刷新變成頁面局部的刷新,並且數據的傳送是以異步方式進行,這使得網絡延遲帶來的視覺差異將會消失。AJAX還利用DHTML和豐富的JavasSript語言來模擬桌面系統的各種事件和響應過程,以及平滑滾動和拖拽的效果。還不止這些,更有一些IT巨頭(Google、Sun、Oracle等)提供了非常豐富的AJAX開發工具,使得開發和調試AJAX應用變得簡單高效,並且開發的AJAX應用還可以跨越各種瀏覽器和操作系統。在這種情況下基於AJAX的Web應用迅速涌起,吞噬着原有桌面系統的份額。聊天工具、郵件閱讀器、博客編輯器,甚至是Office辦公軟件和文字處理軟件在瀏覽器中都有着美麗的外觀和幾乎可以與桌面系統媲美的交互界面。Google更是提出“有了瀏覽器和Google,就不需要微軟”的口號和策略。在Ajax的世界中,除了傳統的CAD設計軟件和大型遊戲軟件等因爲對系統硬件的苛刻需求,還離不開桌面系統以外,似乎其他所有的應用都可以變成Web應用了。
但是,在瀏覽器中的AJAX應用中存在一個致命的缺陷無法滿足傳統桌面系統的需求。那就是“服務器發起的消息傳遞(Server-Initiated Message Delivery)”。在很多的應用當中,服務器軟件需要向客戶端主動發送消息或信息。因爲服務器掌握着系統的主要資源,能夠最先獲得系統的狀態變化和事件的發生。當這些變化發生的時候,服務器需要主動地向客戶端實時地發送消息。例如股票的變化。在傳統的桌面系統中,這種需求沒有任何問題,因爲客戶端和服務器之間通常存在着持久的連接,這個連接可以雙向傳遞各種數據。而基於HTTP協議的Web應用卻不行。上節中也提到過,在Web世界中,服務器永遠是被動地發送數據,前提是客戶端必須先發送請求。瀏覽器其實並不知道服務器的信息什麼時候會有改變,爲了模擬實時的交流,或者不想錯過某些信息,只能通過輪詢(Polling)技術不斷刷新頁面來獲得最新的數據。這種方式不但浪費服務器的資源,最重要的是每次建立(或關閉)新的HTTP連接都有一定的延遲,這種延遲使得頻繁信息傳遞的應用無法忍受。於是就產生了“服務器推送技術”。
2、應用場景
服務器推送技術幹嘛用?就是讓用戶在使用網絡應用的時候,不需要一遍又一遍的去手動刷新就可以及時獲得更新的信息。大家平時在上各種視頻網站時,對視頻節目進行歡樂的吐槽和評論,會看到各種彈幕,當然,他們是用flash技術實現的,對於我們沒有用flash的應用,一樣可以實現彈幕。又比如在股票網站,往往可以看到,各種股票信息的實時刷新,上面的這些都是基於服務器推送技術。
一般實現服務推送技術有以下幾種方式,Ajax短輪詢,**Comet,WebSocket。**以下就重點介紹每個方式的實現。
二、Ajax短輪詢
1、定義
就是用一個定時器不停的去網站上請求數據。比如定義一個定時器,每3s請求一次。雖然實現簡單,但問題也很明顯,存在延遲時間。並且不斷去請求服務器端給服務器端造成一定的壓力
setInterval(function() {
$.ajax({
……………………
});
}, 3000);
2、特點
- 服務端基本不用改造
- 服務器沉重壓力和資源的浪費
- 數據同步不及時
三、Comet
“服務器推”是一種很早就存在的技術,以前在實現上主要是通過客戶端的套接口,或是服務器端的遠程調用。因爲瀏覽器技術的發展比較緩慢,沒有爲“服務器推”的實現提供很好的支持,在純瀏覽器的應用中很難有一個完善的方案去實現“服務器推”並用於商業程序。,因爲 AJAX 技術的普及,gmail等等在實現中使用了這些新技術;同時“服務器推”在現實應用中確實存在很多需求。稱這種基於 HTTP長鏈接、無須在瀏覽器端安裝插件的“服務器推”技術爲“Comet”。他主要由兩種實現。ajax的長輪詢和SSE
3.1 AJAX 的長輪詢
1、定義
由客戶端發起請求,但是服務端並不會立即返回,而是保持該鏈接。知道有新的數據更新的時候才返回響應,並關閉鏈接。客戶端則處理完相應信息之後,再重新發送給服務器新的請求。
實現方式
①Servlet3裏的異步任務
②Spring的DeferedResult
2、特點
- 實時性好,性能較高
- 長期佔用鏈接,喪失了無狀態高併發特點,並且服務器處理鏈接有限。當達到瓶頸時無法響應新的請求
適用於股票和實時通訊系統
3.2 SSE
1、定義
嚴格地說,HTTP 協議無法做到服務器主動推送信息。但是,有一種變通方法,就是服務器向客戶端聲明,接下來要發送的是流信息(streaming)。
也就是說,發送的不是一次性的數據包,而是一個數據流,會連續不斷地發送過來。這時,客戶端不會關閉連接,會一直等着服務器發過來的新的數據流,視頻播放就是這樣的例子。本質上,這種通信就是以流信息的方式,完成一次用時很長的下載。
SSE 就是利用這種機制,使用流信息向瀏覽器推送信息。它基於 HTTP 協議,目前除了 IE/Edge,其他瀏覽器都支持。
2、特點
- SSE 使用 HTTP 協議,現有的服務器軟件都支持。WebSocket 是一個獨立協議。
- SSE 屬於輕量級,使用簡單;WebSocket 協議相對複雜。
- SSE 默認支持斷線重連,WebSocket 需要自己實現。
- SSE 一般只用來傳送文本,二進制數據需要編碼後傳送,WebSocket 默認支持傳送二進制數據。
- SSE 支持自定義發送的消息類型。
3、SSE的使用規範
HTTP 頭信息
服務器向瀏覽器發送的 SSE 數據,必須是 UTF-8 編碼的文本,具有如下的 HTTP 頭信息。
- Content-Type: text/event-stream
- Cache-Control: no-cache
- Connection: keep-alive
上面三行之中,第一行的Content-Type必須指定 MIME 類型爲event-steam。
消息格式
每一次發送的信息,由若干個message組成,每個message之間用\n\n分隔。每個message內部由若干行組成,每一行都是如下格式。
[field]: value\n
上面的field可以取四個值。
字段 | 含義 | 舉例 |
data | 數據內容 |
如果數據很長,可以分成多行,最後一行用\n\n結尾,前面行都用\n結尾,如發送 JSON 數據的例子 data: {\n data: "foo": "bar",\n data: "baz", 555\n data: }\n\n |
event | 自定義的事件類型,默認是message事件。瀏覽器可以用addEventListener()監聽該事件。 |
event: foo\n data: a foo event\n\n 標示事件名字是foo,觸發瀏覽器的foo事件; |
id | 數據標識符用id字段表示,相當於每一條數據的編號 | 瀏覽器用lastEventId屬性讀取這個值。一旦連接斷線,瀏覽器會發送一個 HTTP 頭,裏面包含一個特殊的Last-Event-ID頭信息,將這個值發送回來,用來幫助服務器端重建連接。因此,這個頭信息可以被視爲一種同步機制。id: msg1\n |
retry | 服務器可以用retry字段,指定瀏覽器重新發起連接的時間間隔。 |
兩種情況會導致瀏覽器重新發起連接:一種是時間間隔到期,二是由於網絡錯誤等原因,導致連接出錯。 retry: 10000\n |
四、WebSocket通信
1、什麼是webSocket
WebSocket ——一種在2011 年被互聯網工程任務組(IETF)標準化的協議。
WebSocket解決了一個長期存在的問題:既然底層的協議(HTTP)是一個請求/響應模式的交互序列,那麼如何實時地發佈信息呢?AJAX提供了一定程度上的改善,但是數據流仍然是由客戶端所發送的請求驅動的。還有其他的一些或多或少的取巧方式(Comet).
WebSocket規範以及它的實現代表了對一種更加有效的解決方案的嘗試。簡單地說,WebSocket提供了“在一個單個的TCP連接上提供雙向的通信,結合WebSocket API,它爲網頁和遠程服務器之間的雙向通信提供了一種替代HTTP輪詢的方案"。但是最終它們仍然屬於擴展性受限的變通之法。也就是說,WebSocket 在客戶端和服務器之間提供了真正的雙向數據交換。WebSocket 連接允許客戶端和服務器之間進行全雙工通信,以便任一方都可以通過建立的連接將數據推送到另一端。WebSocket 只需要建立一次連接,就可以一直保持連接狀態。這相比於輪詢方式的不停建立連接顯然效率要大大提高。
Web瀏覽器和服務器都必須實現 WebSockets 協議來建立和維護連接。
2、特點
- HTML5中的協議,實現與客戶端與服務器雙向,基於消息的文本或二進制數據通信
- 適合於對數據的實時性要求比較強的場景,如通信、直播、共享桌面,特別適合於客戶與服務頻繁交互的情況下,如實時共享、多人協作等平臺。
- 採用新的協議,後端需要單獨實現
- 客戶端並不是所有瀏覽器都支持
3、WebSocket通信握手
Websocket借用了HTTP的協議來完成一部分握手
客戶端的請求
Connection 必須設置 Upgrade,表示客戶端希望連接升級。
Upgrade 字段必須設置 Websocket,表示希望升級到 Websocket 協議。
Sec-WebSocket-Key 是隨機的字符串,服務器端會用這些數據來構造出一個 SHA-1 的信息摘要。把 “Sec-WebSocket-Key” 加上一個特殊字符串 “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然後計算 SHA-1 摘要,之後進行 BASE-64 編碼,將結果做爲 “Sec-WebSocket-Accept” 頭的值,返回給客戶端。如此操作,可以儘量避免普通 HTTP 請求被誤認爲 Websocket 協議。
Sec-WebSocket-Version 表示支持的 Websocket 版本。RFC6455 要求使用的版本是 13,之前草案的版本均應當棄用。
服務器端
Upgrade: websocket
Connection: Upgrade
依然是固定的,告訴客戶端即將升級的是 Websocket 協議,而不是mozillasocket,lurnarsocket或者shitsocket。
然後, Sec-WebSocket-Accept 這個則是經過服務器確認,並且加密過後的 Sec-WebSocket-Key 。
後面的, Sec-WebSocket-Protocol 則是表示最終使用的協議。
至此,HTTP已經完成它所有工作了,接下來就是完全按照Websocket協議進行
4、WebSocket通信-STOMP協議
WebSocket是個規範,在實際的實現中有HTML5規範中的WebSocket API、WebSocket的子協議STOMP。
STOMP(Simple Text Oriented Messaging Protocol)
- 簡單(流)文本定向消息協議
- STOMP協議的前身是TTMP協議(一個簡單的基於文本的協議),專爲消息中間件設計。是屬於消息隊列的一種協議, 和AMQP, JMS平級. 它的簡單性恰巧可以用於定義websocket的消息體格式. STOMP協議很多MQ都已支持, 比如RabbitMq, ActiveMq。
- 生產者(發送消息)、消息代理、消費者(訂閱然後收到消息)
- STOMP是基於幀的協議
5、WebSocket 與SSE的對比
WebSocket 與 SSE 作用相似,都是建立瀏覽器與服務器之間的通信渠道,然後服務器向瀏覽器推送信息。
SSE和WebSocket相比的優勢。最大的優勢就是便利:不需要添加任何新組件,用任何你習慣的後端語言和框架就能繼續使用。你不用爲新建虛擬機、弄一個新的IP或新的端口號而勞神,就像在現有網站中新增一個頁面那樣簡單。可以稱爲既存基礎設施優勢。
總體來說,WebSocket 更強大和靈活。因爲它是全雙工通道,可以雙向通信;SSE 是單向通道,只能服務器向瀏覽器發送,因爲流信息本質上就是下載。如果瀏覽器向服務器發送信息,就變成了另一次 HTTP 請求。
五、技術比較
|
1、短輪詢 |
2、長輪詢 |
3、SSE |
4、WebSocket |
瀏覽器支持度 |
最高 |
很高 |
中(IE和Edge均不支持) |
中(早期的瀏覽器不支持) |
實時性 |
最低 |
較高 |
很高 |
很高 |
代碼實現複雜度 |
最容易 |
較容易 |
容易 |
最複雜 |
連接性質 |
短連接 |
長連接 |
長連接
|
長連接
|
適用 |
需要服務極大量或極小量的用戶,實時性要求不高 |
準實時性的應用,比較關注瀏覽器的兼容性 |
實時,基本都是文本交互的應用 |
實時,需要支持多樣化的用戶數據類型的應用或者是原生程序 |
當然技術沒有好壞之分,具體還要看使用場景。就比如京東用的什麼?Ajax短輪詢。京東的痛點是什麼?要用有限的資源來爲千萬級甚至上億的用戶提供服務,如果是用長連接,對於接入的服務器,比如說Nginx,是很大的壓力,光是爲用戶維持這個長連接都需要成百上千的Nginx的服務器,這是很划不來的。因爲對於京東這類購物網站來說,用戶的瀏覽查詢量是遠遠大於用戶下單量的,京東需要注重的是服務更多的用戶,而且相對於用戶瀏覽頁面的圖片等等的流量而言,這點帶寬浪費佔比是很小的。所以我們看京東的付款後的實現,是用的短輪詢機制,而且時長放大到了5秒。希望大家瞭解相關的技術,並滲透到具體業務場景中,選擇最合適的方案。