本文內容由百度技術團隊分享,原題“基于公共信箱的全量消息實現”,為了幫助理解,有較多修訂、內容重組和重新排版。
1、引言
百度的IM消息中臺為百度APP以及廠內百度系產品提供即時通訊的能力,提供包括私聊、群聊、聊天室、直播彈幕等用戶溝通場景,并幫助業務通過消息推送觸達用戶。
如今,百度APP新增了一種需要以“低用戶打擾”的形式觸達全量用戶的場景需求,而現有的IM消息中臺主要是基于用戶“私有信箱”通知拆分的機制(通俗了說也就是IM里的“擴散寫”),所以如果不進行改造,是很難低成本、高時效的滿足該場景訴求。
基于上述問題,本文介紹了百度現有IM消息中臺系統的主要組成,并對比多種實現方案的優劣,以“公有信箱”通知讀擴散的技術方案對現有IM消息中臺系統進行改造,從而達成了低成本、高時效地實現全量用戶通知推送需求。
(本文已同步發布于:http://www.52im.net/thread-4235-1-1.html)
2、全量用戶消息推送需求背景
百度APP新增了需要通過IM實時通知觸達全量用戶的訴求,比如2022年12月7日解除疫情管控結束后,將經過篩選的官方政策解讀、專題匯總、知識科普、實用工具類介紹等信息,通過官方號“x度小助手”下發觸達到百度APP用戶,從而來有效體現人文關懷,提高用戶粘性。
在以IM消息服務進行全量用戶消息觸達時,需要滿足以下訴求:

具體就是:
- 1)在觸達范圍上:希望盡量擴大用戶觸達范圍,包括百度APP月活用戶、以及非月活用戶但是近期新注冊或登錄的用戶;
- 2)在時效上:一次全量觸達,希望短時間內完成(比如小時級、甚至分鐘級),搶占時效性;
- 3)在用戶打擾方面:消息觸達不能給用戶帶來較大的打擾,每次消息下發,只觸達一次,不能重復打擾用戶(但是需要保留回訪入口,滿足用戶二次查看的訴求)。
3、現有IM消息中臺的技術痛點
我們現有的IM(即時通訊)服務中,每個IM用戶對應一個用戶信箱。
基于現有的IM技術實現方案,如果想完成全量用戶的消息觸達,需要把消息推送到每個用戶的信箱(也就是IM中的擴散寫)。
這樣的話,要完成6億以上的消息寫入(假定每條占用存儲4KB,每秒寫入2W條消息),在消息寫入時效性以及存儲資源消耗上,都是很難接受的。
且現有的基于用戶私有信箱的方案,在同時支持多條全量用戶通知消息的場景下,擴展性也較差。
基于上述需求背景和技術痛點,我們本次的改造目的,就是要找到一種技術方案,從而在特定業務場景下通過改造后的消息服務,低成本、高時效的給全量用戶推送內容一致的消息通知。
4、現有IM消息中臺的主要技術實現
在討論改造方案前,我們有必要介紹一下目前IM消息系統的現狀,包括消息系統的組成、通知拉取模式、用戶信箱等。
4.1 消息系統組成
從普通用戶的直觀體驗上看,一個IM系統可以包括如下元素:
- 1)用戶主體;
- 2)用戶賬號;
- 3)賬號關系;
- 4)聊天會話;
- 5)聊天消息。
用自然語言串一下以上元素就是:
- 1)“用戶主體”具有“用戶賬號”;
- 2)“用戶主體”具有頭像、昵稱等用戶屬性;
- 3)“用戶主體”通過“用戶賬號”登錄IM系統,進行聊天;
- 4)“用戶賬號”之間的關注、屏蔽、免打擾等構成“用戶關系”;
- 5)通過用戶之間的互動環節可以產生“聊天消息”;
- 6)聊天記錄構成了一個“聊天會話”。
下面這張圖可能更直觀一些:
從集成消息服務的業務方角度看:
- 1)一個IM系統可以包括消息客戶端(消息客戶端UI組件、消息SDK)和消息服務端;
- 2)IM消息可以作為一種服務,嵌入到各業務系統中,為業務系統提供“實時交互”能力;
- 3)業務通過集成IM服務,提升其用戶體驗;
- 4)業務APP集成IM SDK,通過IM SDK與IM Server交互,完成用戶上行通訊能力;
- 5)業務APP Server通過與IM Server交互,完成通知下行觸達用戶。
下圖為一個集成了IM SDK的業務架構圖:
從使用場景來看,消息包括:
- 1)“私信消息”(包括用戶上下行消息);
- 2)“通知消息”(業務方給用戶推送的下行消息);
- 3)“群聊”、“聊天室”;
- 4)“直播間彈幕”等。
4.2 消息的通知拉取模式
百度的IM消息系統,采用通知拉取(notify-pull)模式來感知新消息、拉取新消息。
IM SDK登錄時,與IM 服務端建立長連接(LCS, Long Connect Service),用戶有新的消息時,通過長連接下發notify,實時通知用戶的IM SDK。
實時notify不寫用戶信箱,因為noitfy不是消息(可以理解為提醒在線用戶有新消息的信號),IM SDK根據這個信號,來服務端拉取消息。
業務方server或者其他用戶給該用戶發送消息后,經過IM業務處理模塊,把消息寫入接收者信箱,IM Server會根據用戶的登錄和路由信息,給消息接收者(私信場景下也包括“消息發送者”,用于消息的多端同步)發送新消息notify,接收到notify的IM設備,通過IM SDK來IM Server端拉取(pull)消息。
4.3 用戶信箱介紹
為了暫存尚未拉取到IM SDK本地的離線消息,需要對消息進行服務端存儲,而消息的離線存儲是通過消息信箱服務完成的。
目前百度的IM用戶消息信箱主要包括:
- 1)用戶私有信箱;
- 2)群公共信箱(非下文提到的用戶公共信箱);
- 3)直播間彈幕mcast等。
用戶信箱通過“消息所屬應用”+“IM標識用戶的唯一ID”來標識。
就一條消息而言:消息參與者有“消息發送者”和“消息接收者”,消息收發雙方的信箱都是相互獨立的(假設發送方刪除了自己信箱的某一條消息,不會影響消息接受者信箱的消息)。
對于有查看歷史消息訴求的一方來說:消息需要入該方的信箱,比如用戶之間的私信(也就是一對一單聊)消息需要入發送者和接收者的信箱。
而對于全量用戶消息通知的場景:消息不需要存儲發送者信箱,而只需要存接收者的信箱。而用戶的信箱排序,是基于信箱Timeline(詳見《現代IM系統中聊天消息的同步和存儲方案探討》)。即消息在信箱內部基于時間線存儲,每條消息對應一個unix 微秒時間戳(如第一條消息1679757323320865),用戶進行信箱拉取時,基于時間范圍正序或者逆序拉取。
如下為信箱Timeline的示例:
用戶信箱中的每一條消息記錄都包含四個主要部分:
- 1)“消息ID”;
- 2)“消息用戶標識”;
- 3)“消息通用屬性”;
- 4)“消息業務屬性”。
下面詳細介紹以上四個部分:
- 1)消息ID:為unix微秒時間戳,不需要全局唯一,只需要特定用戶信箱范圍內唯一即可;
- 2)消息用戶標識:包括from_uid、to_uid、contacter;
- 3)消息通用屬性:包括create_time、expire、is_read;
- 4)消息業務屬性:包括category、type、priority、business_type、APP_id、msgkey、content等。
如下為一條消息記錄示例:
5、全量用戶消息推送技術方案選型
5.1 需求分析
目前百度的IM消息推送機制中,主要支持:
- 1)單播:消息推送方式,每次給一個用戶推送一條消息;
- 2)批量單播:每次給小范圍用戶推送消息,比如30個;
- 3)廣播:基于關注關系的推送,如給全量粉絲推送。
上述三種消息推送機制推送的消息,均需要存儲服務端的用戶私有信箱。為了完成百度APP 6億以上全量月活用戶的消息推送,目前有三種可選的方案,接下來我們逐一分析。
5.2 方案1:全流程從通知入口推送
該種方式下:需要獲取全量的月活用戶列表,經過IM Server推送入口,給每一個用戶推送疫情相關通知。
該通知寫入到用戶信箱時:
- 1)若用戶在線,在實時拉取該通知;
- 2)若用戶離線,再下次登錄IM服務時,拉取離線通知。
該種方案下:推送行為會覆蓋IM的全流程,推送的通知會進入每個月活用戶的私有信箱,服務壓力大。其中增量用戶不會收到通知推送(這里增量用戶指的是不在月活用戶列表的用戶)。
5.3 方案2:跳過通知入口直接寫信箱
該種方式跳過IM消息推送流程中的中間環節,直接把通知消息寫入用戶信箱。
由于跳過了中間流程直接寫入信箱,通知寫入速度主要取決于信箱底層存儲的壓力承受情況。
該種方案下,同方案1一樣,無法給用戶發送實時通知,依賴用戶IM SDK的主動消息拉取(斷鏈后重新登錄/新消息提醒拉取),無法給增量用戶發送通知。
該方案由于跳過中間環節直接寫信箱,風險較大,無法直接提供給業務方使用,不建議如此操作。
5.4 方案3:公有信箱實現機制
該種公有信箱機制的邏輯是把通知消息寫入“公共信箱”。在用戶消息拉取時,合并“用戶私信信箱”+“公共信箱”的消息。
5.5 三種方案比較
方案1和2都是寫擴散方式,基于現有“用戶私有信箱”的機制,把通知消息寫入每個接收通知的用戶私有信箱。
方案2與方案1的差別主要是跳過了消息中間流程,可以避免因為中間環節負載瓶頸導致整體消息寫入速度過低。
方案3是讀擴散方式,消息不用再寫入接收通知的用戶私有信箱,而只需要在公共信箱存儲一份。在用戶拉取消息時,實時拉取公共信箱的消息。方案③中可以采用內存緩存方案,解決對公共信箱的讀壓力。
本質上來說:方案3與方案前兩種相比,是用讀成本(CPU)換寫成本(存儲)。
6、基于公有信箱技術方案的全量用戶消息推送實現
6.1 概述
基于上述方案3的思路,我們進行基于公有信箱的全量消息設計與實現。
該種方案中包含兩個主要流程:
- 1)全量消息的管理;
- 2)用戶私有+公有信箱的拉取。
6.2 全量消息的管理
全量消息管理主要分為:
- 1)運營O端操作平臺:復用運營消息平臺;
- 2)全量消息處理服務:復用IM服務的連接層、邏輯處理層、信箱代理、信箱處理。
運營O端平臺為運營同學提供可視化界面,可以對全量消息進行編輯、預發布、發布、修改、停止、撤回等操作。
具體就是:
- 1)接入層:對接運營O端,進行參數校驗、轉發IM后端邏輯處理模塊;
- 2)邏輯處理層:進行全量消息的創建、修改、停止、刪除、撤回等邏輯操作;
- 3)信箱代理層:復用IM服務的信箱CRUD操作;信箱存儲層公共信箱的底層存儲。
全量消息管理流程:
6.3 用戶信箱拉取
用戶通過IM SDK,以長連接的方式,在邏輯處理層進行消息拉拉取。
在用戶拉取信箱消息時,需要對“用戶個人信箱”和“公有信箱”進行合并。于是每次用戶信箱拉取,都需要進行信箱的合并拉取。
6.3.1)公共信箱內存緩存機制:
百度APP的IM用戶,在IM SDK登錄時需要拉取信箱中的消息。每次消息拉取時,需要檢查公共信箱中是否有消息。
因此,公共信箱需要能抗住日常和峰值流量(拉取峰值為4.7Wqps)。為了防止流量擊穿,流量打到底層的持久化公共信箱MYSQL存儲,我們設計了基于內存的公共信箱緩存機制。同時公共信箱內容變化時,也要實時(或者在能容忍的范圍內做到準實時)變更內存緩存信箱中的消息,我們采用Bthread定期輪詢持久化公共信箱,更新內存公共信箱,輪詢間隔可配置(比如設置1秒)。
6.3.2)分級發布機制:
同時,在邏輯層實現白名單機制,支持全量消息在“預發布”狀態下,僅對白名單用戶可見,從而達到分級驗證的效果。
白名單的用戶列表通過邏輯處理成的配置加載,也支持通過CURL請求動態修改白名單的配置。
7、基于公有信箱技術方案的技術挑戰
公有信箱的技術方案,需要解決如下問題:
8、基于公有信箱技術方案的優缺點總結
8.1 優點
以公共信箱的方式,實現全量用戶消息分發,具有:“分發速度快”、“資源成本低”的特點。
8.2 缺點
但公共信箱的方式也存在一定的局限性。
8.2.1)不適用于個性化要求高的場景:
由于消息在公共信箱只存儲一份,下發消息內容固定,無法很大程度下,下發個性化消息(當然也不是一定無法下發個性化的消息,可以通過在公共信箱存儲消息模板,根據拉取消息的用戶ID獲取個性化信息,在消息拉取時,臨時拼裝消息,這樣就增大了消息拉取時的代價)。
8.2.2)不適用于實時消息提醒場景:
1)從業務場景上看:全量消息優先級低,不需要在全量生效的瞬間讓用戶感知。
2)從實現上看:全量消息實時消息提醒成本高。因為實時消息提醒Notify,需要以類似單播的形式實時通知用戶。和單播的區別是,Notify不用觸達離線用戶,也就是不用寫用戶信箱,只需實時觸達在線用戶。
3)從系統壓力看:全量在線用戶均收到實時新消息提醒,會帶來信箱拉取請求的瞬時流量(手機百度IM SDK長連接峰值在線1550W,假定新消息提醒在瞬間下發,同時在線用戶信箱拉取請求,會把db打掛的)。
9、基于公有信箱技術方案的落地實施效果
全量消息目前已經在百度APP得到應用,包括:重大通知的下發;百度APP功能更新介紹通知;消息的撤回,后續還將推廣到其他的矩陣APP的全量通知推送場景。
舉個具體的例子:22年Q4宣布疫情解封時,利用全量消息推送,低成本、高時效的完成3條“疫情解封專項”全量消息下發。
在這個例子中,三次全量消息下發,到達數據在2億+(該值小于月活的6億+),主要因為幾個原因:
- 1)本次全量消息有效期僅3天左右,全量消息有效期內登錄IM SDK的用戶才有機會拉到全量消息;
- 2)本次下發使用了新的消息展示模板,所以限制了拉取全量消息的百度APP版本,只有高版本百度APP可以拉到;
- 3)本次全量消息,限制了僅有百度APP登錄用戶拉取。
10、未來展望
本文介紹了現有IM消息中臺系統,并通過公有信箱技術方案的改造,達成了低成本、高分發速度完成全量用戶消息下發的設計、實現與應用。
在全量用戶消息應用方面,除了業務上的使用,后續也可以用于廣播消息、批量單播消息的撤回。比如由于誤操作發送了廣播消息,用戶已經把廣播消息拉到了端,并持久化到端,這是可以“以全量消息的方式,下發刪除指令”,刪除已經緩存到端的垃圾消息。
我們希望,通過消息系統持續不斷優化,為更多的業務提供低成本、高穩定性的即時通訊能力。
11、相關資料
[1] 現代IM系統中聊天消息的同步和存儲方案探討
[2] 百度APP移動端網絡深度優化實踐分享(一):DNS優化篇
[3] 百度APP移動端網絡深度優化實踐分享(二):網絡連接優化篇
[4] 百度APP移動端網絡深度優化實踐分享(三):移動端弱網優化篇
[5] 百度直播的海量用戶實時消息系統架構演進實踐
[6] 深入了解百度開源的分布式RPC框架brpc的方方面面
[7] 百度網盤千萬節點的P2P架構設計(PPT)
[8] 零基礎IM開發入門(一):什么是IM系統?
[9] 一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)
[10] 一套原創分布式即時通訊(IM)系統理論架構方案
[11] 一套億級用戶的IM架構技術干貨(上篇):整體架構、服務拆分等
[12] 基于實踐:一套百萬消息量小規模IM系統技術要點總結
[13] 一套十萬級TPS的IM綜合消息系統的架構實踐與思考
[14] 從新手到專家:如何設計一套億級消息量的分布式IM系統
[15] 閑魚億級IM消息系統的架構演進之路
[16] 深度解密釘釘即時消息服務DTIM的技術設計
[17] 一套高可用、易伸縮、高并發的IM群聊、單聊架構方案設計實踐
[18] 企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等
(本文已同步發布于:http://www.52im.net/thread-4235-1-1.html)