基於公共信箱的全量訊息實現

架構師修行手冊發表於2023-04-27

來源:百度Geek說

作者 | 百度訊息中臺團隊

導讀 
introduction
息中臺為百度App以及廠內百度系產品提供即時通訊的能力,提供包括私聊、群聊、聊天室、直播彈幕等使用者溝通場景,並幫助業務透過訊息推送觸達使用者。百度App存在需要以『低使用者打擾』的形式觸達全量使用者的場景,而現有基於使用者『私有信箱』通知拆分的機制,很難低成本、高時效的滿足該場景訴求。基於上述問題,本文介紹了現有訊息系統的主要組成,對比多種實現方案的差異,提出以『公有信箱』通知讀擴散的方式,低成本、高時效的實現全量使用者通知推送。

全文5515字,預計閱讀時間14分鐘。



GEEK TALK

01

全量訊息提出背景

百度App存在需要觸達全量使用者的訴求,比如:2022年12月7日解除疫情管控結束後,將經過篩選的官方政策解讀、專題彙總、知識科普、實用工具類介紹等資訊,透過官方號『百度小助手』下發觸達到百度App使用者,來有效體現人文關懷,提高使用者粘性。

1.1 全量訊息訴求

在以訊息服務進行全量觸達(即全量訊息)時,期望能夠滿足:

基於公共信箱的全量訊息實現

在觸達範圍上,希望儘量擴大使用者觸達範圍,包括百度App月活使用者、以及非月活使用者但是近期新註冊或登入的使用者(根據2022年12月對外公開資料,百度App月活6億+使用者);在時效上,一次全量觸達,希望短時間內完成(比如小時級、甚至分鐘級),搶佔時效性;在使用者打擾方面,訊息觸達不能給使用者帶來較大的打擾,每次訊息下發,只觸達一次,不能重複打擾使用者,但是需要保留回訪入口,滿足使用者二次檢視的訴求。

1.2 現有技術痛點

我們現有IM(即時通訊)服務中,每個IM使用者對應一個使用者信箱。基於現有服務,如果想完成全量使用者的訊息觸達,需要把訊息推送到每個使用者的信箱。完成6億+的訊息寫入(假定每條佔用儲存4KB,每秒寫入2W條訊息),在訊息寫入時效性,以及儲存資源消耗上,都是很難接受的。且現有的基於使用者私有信箱的方案,在同時支援多條全量訊息的場景下,擴充套件性也較差。

基於上述背景和技術痛點,我們抽象基於公共信箱的全量訊息實現:在特定業務場景下透過訊息服務,低成本、高時效的給全量使用者推送內容一致的通知訊息。


GEEK TALK

02

現有訊息系統介紹

在介紹基於公共信箱(信箱的實現方式,該信箱為IM使用者公有)的全量訊息實現之前,先介紹一下目前訊息系統的現狀,包括訊息系統的組成、通知拉取模式、使用者信箱等。

2.1 訊息系統組成

普通用的直觀體驗上看,一個IM系統可以包括如下幾個元素:使用者主體、使用者賬號、賬號關係、聊天會話、聊天訊息。『使用者主體』具有『使用者賬號』,『使用者主體』具有頭像、暱稱等使用者屬性,『使用者主體』透過『使用者賬號』登入IM系統,進行聊天;賬號之間的關注、遮蔽、免打擾等構成『使用者關係』;透過使用者之間的互動環節可以產生『聊天訊息』;聊天記錄構成了一個『聊天會話』。

基於公共信箱的全量訊息實現

整合訊息服務的業務方角度看,一個IM系統可以包括訊息客戶端(訊息客戶端UI元件、訊息SDK)和訊息服務端。IM訊息可以作為一種服務,嵌入到各業務系統中,為業務系統提供『實時互動』能力。業務透過整合IM服務,提升其使用者體驗。如下為一個整合了IM SDK的業務架構圖。業務App整合IM SDK,透過IM SDK與IM Server互動,完成使用者上行通訊能力。業務App Server透過與IM Server互動,完成通知下行觸達使用者。

基於公共信箱的全量訊息實現

使用場景來看,訊息包括『私信訊息』(包括使用者上下行訊息)、『通知訊息』(業務方給使用者推送的下行訊息)、『群聊』、『聊天室』、『直播間彈幕』等。

2.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)訊息。

2.3 使用者信箱介紹

