網頁端收訊息,究竟是推還是拉?
任何脫離業務的架構設計都是耍流氓。網頁端收訊息,究竟是推還是拉?
需求緣起
對於在網頁端登入的使用者A,傳送方,也就是訊息的來源有幾方面:
系統發給A的“系統通知”,可能對實時性要求沒這麼高
使用者發給A的“聊天訊息”,有對實時性要求比較高,越實時越好
訊息的處理方,也就是系統側,一般來說:
有服務對訊息進行邏輯處理
有資料庫對資料進行落地
有快取對資料進行加速
拋開這些技術細節不談,暫且認為服務端對每一個使用者都有一個“待收訊息”的佇列,裡面存放了需要給這個使用者的一切訊息。
訊息的接收方,也就是使用者A,如果是在網頁端登入,因為HTTP協議是“請求-響應”式的,服務端與網頁之間沒有訊息通道,對於這類“收訊息”的需求,是如何處理的呢?
方案一、輪詢拉取
輪詢拉取,是最容易想到的實現方式:
傳送方傳送了訊息,先入佇列
網頁端起一個timer,每個一段時間(例如10秒),發起一個輪詢請求,拉取佇列裡的訊息
如果佇列裡有訊息,就返回訊息
如果佇列裡無訊息,就10秒後再次輪詢
這種方式的優勢是:實現簡單,直觀且,容易理解,網際網路興起時,人數不多的聊天室就是這麼玩的。
畫外音:創辦於1996年的網際網路老站碧海銀沙,曾經中國最火爆的聊天室,已於2017.9.27停止運營。
缺點也很明顯:
實時性差:最壞的情況下,1條訊息進入佇列後,10s之後才會收到
效率低下:發訊息是一個低頻動作,如果10次輪詢才收到1條訊息,請求有效性只有10%,浪費了大量伺服器資源
更要命的是,在這種方案下,實時性與效率是一對不可調和的矛盾:如果將輪詢週期設為1/10,將時延縮短到1秒,意味著100次輪詢才會收到1條訊息,請求有效性則降為了1%。
方案二、建立長連線
如果要兼顧實時性和效率,長連線是最佳之選,PC端聊天軟體基本都是使用長連線。網頁端常見的實現長連線的方式有兩種:
WebSocket
FlashSocket
這兩種方案的細節不再展開,ta們均有一定的侷限性。
更為通用的方式,是“長輪詢”。
長輪詢,是通過拼裝HTTP短連線來達到長連線的效果,即保證了訊息100%實時,又最大化的系統效率。
方案三、HTTP長輪詢
HTTP長輪詢的核心在於,瀏覽器與服務端之間建立了一條“通知連線”,它的特點是:
這是一條browser發往web-server的HTTP連線
這條連線只用來收取推送通知
不像普通的“請求-響應”式HTTP請求,這個HTTP會被服務端夯住,直到有推送通知到達,或者超過約定的時間
畫外音:對於HTTP請求,為了提高效率,一般來說browser和web-server都會有一些設定,如果一條HTTP請求長時間沒有資料(例如,150秒),會被斷開。“通知連線”為了不被browser和web-server粗暴斷開,一般會設定一個約定閾值(例如,小於150秒),由系統返回一個空訊息,以便“優雅返回”。
更具體的,對於這條“夯住”與“只收推送通知”的“通知連線”,是怎麼玩的呢?
場景1,發起通知連線時,佇列里正好有訊息,則:
發起通知連線,正好佇列裡有訊息
實時把佇列裡的訊息帶回
立馬再發起通知連線
場景二,發起通知連線時,佇列裡無訊息,則:
發起通知連線時,佇列裡無訊息
一直等待,直到觸發“時間閾值”,返回無訊息
立馬再發起通知連線
場景三,新訊息來時,正好有通知連線在,則:
新訊息來時,正好有通知連線在
通知連線實時將訊息帶回
立馬再發起通知連線
上面三個場景的最終狀態,都是“一定,永遠,會有一條通知連線,連線在瀏覽器與伺服器之間”,這樣就能夠保證訊息的實時性。當然,有人會說,HTTP的返回與再次發起會有一個時間差,如果這個時間差,恰巧有新訊息過來呢?
場景四,新訊息來時,沒有通知連線,則:
新訊息來時,沒有通知連線
把新訊息放入佇列
最後這個場景,發生的概率非常小,但也確保了在“HTTP的返回與再次發起會有一個時間差”內,訊息不會丟失,在通知連線發起後,訊息能夠實時返回。
總結
網頁端收訊息,究竟是推還是拉?
最容易想到的是拉,但實時性和效率是一對無法調和的矛盾
最佳的方式是推,但WebSocket和FlashSocket各有侷限性
最通用的方式是長輪詢,通過HTTP短連線拼裝長連線,具體是通過“夯住”“只收推送通知”的“通知連線”來實現的,能夠做到訊息的實時性到達
挖坑篇:《feed流,單聊群聊,系統通知,狀態同步,到底是推還是拉?》
填坑篇1:《系統通知,究竟是推還是拉?》
填坑篇2:《狀態同步,究竟是推還是拉?》
若有收穫,隨手轉發。
相關文章
- 狀態同步,究竟是推還是拉?
- RocketMQ -- 訊息拉取MQ
- 【RocketMQ】訊息的拉取MQ
- 7-RocketMQ拉取訊息MQ
- 如何判斷頁面是pc端還是移動端,進入不同的頁面
- Metaverse究竟是泡沫還是未來?Metaverse
- 快取,究竟是淘汰,還是修改?快取
- [譯]如何在Service Worker和網頁客戶端之間傳送訊息網頁客戶端
- 訊息佇列究竟是個什麼鬼?佇列
- RocketMQ -- 寫在訊息拉取前MQ
- feed留,單聊群聊,系統通知,狀態同步,到底是推還是拉?
- 爬蟲究竟是合法還是違法的?爬蟲
- Lazarus使用IPC收發訊息
- MQ不丟訊息,究竟是怎麼實現的?MQ
- JavaScript 工作原理之九-網頁訊息推送通知機制JavaScript網頁
- RocketMQ中PullConsumer的訊息拉取原始碼分析MQ原始碼
- 訊息佇列批次收發訊息,請避開這 5 個坑!佇列
- 什麼是KYC?與加密究竟是水火不容,還是可以兼得?加密
- 魅族19系列到現在還沒訊息你看好驍龍8還是天璣?
- IM系統的MQ訊息中介軟體選型:Kafka還是RabbitMQ?MQKafka
- 委內瑞拉遭遇全球最大規模停電,是管理不善還是網路攻擊?
- 關於QQ可以發訊息但是網頁刷不出來問題網頁
- JSer全棧化技術棧推薦(一)——原生移動端是天堂還是泥潭JS全棧
- 線上雲養豬刷屏,究竟是薅羊毛還是割韭菜?
- App如何利用推送訊息有效實現拉新促活?APP
- 直播原始碼網站,訊息圖示在收到訊息時展示訊息條數原始碼網站
- 沒用過訊息佇列?一文帶你體驗RabbitMQ收發訊息佇列MQ
- 什麼是訊息佇列?佇列
- 端到端拉通
- 參加IT程式設計培訓,究竟是選擇Python還是Java?程式設計PythonJava
- 理性談電競:究竟是舉步維艱還是進無止境?
- 網路核心之TCP是如何傳送和接收訊息的TCP
- 騰訊放棄收購DNF開發商NEXON,嫌貴還是不合適?
- Spring Boot+Socket實現與html頁面的長連線,客戶端給伺服器端發訊息,伺服器給客戶端輪詢傳送訊息,附案例原始碼Spring BootHTML客戶端伺服器原始碼
- 訊息佇列之事務訊息,RocketMQ 和 Kafka 是如何做的?佇列MQKafka
- 什麼是push通知欄訊息?
- 什麼是訊息佇列啊?佇列
- 企業微信hook,自定義工具,收發訊息Hook