IM序列4:IM單聊和群聊中的在線狀態同步應該用「推」還是「拉」?
1、前言
「用戶在線狀態的一致性」(單聊好友在線狀態、群聊用戶在線狀態)是IM應用領域比較難解決的一個技術問題,如何精準實時的獲得好友、群友的在線狀態,是今天將要探討的話題。
2、IM開發乾貨系列文章
《IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞》
《IM消息送達保證機制實現(二):保證離線消息的可靠投遞》
《如何保證IM實時消息的「時序性」與「一致性」?》
《IM單聊和群聊中的在線狀態同步應該用「推」還是「拉」?》(本文)
《IM群聊消息如此複雜,如何保證不丟不重?》
《一種Android端IM智能心跳演算法的設計與實現探討(含樣例代碼)》
《移動端IM登錄時拉取數據如何作到省流量?》
《通俗易懂:基於集群的移動端IM接入層負載均衡方案分享》
《淺談移動端IM的多點登陸和消息漫遊原理》
本系列由公號「編碼前線」整理。
3、保持單聊好友狀態的一致性
1場景一:用戶uid-A登錄時,如何獲取自己全部好友的在線狀態?
一個典型的IM大致的處理邏輯是這樣的:
1)伺服器要存儲所有用戶的在線狀態(往往存儲在保證高可用的緩存集群里) -> 保證狀態可查,流程見下圖:
2)用戶狀態實時變更,任何用戶登錄時,需要將服務端自己的在線狀態置為online;任何用戶登出時,需要將服務端自己的狀態置為offline -> 保證服務端狀態存儲的一致性與實時性,流程見下圖:
3)uid-A登錄時,先去資料庫拉取自己的好友列表,再去緩存獲取所有好友的在線狀態 -> 保證登錄時好友狀態獲取的一致性與實時性,流程見下圖:
2場景二:用戶uid-A的好友uid-B狀態改變時(由登錄、登出、隱身等動作觸發),uid-A如何知道這一事件?
? 方案一的邏輯:
uid-A向伺服器輪詢拉取uid-B(其實是自己的全部好友)的狀態,例如每1分鐘一次。
方案一的缺點:
如果uid-B的狀態改變,uid-A獲取不實時,可能有1分鐘時延;
如果uid-B的狀態不改變,uid-A會有大量無效的輪詢請求,佔用伺服器資源。
? 方案二的邏輯:
uid-B狀態改變時(由登錄、登出、隱身等動作觸發),伺服器不僅在緩存中修改uid-B的狀態,還要將這個狀體改變的通知推送給uid-B的在線反向好友(反向好友是指:加了uid-B為好友的人,而不是uid-B的好友,這個細節要注意)。
方案二的優點:實時。
方案二的缺點:當在線好友量很大時,任何一個用戶狀態的改變,會擴散成N個實時通知,這個N叫做「消息風暴擴散係數」。
設一個im系統平均每個用戶有200個反向好友,平均有20%的反向好友在線,那麼消息風暴擴散係數N=40,這意味著,任何一個狀態的變化會變成40個推送請求。
4、保持群聊友狀態的一致性
1場景一:群友狀態一致性有什麼不同,和好友狀態一致性相比複雜在哪裡?為什麼不能採用實時推送?
理論上群友狀態也可以通過實時推送的方式實現,以保證實時性。但實際上,群友狀態一般都是採用拉取的方式獲得,因為群友狀態「消息風暴擴散係數」N實在太大,全部實時獲取系統往往承受不了。
假設平均每個用戶加了20個群,平均每個群有200個用戶,依然假設20%的用戶在線,那麼為了保證群友狀態的實時性,每個用戶登錄,就要將自己的狀態改變通知發送給20*200*20%=800個群友,N=800,意味著,任何一個狀態的變化會變成800個推送請求。
XXX系統使用的是群友狀態推送,不存在的這樣的問題?那很可能是,XXX系統的用戶量和活躍度還不夠高吧。
2場景二:輪詢拉取群友狀態也會給伺服器帶來過大的壓力,還有什麼優化方式?
群友的數據量太大,雖然每個用戶平均加入了20個群,但實際上並不會每次登錄都進入每一個群。不採用輪詢拉取,而採用按需拉取,延時拉取的方式,在真正進入一個群時才實時拉取群友的在線狀態,是既能滿足用戶需求(用戶感覺是狀態是實時、一致的,但其實是進入群才拉取的),又能降低伺服器壓力。這是一種常見方法。
總結與建議
IM應用中在線狀態的實時性與一致性是一個較難解決的技術問題,不同的業務接受度,不同的數據量並發量在線量,實現方式不同。
個人建議的方式是:
好友狀態,如果對實時性要求較高,可以採用推送的方式同步;如果實時性要求不高,可以採用輪詢拉取的方式同步;
群友的狀態,由於消息風暴擴散係數過大,可以採用按需拉取,延時拉取的方式同步;
系統消息/開屏廣告等對實時性要求不高的業務,可以採用拉取的方式獲取消息;
「消息風暴擴散係數」是指一個消息發出時,變成N個消息的擴散係數,這個係數與業務及數據相關,一定程度上它的大小決定了技術採用推送還是拉取。
推薦閱讀:
※科技發展對音樂的影響是什麼?
※Medium上值得關注的12個人工智慧領域科技作者
※肯德基、優衣庫、蘇寧……2017這麼玩紅包營銷
※你知道馬雲唱電影主題曲《風清揚》了,卻不知道他是喝了酒唱的!
※鉚接(riveted)、螺栓連接(bolted)和焊接(welded)各有什麼優劣?