現代IM系統中消息推送和存儲架構的實現

摘要:前言 IM全稱是『Instant Messaging』,中文名是即時通信。在這個高度信息化的移動互聯網時代,生活中IM類產品已經成爲必備品,比較有名的如釘釘、微信、QQ等以IM爲核心功能的產品。固然目前微信已經成長爲一個生態型產品,但其核心功能仍是IM。數據庫

前言

IM全稱是『Instant Messaging』,中文名是即時通信。在這個高度信息化的移動互聯網時代,生活中IM類產品已經成爲必備品,比較有名的如釘釘、微信、QQ等以IM爲核心功能的產品。固然目前微信已經成長爲一個生態型產品,但其核心功能仍是IM。還有一些非以IM系統爲核心的應用,最典型的如一些在線遊戲、社交應用,IM也是其重要的功能模塊。能夠說,帶有社交屬性的應用,IM功能必定是必不可少的。緩存

IM系統在互聯網初期即存在,其基礎技術架構在這十幾年的發展中更新迭代屢次,從早期的CS、P2P架構,到如今後臺已經演變爲一個複雜的分佈式系統,涉及移動端、網絡、安全和存儲等技術的方方面面。其支撐的規模也從早期的少許日活,到如今微信這個巨頭最新公佈的達到9億的日活的體量。安全

IM系統中最核心的部分是消息系統,消息系統中最核心的功能是消息的同步和存儲:微信

消息的同步:將消息完整的、快速的從發送方傳遞到接收方,就是消息的同步。消息同步系統最重要的衡量指標就是消息傳遞的實時性、完整性以及能支撐的消息規模。從功能上來講,通常至少要支持在線和離線推送,高級的IM系統還支持『多端同步』。網絡

消息的存儲:消息存儲即消息的持久化保存,這裏不是指消息在客戶端本地的保存,而是指雲端的保存,功能上對應的就是『消息漫遊』。『消息漫遊』的好處是能夠實現帳號在任意端登錄查看全部歷史消息,這也是高級IM系統特有的功能之一。架構

本篇文章內容主要涉及IM系統中的消息系統架構,會介紹一種基於TableStore構建的消息同步以及存儲系統的架構實現,可以支持消息系統中的高級特性『多端同步』以及『消息漫遊』。在性能和規模上,可以作到全量消息雲端存儲,百萬TPS以及毫秒級延遲的消息同步能力。併發

架構設計

本章主要會介紹基於TableStore的現代IM消息系統的架構設計,在詳細介紹架構設計以前,會先介紹一種Timeline邏輯模型,來抽象和簡化對IM消息同步和存儲模型的理解。理解了Timeline模型後,會介紹如何基於此模型對消息的同步以及存儲進行建模。基於Timeline模型,在實現消息同步和存儲時還會有各方面的技術權衡,例如如何對消息同步常見的讀擴散和寫擴散兩種模型進行對比和選擇,以及針對Timeline模型的特徵如何來選擇底層數據庫。less

傳統架構 vs 現代架構

上圖是消息系統傳統架構與現代架構的簡單對比。分佈式

傳統架構下,消息是先同步後存儲。對於在線的用戶,消息會直接實時同步到在線的接收方,消息同步成功後,並不會進行持久化。而對於離線的用戶或者消息沒法實時同步成功時,消息會持久化到離線庫,當接收方從新鏈接後,會從離線庫拉取全部未讀消息。當離線庫中的消息成功同步到接收方後,消息會從離線庫中刪除。傳統的消息系統,服務端的主要工做是維護髮送方和接收方的鏈接狀態,並提供在線消息同步和離線消息緩存的能力,保證消息必定可以從發送方傳遞到接收方。服務端不會對消息進行持久化,因此也沒法支持消息漫遊。函數