為了暫存尚未拉取到IM SDK本地的離線訊息,需要對訊息進行服務端儲存,而訊息的離線儲存透過訊息信箱服務完成。目前IM使用者訊息信箱主要包括使用者私有信箱、群公共信箱(非下文提到的使用者公共信箱)、直播間彈幕mcast等。使用者信箱透過『訊息所屬應用』+『IM標識使用者的唯一ID』來標識。就一條訊息而言,訊息參與者有『訊息傳送者』和『訊息接收者』,訊息收發雙方的信箱都是相互獨立的(假設傳送方刪除了自己信箱的某一條訊息,不會影響訊息接受者信箱的訊息)。對於有檢視歷史訊息訴求的一方來說,訊息需要入該方的信箱:比如使用者之間的私信(點對點聊天)訊息需要入傳送者和接收者的信箱,而對於全量通知場景,訊息不需要儲存傳送者信箱,而只需要存接收者的信箱。而使用者的信箱排序,是基於信箱Timeline,即訊息在信箱內部基於時間線儲存,每條訊息對應一個unix 微秒時間戳(如第一條訊息1679757323320865),使用者進行信箱拉取時,基於時間範圍正序或者逆序拉取,如下為信箱timeline的示例:

基於公共信箱的全量訊息實現

△信箱timeline

使用者信箱中的每一條訊息記錄都包含『訊息ID』、『訊息使用者標識』、『訊息通用屬性』、『訊息業務屬性』四個主要部分。訊息ID為unix微秒時間戳,不需要全域性唯一,只需要特定使用者信箱範圍內唯一即可。訊息使用者標識包括from_uid、to_uid、contacter。訊息通用屬性包括create_time、expire、is_read。訊息業務屬性包括category、type、priority、business_type、app_id、msgkey、content等。如下為一條訊息記錄示例:

基於公共信箱的全量訊息實現

△訊息記錄示例

GEEK TALK

03

全訊息實現

3.1 全量訊息推送方案分析

目前訊息推送機制中,主要支援:單播(訊息推送方式,每次給一個使用者推送一條訊息)、批次單播(每次給小範圍使用者推送訊息,比如30個)、廣播(基於關注關係的推送,如給全量粉絲推送),上述三種訊息推送機制推送的訊息,均需要儲存服務端的使用者私有信箱。為了完成百度App 6億+月活使用者(月活資料來源:2022年12月百度App公開月活資料,)的訊息推送,有幾種可選的方案。

3.1.1 全流程從通知入口推送

①該種方式下,需要獲取全量的月活使用者列表,經過IM Server推送入口,給每一個使用者推送疫情相關通知。該通知寫入到使用者信箱,若使用者線上,在實時拉取該通知;若使用者離線,再下次登入IM服務時,拉取離線通知。該種方案下,推送行為會覆蓋IM的全流程,推送的通知會進入每個月活使用者的私有信箱,服務壓力大。其中增量使用者不會收到通知推送(這裡增量使用者指的是不在月活使用者列表的使用者)。


3.1.2 跳過通知入口直接寫信箱

②跳過IM訊息推送流程中的中間環節,直接把通知訊息寫入使用者信箱。由於跳過了中間流程,直接寫入信箱,通知寫入速度主要取決於信箱底層儲存的壓力承受情況。該種方案下,同①方案一樣,無法給使用者傳送實時通知,依賴使用者IM SDK的主動訊息拉取(斷鏈後重新登入/新訊息提醒拉取),無法給增量使用者傳送通知。該方案由於跳過中間環節直接寫信箱,風險較大,無法直接提供給業務方使用,不建議如此操作。


3.1.3 公有信箱實現機制

③公有信箱機制,把通知訊息寫入『公共信箱』,在使用者訊息拉取時,合併『使用者私信信箱』+『公共信箱』的訊息。


3.1.4 三種方案比較

基於公共信箱的全量訊息實現

方案①②都是寫擴散方式,基於現有『使用者私有信箱』的機制,把通知訊息寫入每個接收通知的使用者私有信箱。方案②與方案①的差別主要是跳過了訊息中間流程,可以避免因為中間環節負載瓶頸導致整體訊息寫入速度過低。方案③是讀擴散方式,訊息不用再寫入接收通知的使用者私有信箱,而只需要在公共信箱儲存一份,在使用者拉取訊息時,實時拉取公共信箱的訊息。方案③中可以採用記憶體快取方案,解決對公共信箱的讀壓力。本質上來說,方案③與方案①②相比,是用讀成本(CPU)換寫成本(儲存)。

3.2 基於公有信箱的全量訊息實現

基於上述方案③的思路,我們進行基於公有信箱的全量訊息設計與實現。該種方案中,包含兩個主要流程:『全量訊息的管理』和『使用者私有+公有信箱的拉取』。


3.2.1 全量訊息的管理

全量訊息管理主要分為運營O端操作平臺(複用運營訊息平臺),以及全量訊息處理服務(複用IM服務的連線層、邏輯處理層、信箱代理、信箱處理)。運營O端平臺為運營同學提供視覺化介面,可以對全量訊息進行編輯、預釋出、釋出、修改、停止、撤回等操作;接入層對接運營O端,進行引數校驗、轉發IM後端邏輯處理模組;邏輯處理層進行全量訊息的建立、修改、停止、刪除、撤回等邏輯操作;信箱代理層複用IM服務的信箱CRUD操作;信箱儲存層公共信箱的底層儲存。

