1. 程式人生 > 其它 >im即時通訊開發:群訊息推送如何保證實時性

im即時通訊開發:群訊息推送如何保證實時性

眾所周之,群聊是移動端IM的服務端技術難點所在,難在哪?大量的群聊訊息,是一條條推給群內成員還是可以使用什麼樣的優化策略?試想一個2000人大群,一條訊息的發出,如果瞬間被擴散寫成2000條一對一訊息的投遞,對於接收方而言不過是一條訊息而已,而服務端是以對相對比單聊訊息的2000倍處理壓力後的結果。那麼服務端在保證訊息投遞的同時,面對這麼大的壓力該如何解決好效率問題?解決不好效率問題那實時性就不能保證!

當然,實際在生產環境下,群訊息的傳送都會想盡辦法進行壓縮,並開展各種改善效能的處理辦法,而不是像上述舉例裡的直接擴散寫(即2000人群裡,一條訊息被簡單地複製為2000條一對一的訊息投遞)。

先大致分析一下問題產生的原因。

1)訊息量瞬間大增:

搶紅包時大家都比較活躍,不停在群裡發訊息,尤其群成員比較多的群(500人),每條訊息都會給服務端帶來大量的計算工作。

2)後臺邏輯不夠優化:

比如紅包訊息沒有單獨的通道,時效性會收到其他訊息影響、沒有采用批處理方式、非同步處理有些環節還不到位等等。

精確定位問題的原因

我們嘗試精確定位問題的根本原因,原因分析如下。

1)c2g模組沒有采取批處理方式:

1條群(500人群)訊息到達c2g模組後,c2g模組為每個人寫收件箱(這裡時間延遲較大,優化點),然後在把這條訊息變成500條投遞訊息(需要批處理,就給Kafka放入一條訊息),通過Kafka送給Deliver節點投遞。即時通訊開發

2)Deliver模組的處理沒有批量合併:

Deliver模組會到Redis中逐條(500條)檢索接收訊息使用者的線上狀態(這個點需要批處理,根據使用者Id分佈,一次檢索若干使用者的線上狀態),線上的投遞訊息(批處理),離線的傳送第三方push(批處理)。

3)離線推送流程不優化:

整體流程上,每條訊息是先寫了離線收件箱,再推送。這樣效率也不高,需要對這個流程細化以及非同步化。

總結一下就是:

微信在這塊的一個重要優化思想是批處理,做法是單次批量操作(我們本次優化目標)裸寫,多條訊息的聚合(MapReduce過程)下沉到了MQ中介軟體中。

群聊紅包邏輯單獨部署

現階段,當訊息(尤其是大群訊息)量大的時候,Deliver節點會成為瓶頸。紅包對時效性要求很高,架構上採用獨立為紅包部署Deliver節點的方式確保紅包訊息走單獨通道進行推送。即使其他訊息出現延遲,紅包訊息依然能保證即使送達。

裸寫批處理邏輯、

處理一條群訊息,服務端要進行大量的工作,需要查詢所有群成員的路由表、線上狀態,線上人員需要推送及時訊息,離線人員需要推送第三方push(比如iOS的apns推送通道)。這些工作逐條執行,效能會非常差,如果遇到大群,系統會不可用。

批處理可以較好解決這個問題。比如使用者狀態及路由表資料,採用hash演算法分佈在幾臺伺服器上。收到群訊息後,根據群成員,計算出使用者狀態及路由表資料的分佈情況,從快取伺服器中一次檢索出該伺服器可能存在的所有群成員狀態及路由資訊。這樣可以極大減少RPC呼叫次數,及計算量。

推送操作也類似,批量向接入層投遞訊息即可。

離線訊息非同步寫收件箱

在處理大群訊息推送時,寫離線訊息也是一個非常影響效能的地方。現有的邏輯是先為每個人寫一條離線訊息,再執行推送。

1)Deliver節點收到一條群訊息,檢索使用者線上狀態及路由資訊,使用者線上(離線的邏輯相對簡單,略過);

2)批量推送訊息(2、批處理邏輯);

3)非同步將訊息寫入訊息匯流排,同時寫入第三方push的延遲推送任務;

4)非同步寫離線訊息(不影響線上使用者收到訊息的速度);

5)第(2)步推送訊息的ack資訊回到服務端;

6)c2g模組將ack資訊放入訊息匯流排。(確保訊息時序性,ack需要在寫離線訊息之後處理,否則可能出現訊息重複);

7)刪除對應的離線訊息;

8)第(3)步寫入的延遲推送任務,在規定時間(如10秒)後生效,判斷是否存在此條離線訊息(如果ack回來了,離線訊息會被刪掉),如果離線訊息還存在,傳送第三方push。

通過以上3個方面的優化,能夠確保在併發訊息量較大時,推送訊息依然及時。