現代架構下,消息是先存儲後同步。先存儲後同步的好處是,若是接收方確認接收到了消息,那這條消息必定是已經在雲端保存了。而且消息會有兩個庫來保存,一個是消息存儲庫,用於全量保存全部會話的消息,主要用於支持消息漫遊。另外一個是消息同步庫,主要用於接收方的多端同步。消息從發送方發出後,通過服務端轉發,服務端會先將消息保存到消息存儲庫,後保存到消息同步庫。完成消息的持久化保存後,對於在線的接收方,會直接選擇在線推送。但在線推送並非一個必須路徑,只是一個更優的消息傳遞路徑。對於在線推送失敗或者離線的接收方,會有另一個統一的消息同步方式。接收方會主動的向服務端拉取全部未同步消息,但接收方什麼時候來同步以及會在哪些端來同步消息對服務端來講是未知的,因此要求服務端必須保存全部須要同步到接收方的消息,這是消息同步庫的主要做用。對於新的同步設備,會有消息漫遊的需求,這是消息存儲庫的主要做用,在消息存儲庫中,能夠拉取任意會話的全量歷史消息。

以上是傳統架構和現代架構的一個簡單的對比,現代架構上整個消息的同步和存儲流程,並無變複雜太多,可是其能實現多端同步以及消息漫遊。現代架構中最核心的就是兩個消息庫『消息同步庫』和『消息存儲庫』,是消息同步和存儲最核心的基礎。而本篇文章接下來的部分,都是圍繞這兩個庫的設計和實現來展開。

Timeline模型

在分析『消息同步庫』和『消息存儲庫』的設計和實現以前,在本章會先介紹一個邏輯模型-Timeline。Timeline模型會幫助咱們簡化對消息同步和存儲模型的理解,而消息庫的設計和實現也是圍繞Timeline的特性和需求來展開。

如圖是Timeline模型的一個抽象表述,Timeline能夠簡單理解爲是一個消息隊列,但這個消息隊列有以下特性:

每一個消息擁有一個順序ID(SeqId),在隊列後面的消息的SeqId必定比前面的消息的SeqId大,也就是保證SeqId必定是增加的,可是不要求嚴格遞增。

新的消息永遠在尾部添加,保證新的消息的SeqId永遠比已經存在隊列中的消息都大。

可根據SeqId隨機定位到具體的某條消息進行讀取,也能夠任意讀取某個給定範圍內的全部消息。

有了這些特性後,消息的同步能夠拿Timeline來很簡單的實現。圖中的例子中,消息發送方是A,消息接收方是B,同時B存在多個接收端,分別是B一、B2和B3。A向B發送消息,消息須要同步到B的多個端,待同步的消息經過一個Timeline來進行交換。A向B發送的全部消息,都會保存在這個Timeline中,B的每一個接收端都是獨立的從這個Timeline中拉取消息。每一個接收端同步完畢後,都會在本地記錄下最新同步到的消息的SeqId,即最新的一個位點,做爲下次消息同步的起始位點。服務端不會保存各個端的同步狀態,各個端都可以在任意時間從任意點開始拉取消息。

消息漫遊也是基於Timeline,和消息同步惟一的區別是,消息漫遊要求服務端可以對Timeline內的全部數據進行持久化。

基於Timeline,從邏輯模型上可以很簡單的理解在服務端如何去實現消息同步和存儲,並支持多端同步和消息漫遊這些高級功能。落地到實現的難點主要在如何將邏輯模型映射到物理模型,Timeline的實現對數據庫會有哪些要求?咱們應該選擇何種數據庫去實現?這些是接下來會討論到的問題。

消息存儲模型

如圖是基於Timeline的消息存儲模型,消息存儲要求每一個會話都對應一個獨立的Timeline。如圖例子所示,A與B/C/D/E/F均發生了會話,每一個會話對應一個獨立的Timeline,每一個Timeline內存有這個會話中的全部消息,服務端會對每一個Timeline進行持久化。服務端可以對全部會話Timeline中的全量消息進行持久化,也就擁有了消息漫遊的能力。

消息同步模型

消息同步模型會比消息存儲模型稍複雜一些,消息的同步通常有讀擴散和寫擴散兩種不一樣的方式,分別對應不一樣的Timeline物理模型。