基於公共信箱的全量訊息實現

△全量訊息管理流程


3.2.1 使用者信箱拉取

使用者透過IM SDK,以長連線的方式,在邏輯處理層進行訊息拉拉取。在使用者拉取信箱訊息時,需要對『使用者個人信箱』和『公有信箱』進行合併。由於每次使用者信箱拉取,都需要進行信箱的合併拉取。

公共信箱記憶體快取機制

百度App的IM使用者,在IM SDK登入時需要拉取信箱中的訊息。每次訊息拉取時,需要檢查公共信箱中是否有訊息。因此,公共信箱需要能抗住日常和峰值流量(拉取峰值為4.7Wqps)。為了防止流量擊穿,流量打到底層的持久化公共信箱MYSQL儲存,我們設計了基於記憶體的公共信箱快取機制。同時公共信箱內容變化時,也要實時(或者在能容忍的範圍內做到準實時)變更記憶體快取信箱中的訊息,我們採用Bthread定期輪詢持久化公共信箱,更新記憶體公共信箱,輪詢間隔可配置(比如設定1秒)。

分級釋出機制

同時,在邏輯層實現白名單機制,支援全量訊息在『預釋出』狀態下,僅對白名單使用者可見,從而達到分級驗證的效果。白名單的使用者列表透過邏輯處理成的配置載入,也支援透過CURL請求動態修改白名單的配置。

基於公共信箱的全量訊息實現

3.3 基於公有信箱的全量訊息實現需要解決的問題

以公有信箱的方案實現全量訊息,需要解決如下問題:

基於公共信箱的全量訊息實現


GEEK TALK

04

全量訊息公共信箱實現的優缺點

以公共信箱的方式,實現全量訊息分發,具有:『分發速度快』、『資源成本低』的特點。

基於公共信箱的全量訊息實現

公共信箱的方式也存在一定的侷限性:

1、不適用於個性化要求高的場景:由於訊息在公共信箱只儲存一份,下發訊息內容固定,無法很大程度下,下發個性化訊息(當然也不是一定無法下發個性化的訊息,可以透過在公共信箱儲存訊息模板,根據拉取訊息的使用者ID獲取個性化資訊,在訊息拉取時,臨時拼裝訊息,這樣就增大了訊息拉取時的代價)。

2、不適用於實時訊息提醒場景

①從業務場景上看,全量訊息優先順序低,不需要在全量生效的瞬間讓使用者感知;

②從實現上看,全量訊息實時訊息提醒成本高(因為實時訊息提醒Notify,需要以類似單播的形式實時通知使用者。和單播的區別是,Notify不用觸達離線使用者,也就是不用寫使用者信箱,只需實時觸達線上使用者);

③從系統壓力看,全量線上使用者均收到實時新訊息提醒,會帶來信箱拉取請求的瞬時流量(手百IM SDK長連線峰值線上1550W,假定新訊息提醒在瞬間下發,同時線上使用者信箱拉取請求,會把db打掛的)。

GEEK TALK

05

全量訊息的應用

全量訊息目前已經在百度App得到應用,包括:重大通知的下發,百度App功能更新介紹通知,訊息的撤回,後續將推廣到其他的矩陣App的全量通知推送場景。

22年Q4宣佈疫情解封時,利用全量訊息推送,低成本、高時效的完成3條『疫情解封專項』全量訊息下發。

主題

有效期

到達

個人如何做好預防

12.09-12.13

2億+

陽了的應對措施

12.16-12.19

2億+

新冠闢謠&三年抗疫

12.23-12.26

2億+

備註:三次全量訊息下發,到達資料在2億+,該值小於月活的6億+,主要因為幾個原因:

①本次全量訊息有效期僅3天左右,全量訊息有效期內登入IM SDK的使用者才有機會拉到全量訊息;

②本次下發使用了新的訊息展示模板,所以限制了拉取全量訊息的百度App版本,只有高版本百度App可以拉到;

③本次全量訊息,限制了僅有百度App登入使用者拉取。


GEEK TALK

06

展望

前文介紹了現有訊息系統,透過公有信箱低成本、高分發速度完成全量訊息下發的設計、實現與應用。在全量訊息應用方面,除了業務上的使用,後續也可以用於廣播訊息、批次單播訊息的撤回。比如由於誤操作傳送了廣播訊息,使用者已經把廣播訊息拉到了端,並持久化到端,這是可以『以全量訊息的方式,下發刪除指令』,刪除已經快取到端的垃圾訊息。

希望,透過訊息系統持續不斷最佳化,為更多的業務提供低成本、高穩定性的即時通訊能力。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027824/viewspace-2949249/,如需轉載,請註明出處,否則將追究法律責任。

相關文章