狀態同步,究竟是推還是拉?
任何脫離業務的架構設計都是耍流氓。
狀態同步,有好友狀態的同步,有群友狀態的同步,有的需要實時同步,有的能夠容忍延時。結合具體場景來看下,狀態同步,究竟是推還是拉。
使用者的線上狀態,分為客戶端狀態(端),服務端狀態(雲)兩種形態。
什麼是服務端狀態?
服務端狀態,主要分為線上online和離線offline,不同的狀態,對於不同的業務處理流程可能不同。例如對於訊息的處理:
服務端狀態線上,直接投遞給使用者
服務端狀態離線,直接儲存離線訊息,等使用者下一次登入拉取
如何實時更新服務端狀態?
使用者uid-A登入時,會修改使用者的服務端狀態為線上。
使用者uid-A登出時,會修改使用者的服務端狀態為離線。
經常的,服務端會將使用者的服務端狀態儲存在高可用的快取叢集裡。
什麼是客戶端狀態?
不同的產品,會有不同的客戶端狀態,例如隱身、離線、忙碌、勿擾等,這些狀態大多是產品功能需求。有的產品,例如微信,在設計之初,就摒棄了使用者端狀態這個概念。
後文為了方便描述,不妨設待討論的是QQ這種擁有客戶端狀態的產品,並假設客戶端狀態也只有線上和離線兩種狀態,後文統一稱為“使用者狀態”。
如何獲取好友的狀態?
uid-A登入時,先去資料庫拉取自己的好友列表,再去快取獲取所有好友的狀態。
使用者uid-A的好友uid-B狀態改變時(由登入、登出等動作觸發),uid-A如何同步這一事件?
這裡就有推拉的設計折衷了。
如果對於狀態變更實時性要求不高,可以採用拉取
uid-A向伺服器輪詢拉取uid-B(其實是自己的全部好友)的狀態,例如每1分鐘一次,其缺點是:
(1)如果uid-B的狀態改變,uid-A獲取不實時,可能有1分鐘時延
(2)如果uid-B的狀態不改變,uid-A會有大量無效的輪詢請求,非常低效
如果對於狀態變更實時性要求較高,則必須推送
uid-B狀態改變時(由登入、登出等動作觸發),服務端不僅要在快取中修改uid-B的狀態,還要將這個狀體改變的通知推送給uid-B的線上好友。
推送的優勢是:實時
缺點是:當線上好友量很大時,任何一個使用者狀態的改變,會擴散成N個實時通知,這個N叫做“訊息風暴擴散係數”。假設一個IM系統平均每個使用者有200個好友,平均有20%的好友線上,那麼訊息風暴擴散係數N=40,這意味著,任何一個狀態的變化會變成40個推送請求。
群友狀態的一致性,和好友狀態的一致性相比,複雜在哪裡?可不可以採用實時推送?
群這個業務場景大夥也非常之熟悉,你能夠加入若干群(例如20個),假設平均每個群有200人,即你會有4000個群友。
理論上群友狀態也可以通過實時推送的方式實現,以保證實時性。進一步討論之前,先一起估算下這個業務場景下的“訊息風暴擴散係數”。
假設平均每個使用者加了20個群,平均每個群有200個使用者,依然假設20%的使用者線上,那麼為了保證群友狀態的實時性,每個使用者登入,就要將自己的狀態改變通知傳送給20*200*20%=800個群友,N=800,意味著,任何一個狀態的變化會變成800個推送請求。如果說好友狀態實時推送,訊息風暴擴散係數N=40尚可以接受,那麼群友狀態實時推送,N=800則是災難性的。此類業務往往採用輪詢拉取的方式,獲得群友的狀態。
輪詢拉取群友狀態也會給伺服器帶來過大的壓力,還有什麼優化方式?
群友的資料量太大,雖然每個使用者平均加入了20個群,但實際上並不會每次登入都進入每一個群。不採用輪詢拉取,而採用按需拉取,延時拉取的方式,在真正進入一個群時才實時拉取群友的線上狀態,是既能滿足使用者需求(使用者感覺是狀態是實時、一致的,但其實是進入群才拉取的),又能降低伺服器壓力。這是一種常見方法。
總結
狀態的實時性與一致性是一個較難解決的技術問題,不同的業務實現方式不同,一般來說:
好友狀態同步,是採用推送的方式同步
群友狀態同步,由於訊息風暴擴散係數過大,一般採用拉取的方式同步
群友狀態同步,還能採用按需拉取的優化方式,進一步降低服務端壓力
“訊息風暴擴散係數”是指一個訊息發出時,變成N個訊息的擴散係數,這個係數一定程度上決定了技術採用推送還是拉取
挖坑篇:《feed流,單聊群聊,系統通知,狀態同步,到底是推還是拉?》
填坑篇1:《系統通知,究竟是推還是拉?》
相關文章
- feed留,單聊群聊,系統通知,狀態同步,到底是推還是拉?
- 網頁端收訊息,究竟是推還是拉?網頁
- 快取,究竟是淘汰,還是修改?快取
- Metaverse究竟是泡沫還是未來?Metaverse
- 網路遊戲同步方式(幀同步和狀態同步)遊戲
- 爬蟲究竟是合法還是違法的?爬蟲
- Django是同步框架還是非同步框架Django框架非同步
- [ - Flutter 狀態篇 redux - ] StoreConnector還是StoreBuilder,讓distinct把好關FlutterReduxRebuild
- canvas 儲存與還原狀態Canvas
- vue父子元件狀態同步的最佳方式Vue元件
- Java執行緒狀態及同步鎖Java執行緒
- C# 同步 非同步 回撥 狀態機 async await DemoC#非同步AI
- steam雲狀態無法同步怎麼辦 steam雲狀態無法同步會有什麼影響
- 什麼是KYC?與加密究竟是水火不容,還是可以兼得?加密
- MongoDB原理:複製集狀態同步機制MongoDB
- Web3開發中的狀態同步Web
- mysql檢視主從同步狀態的方法MySql主從同步
- springboot:巢狀使用非同步註解@Async還會非同步執行嗎Spring Boot巢狀非同步
- Serverless 是一種思想狀態Server
- 最全的HTTP響應狀態碼列表:除了404,HTTP狀態碼還有啥?HTTP
- 線上雲養豬刷屏,究竟是薅羊毛還是割韭菜?
- 非同步API中事件、命令和狀態區別非同步API事件
- 基於 swoole 的 websocket 服務一:狀態同步Web
- 記錄--localStorage是同步還是非同步的?為什麼?非同步
- HTTP狀態程式碼是什麼?HTTP
- 理性談電競:究竟是舉步維艱還是進無止境?
- 參加IT程式設計培訓,究竟是選擇Python還是Java?程式設計PythonJava
- Vue非同步元件處理路由元件載入狀態Vue非同步元件路由
- 個人中心釋出狀態無法同步到QQ
- 基於 swoole 的 websocket 服務實現狀態同步Web
- Android面試題:bindService獲取代理是同步還是非同步Android面試題非同步
- 事件溯源:是來自事件的狀態與作為狀態的事件? - verraes事件
- 什麼是HTTP 304狀態程式碼?HTTP
- TCP為什麼是有狀態的?TCP
- React Fiber原始碼分析 第三篇(非同步狀態)React原始碼非同步
- 筆記: 判斷lib庫是動態庫還是靜態庫筆記
- 比特幣開年至今漲幅近43%!究竟是市場回春還是陷阱?比特幣
- 究竟是誰還在買GTA5?