如圖是讀擴散和寫擴散兩種不一樣同步模式下對應的不一樣的Timeline模型,按圖中的示例,A做爲消息接收者,其與B/C/D/E/F發生了會話,每一個會話中的新的消息都須要同步到A的某個端,看下讀擴散和寫擴散兩種模式下消息如何作同步。

讀擴散:消息存儲模型中,每一個會話的Timeline中保存了這個會話的全量消息。讀擴散的消息同步模式下,每一個會話中產生的新的消息,只須要寫一次到其用於存儲的Timeline中,接收端從這個Timeline中拉取新的消息。優勢是消息只須要寫一次,相比寫擴散的模式,可以大大下降消息寫入次數,特別是在羣消息這種場景下。但其缺點也比較明顯,接收端去同步消息的邏輯會相對複雜和低效。接收端須要對每一個會話都拉取一次才能獲取所有消息,讀被大大的放大,而且會產生不少無效的讀,由於並非每一個會話都會有新消息產生。

寫擴散:寫擴散的消息同步模式,須要有一個額外的Timeline來專門用於消息同步,一般是每一個接收端都會擁有一個獨立的同步Timeline,用於存放須要向這個接收端同步的全部消息。每一個會話中的消息,會產生屢次寫,除了寫入用於消息存儲的會話Timeline,還須要寫入須要同步到的接收端的同步Timeline。在我的與我的的會話中,消息會被額外寫兩次,除了寫入這個會話的存儲Timeline,還須要寫入參與這個會話的兩個接收者的同步Timeline。而在羣這個場景下,寫入會被更加的放大,若是這個羣擁有N個參與者,那每條消息都須要額外的寫N次。寫擴散同步模式的優勢是,在接收端消息同步邏輯會很是簡單,只須要從其同步Timeline中讀取一次便可,大大下降了消息同步所需的讀的壓力。其缺點就是消息寫入會被放大,特別是針對羣這種場景。

在IM這種應用場景下,一般會選擇寫擴散這種消息同步模式。IM場景下,一條消息只會產生一次,可是會被讀取屢次,是典型的讀多寫少的場景,消息的讀寫比例大概是10:1。若使用讀擴散同步模式,整個系統的讀寫比例會被放大到100:1。一個優化的好的系統,必須從設計上去平衡這種讀寫壓力,避免讀或寫任意一維觸碰到天花板。因此IM系統這類場景下,一般會應用寫擴散這種同步模式,來平衡讀和寫,將100:1的讀寫比例平衡到30:30。固然寫擴散這種同步模式,還須要處理一些極端場景,例如萬人大羣。針對這種極端寫擴散的場景,會退化到使用讀擴散。一個簡單的IM系統,一般會在產品層面限制這種大羣的存在,而對於一個高級的IM系統,會採用讀寫擴散混合的同步模式,來知足這類產品的需求。

消息庫設計

基於Timeline模型,以及Timeline模型在消息存儲和消息同步的應用,咱們看下消息同步庫和消息存儲庫的設計。

如圖是基於Timeline的消息庫設計。

消息同步庫:消息同步庫用於存儲全部用於消息同步的Timeline,每一個Timeline對應一個接收端,主要用做寫擴散模式的消息同步。這個庫不須要永久保留全部須要同步的消息,由於消息在同步到全部端後其生命週期就能夠結束,就能夠被回收。可是如前面所介紹的,一個實現簡單的多端同步消息系統,在服務端不會保存有全部端的同步狀態,而是依賴端本身主動來作同步。因此服務端不知道消息什麼時候能夠回收,一般的作法是爲這個庫裏的消息設定一個固定的生命週期,例如一週或者一個月,生命週期結束可被淘汰。

消息存儲庫:消息存儲庫用於存儲全部會話的Timeline,每一個Timeline包含了一個會話中的全部消息。這個庫主要用於消息漫遊時拉取某個會話的全部歷史消息,也用於讀擴散模式的消息同步。

消息同步庫和消息存儲庫,對數據庫有不一樣的要求,如何對數據庫作選型,在下面會討論。

數據庫選型

消息系統最核心的兩個庫是消息同步庫和消息存儲庫,兩個庫對數據庫有不一樣的要求:

總結下來,對數據庫的要求有以下幾點:

1. 表結構設計可以知足Timeline模型的功能要求:不要求關係模型,可以實現隊列模型,並可以支持生成自增的SeqId。

2. 可以支持高併發寫和範圍讀,規模在十萬級TPS。

3. 可以保存海量數據,百TB級。

4. 可以爲數據定義生命週期。

阿里雲表格存儲(TableStore)是基於LSM存儲引擎的分佈式NoSQL數據庫,支持百萬TPS高併發讀寫,PB級數據存儲,數據支持TTL,可以很好的知足以上需求,而且支持自增列,可以很是完美的設計和實現Timeline的物理模型。

架構實現

本章會以一段很是精簡的代碼,來展現如何基於TableStore實現Timeline模型,並基於Timeline模型進行消息存儲和推送。

這篇文章中給出的代碼,主要目的是爲了演示如何可以實現一個精簡Timeline的最基本功能。立刻咱們會推出一個完整的Timeline Library,來將基於Timeline進行消息存儲和推送的代碼的開發變得無比簡單。

全部示例代碼基於以下SDK版本:

表結構設計

以上是建立Timeline表的示例代碼,總共須要建立兩張表,一張表做爲消息同步庫,名稱爲『PushTable』,另外一張表做爲消息存儲庫,名稱爲『StoreTable』。

推送和存儲實現

以上是模擬一個羣內消息同步和存儲的示例代碼。羣名稱爲『TableStore(釘釘號:11789671)』,羣內成員有『A, B, C, D, E』。羣內新的消息,須要先存儲到羣的存儲Timeline(Timeline ID爲羣名稱),以後須要以寫擴散的模式推送到羣內每一個成員的同步Timeline(以羣成員名稱做爲Timeline ID)。

以上是拉取羣內歷史消息以及某個羣成員進行消息同步的示例代碼,主要邏輯在syncMessages函數內。示例代碼中,拉取消息都是從seq_id爲0開始,0爲TableStore自增列中最小值,因此表明了從最小的一個位點開始拉取消息,即拉取全量消息。

後記

這篇文章主要介紹了現代IM系統中消息推送和存儲架構的實現,基於邏輯的Timeline模型,咱們能夠很清晰明瞭的理解整個消息推送和存儲的架構。基於TableStore,能夠很是簡單的實現Timeline模型,其中自增列功能,完美的匹配了Timeline模型中所須要的最關鍵的SeqId自增。

TableStore(表格存儲)是阿里雲自主研發的專業級分佈式NoSQL數據庫,是基於共享存儲的高性能、低成本、易擴展、全託管的半結構化數據存儲平臺,支撐互聯網和物聯網數據的高效計算與分析。IM系統的消息推送和存儲場景,是TableStore在社交領域的重要應用之一。

基於Timeline的消息存儲和推送模型,將不光應用在IM消息系統中,還可應用在例如Feeds流、實時消息同步、直播彈幕等場景。在Feeds流場景下,咱們也有了比較深刻的研究,能夠參考《如何打造千萬級Feeds流系統》這篇文章。而在其餘更多的場景下,咱們將會有更多的深刻研究。

針對社交場景下對數據的數據高可靠以及服務高可用要求,咱們也一直在建設:

1. 《表格存儲如何實現高可靠和高可用

2. 《表格存儲如何實現跨區域的容災

同時在新的Serverless架構下,咱們也一直在嘗試:

1. 《以物流案例看基於表格存儲實時數據流的serverless計算

除了社交領域,在物聯網車聯網領域,表格存儲也在發揮它強大的分佈式數據庫能力:

1. 《如何高效存儲海量GPS數據

2. 《超級快遞——如何用系統來保證快遞準時送達

相關文章
相關標籤/搜索