消息已读未读的模型设计_阿里云技术专家分享:现代 IM 系统中消息推送和存储架构的实现...
前言
IM 全稱是“Instant Messaging”,中文名是即時通訊。在這個高度信息化的移動互聯(lián)網(wǎng)時代,生活中 IM 類產(chǎn)品已經(jīng)成為必備品,比較有名的如釘釘、微信、QQ 等以 IM 為核心功能的產(chǎn)品。當然目前微信已經(jīng)成長為一個生態(tài)型產(chǎn)品,但其核心功能還是 IM。還有一些非以 IM 系統(tǒng)為核心的應用,最典型的如一些在線游戲、社交應用,IM 也是其重要的功能模塊。可以說,帶有社交屬性的應用,IM 功能一定是必不可少的。
IM 系統(tǒng)在互聯(lián)網(wǎng)初期即存在,其基礎技術(shù)架構(gòu)在這十幾年的發(fā)展中更新迭代多次,從早期的 CS、P2P 架構(gòu),到現(xiàn)在后臺已經(jīng)演變?yōu)橐粋€復雜的分布式系統(tǒng),涉及移動端、網(wǎng)絡、安全和存儲等技術(shù)的方方面面。其支撐的規(guī)模也從早期的少量日活,到現(xiàn)在微信這個巨頭最新公布的達到 9 億日活的體量。
IM 系統(tǒng)中最核心的部分是消息系統(tǒng),消息系統(tǒng)中最核心的功能是消息的同步和存儲:
消息的同步:將消息完整、快速地從發(fā)送方傳遞到接收方,就是消息的同步。消息同步系統(tǒng)最重要的衡量指標就是消息傳遞的實時性、完整性以及能支撐的消息規(guī)模。從功能上來說,一般至少要支持在線和離線推送,高級的 IM 系統(tǒng)還支持“多端同步”。
消息的存儲:消息存儲即消息的持久化保存,這里不是指消息在客戶端本地的保存,而是指云端的保存,功能上對應的就是“消息漫游”。“消息漫游”的好處是可以實現(xiàn)賬號在任意端登陸查看所有歷史消息,這也是高級 IM 系統(tǒng)特有的功能之一。
本文內(nèi)容主要涉及 IM 系統(tǒng)中的消息系統(tǒng)架構(gòu),會介紹一種基于 TableStore 構(gòu)建的消息同步以及存儲系統(tǒng)的架構(gòu)實現(xiàn),能夠支持消息系統(tǒng)中的高級特性“多端同步”以及“消息漫游”。在性能和規(guī)模上,能夠做到全量消息云端存儲,百萬 TPS 以及毫秒級延遲的消息同步能力。
架構(gòu)設計
本章主要會介紹基于 TableStore 的現(xiàn)代 IM 消息系統(tǒng)的架構(gòu)設計,在詳細介紹架構(gòu)設計之前,會先介紹一種 Timeline 邏輯模型,來抽象和簡化對 IM 消息同步和存儲模型的理解。理解了 Timeline 模型后,會介紹如何基于此模型對消息的同步以及存儲進行建模。基于 Timeline 模型,在實現(xiàn)消息同步和存儲時還會有各方面的技術(shù)權(quán)衡,例如如何對消息同步常見的讀擴散和寫擴散兩種模型進行對比和選擇,以及針對 Timeline 模型的特征如何來選擇底層數(shù)據(jù)庫。
傳統(tǒng)架構(gòu) vs 現(xiàn)代架構(gòu)
上圖是消息系統(tǒng)傳統(tǒng)架構(gòu)與現(xiàn)代架構(gòu)的簡單對比。
傳統(tǒng)架構(gòu)下,消息是先同步后存儲。對于在線的用戶,消息會直接實時同步到在線的接收方,消息同步成功后,并不會進行持久化。而對于離線的用戶或者消息無法實時同步成功時,消息會持久化到離線庫,當接收方重新連接后,會從離線庫拉取所有未讀消息。當離線庫中的消息成功同步到接收方后,消息會從離線庫中刪除。傳統(tǒng)的消息系統(tǒng),服務端的主要工作是維護發(fā)送方和接收方的連接狀態(tài),并提供在線消息同步和離線消息緩存的能力,保證消息一定能夠從發(fā)送方傳遞到接收方。服務端不會對消息進行持久化,所以也無法支持消息漫游。
現(xiàn)代架構(gòu)下,消息是先存儲后同步。先存儲后同步的好處是,如果接收方確認接收到了消息,那這條消息一定是已經(jīng)在云端保存了。并且消息會有兩個庫來保存,一個是消息存儲庫,用于全量保存所有會話的消息,主要用于支持消息漫游。另一個是消息同步庫,主要用于接收方的多端同步。消息從發(fā)送方發(fā)出后,經(jīng)過服務端轉(zhuǎn)發(fā),服務端會先將消息保存到消息存儲庫,后保存到消息同步庫。完成消息的持久化保存后,對于在線的接收方,會直接選擇在線推送。但在線推送并不是一個必須路徑,只是一個更優(yōu)的消息傳遞路徑。對于在線推送失敗或者離線的接收方,會有另外一個統(tǒng)一的消息同步方式。接收方會主動的向服務端拉取所有未同步消息,但接收方何時來同步以及會在哪些端來同步消息對服務端來說是未知的,所以要求服務端必須保存所有需要同步到接收方的消息,這是消息同步庫的主要作用。對于新的同步設備,會有消息漫游的需求,這是消息存儲庫的主要作用,在消息存儲庫中,可以拉取任意會話的全量歷史消息。
以上是傳統(tǒng)架構(gòu)和現(xiàn)代架構(gòu)的一個簡單的對比,現(xiàn)代架構(gòu)上整個消息的同步和存儲流程,并沒有變復雜太多,但是其能實現(xiàn)多端同步以及消息漫游。現(xiàn)代架構(gòu)中最核心的就是兩個消息庫“消息同步庫”和“消息存儲庫”,是消息同步和存儲最核心的基礎。而本文接下來的部分,都是圍繞這兩個庫的設計和實現(xiàn)來展開。
Timeline 模型
在分析“消息同步庫”和“消息存儲庫”的設計和實現(xiàn)之前,在本章會先介紹一個邏輯模型——Timeline。Timeline 模型會幫助我們簡化對消息同步和存儲模型的理解,而消息庫的設計和實現(xiàn)也是圍繞 Timeline 的特性和需求來展開。
如圖是 Timeline 模型的一個抽象表述,Timeline 可以簡單理解為是一個消息隊列,但這個消息隊列有如下特性:
每個消息擁有一個順序 ID(SeqId),在隊列后面的消息的 SeqId 一定比前面的消息的 SeqId 大,也就是保證 SeqId 一定是增長的,但是不要求嚴格遞增。
新的消息永遠在尾部添加,保證新的消息的 SeqId 永遠比已經(jīng)存在隊列中的消息都大。
可根據(jù) SeqId 隨機定位到具體的某條消息進行讀取,也可以任意讀取某個給定范圍內(nèi)的所有消息。
有了這些特性后,消息的同步可以拿 Timeline 來很簡單的實現(xiàn)。圖中的例子中,消息發(fā)送方是 A,消息接收方是 B,同時 B 存在多個接收端,分別是 B1、B2 和 B3。A 向 B 發(fā)送消息,消息需要同步到 B 的多個端,待同步的消息通過一個 Timeline 來進行交換。A 向 B 發(fā)送的所有消息,都會保存在這個 Timeline 中,B 的每個接收端都是獨立的從這個 Timeline 中拉取消息。每個接收端同步完畢后,都會在本地記錄下最新同步到的消息的 SeqId,即最新的一個位點,作為下次消息同步的起始位點。服務端不會保存各個端的同步狀態(tài),各個端均可以在任意時間從任意點開始拉取消息。
消息漫游也是基于 Timeline,和消息同步唯一的區(qū)別是,消息漫游要求服務端能夠?qū)?Timeline 內(nèi)的所有數(shù)據(jù)進行持久化。
基于 Timeline,從邏輯模型上能夠很簡單的理解在服務端如何去實現(xiàn)消息同步和存儲,并支持多端同步和消息漫游這些高級功能。落地到實現(xiàn)的難點主要在如何將邏輯模型映射到物理模型,Timeline 的實現(xiàn)對數(shù)據(jù)庫會有哪些要求?我們應該選擇何種數(shù)據(jù)庫去實現(xiàn)?這些是接下來會討論到的問題。
消息存儲模型
如圖是基于Timeline的消息存儲模型,消息存儲要求每個會話都對應一個獨立的 Timeline。如圖例子所示,A 與 B/C/D/E/F 均發(fā)生了會話,每個會話對應一個獨立的 Timeline,每個 Timeline 內(nèi)存有這個會話中的所有消息,服務端會對每個 Timeline 進行持久化。服務端能夠?qū)λ袝?Timeline 中的全量消息進行持久化,也就擁有了消息漫游的能力。
消息同步模型
消息同步模型會比消息存儲模型稍復雜一些,消息的同步一般有讀擴散和寫擴散兩種不同的方式,分別對應不同的 Timeline 物理模型。
如圖是讀擴散和寫擴散兩種不同同步模式下對應的不同的 Timeline 模型,按圖中的示例,A 作為消息接收者,其與 B/C/D/E/F 發(fā)生了會話,每個會話中的新的消息都需要同步到 A 的某個端,看下讀擴散和寫擴散兩種模式下消息如何做同步。
讀擴散:消息存儲模型中,每個會話的 Timeline 中保存了這個會話的全量消息。讀擴散的消息同步模式下,每個會話中產(chǎn)生的新的消息,只需要寫一次到其用于存儲的 Timeline 中,接收端從這個 Timeline 中拉取新的消息。優(yōu)點是消息只需要寫一次,相比寫擴散的模式,能夠大大降低消息寫入次數(shù),特別是在群消息這種場景下。但其缺點也比較明顯,接收端去同步消息的邏輯會相對復雜和低效。接收端需要對每個會話都拉取一次才能獲取全部消息,讀被大大的放大,并且會產(chǎn)生很多無效的讀,因為并不是每個會話都會有新消息產(chǎn)生。
寫擴散:寫擴散的消息同步模式,需要有一個額外的 Timeline 來專門用于消息同步,通常是每個接收端都會擁有一個獨立的同步 Timeline,用于存放需要向這個接收端同步的所有消息。每個會話中的消息,會產(chǎn)生多次寫,除了寫入用于消息存儲的會話 Timeline,還需要寫入需要同步到的接收端的同步 Timeline。在個人與個人的會話中,消息會被額外寫兩次,除了寫入這個會話的存儲 Timeline,還需要寫入?yún)⑴c這個會話的兩個接收者的同步 Timeline。而在群這個場景下,寫入會被更加的放大,如果這個群擁有 N 個參與者,那每條消息都需要額外的寫 N 次。寫擴散同步模式的優(yōu)點是,在接收端消息同步邏輯會非常簡單,只需要從其同步 Timeline 中讀取一次即可,大大降低了消息同步所需的讀的壓力。其缺點就是消息寫入會被放大,特別是針對群這種場景。
在 IM 這種應用場景下,通常會選擇寫擴散這種消息同步模式。IM 場景下,一條消息只會產(chǎn)生一次,但是會被讀取多次,是典型的讀多寫少的場景,消息的讀寫比例大概是 10:1。若使用讀擴散同步模式,整個系統(tǒng)的讀寫比例會被放大到 100:1。一個優(yōu)化的好的系統(tǒng),必須從設計上去平衡這種讀寫壓力,避免讀或?qū)懭我庖痪S觸碰到天花板。所以 IM 系統(tǒng)這類場景下,通常會應用寫擴散這種同步模式,來平衡讀和寫,將 100:1 的讀寫比例平衡到 30:30。當然寫擴散這種同步模式,還需要處理一些極端場景,例如萬人大群。針對這種極端寫擴散的場景,會退化到使用讀擴散。一個簡單的 IM 系統(tǒng),通常會在產(chǎn)品層面限制這種大群的存在,而對于一個高級的 IM 系統(tǒng),會采用讀寫擴散混合的同步模式,來滿足這類產(chǎn)品的需求。
消息庫設計
基于 Timeline 模型,以及 Timeline 模型在消息存儲和消息同步的應用,我們看下消息同步庫和消息存儲庫的設計。
如圖是基于 Timeline 的消息庫設計。
消息同步庫:消息同步庫用于存儲所有用于消息同步的 Timeline,每個 Timeline 對應一個接收端,主要用作寫擴散模式的消息同步。這個庫不需要永久保留所有需要同步的消息,因為消息在同步到所有端后其生命周期就可以結(jié)束,就可以被回收。但是如前面所介紹的,一個實現(xiàn)簡單的多端同步消息系統(tǒng),在服務端不會保存有所有端的同步狀態(tài),而是依賴端自己主動來做同步。所以服務端不知道消息何時可以回收,通常的做法是為這個庫里的消息設定一個固定的生命周期,例如一周或者一個月,生命周期結(jié)束可被淘汰。
消息存儲庫:消息存儲庫用于存儲所有會話的 Timeline,每個 Timeline 包含了一個會話中的所有消息。這個庫主要用于消息漫游時拉取某個會話的所有歷史消息,也用于讀擴散模式的消息同步。
消息同步庫和消息存儲庫,對數(shù)據(jù)庫有不同的要求,如何對數(shù)據(jù)庫做選型,在下面會討論。
數(shù)據(jù)庫選型
消息系統(tǒng)最核心的兩個庫是消息同步庫和消息存儲庫,兩個庫對數(shù)據(jù)庫有不同的要求:
總結(jié)下來,對數(shù)據(jù)庫的要求有如下幾點:
1. 表結(jié)構(gòu)設計能夠滿足 Timeline 模型的功能要求:不要求關系模型,能夠?qū)崿F(xiàn)隊列模型,并能夠支持生成自增的 SeqId。
2. 能夠支持高并發(fā)寫和范圍讀,規(guī)模在十萬級 TPS。
3. 能夠保存海量數(shù)據(jù),百 TB 級。
4. 能夠為數(shù)據(jù)定義生命周期。
阿里云表格存儲(TableStore)是基于 LSM 存儲引擎的分布式 NoSQL 數(shù)據(jù)庫,支持百萬 TPS 高并發(fā)讀寫,PB 級數(shù)據(jù)存儲,數(shù)據(jù)支持 TTL,能夠很好的滿足以上需求,并且支持自增列,能夠非常完美的設計和實現(xiàn) Timeline 的物理模型。
架構(gòu)實現(xiàn)
本章會以一段非常精簡的代碼,來展示如何基于 TableStore 實現(xiàn) Timeline 模型,并基于 Timeline 模型進行消息存儲和推送。本文中給出的代碼,主要目的是為了演示如何能夠?qū)崿F(xiàn)一個精簡 Timeline 的最基本功能。馬上我們會推出一個完整的 Timeline Library,來將基于 Timeline 進行消息存儲和推送的代碼的開發(fā)變得無比簡單。
所有示例代碼基于如下 SDK 版本:
表結(jié)構(gòu)設計
以上是創(chuàng)建 Timeline 表的示例代碼,總共需要創(chuàng)建兩張表,一張表作為消息同步庫,名稱為“PushTable”,另一張表作為消息存儲庫,名稱為“StoreTable”。推送和存儲實現(xiàn)
以上是模擬一個群內(nèi)消息同步和存儲的示例代碼。群名稱為『TableStore(釘釘號:11789671)』,群內(nèi)成員有『A, B, C, D, E』。群內(nèi)新的消息,需要先存儲到群的存儲 Timeline(Timeline ID 為群名稱),之后需要以寫擴散的模式推送到群內(nèi)每個成員的同步 Timeline(以群成員名稱作為 Timeline ID)。
以上是拉取群內(nèi)歷史消息以及某個群成員進行消息同步的示例代碼,主要邏輯在 syncMessages 函數(shù)內(nèi)。示例代碼中,拉取消息都是從 seq_id 為 0 開始,0 為 TableStore 自增列中最小值,所以代表了從最小的一個位點開始拉取消息,即拉取全量消息。
后記
這篇文章主要介紹了現(xiàn)代IM系統(tǒng)中消息推送和存儲架構(gòu)的實現(xiàn),基于邏輯的 Timeline 模型,我們可以很清晰明了的理解整個消息推送和存儲的架構(gòu)。基于 TableStore,可以非常簡單的實現(xiàn) Timeline 模型,其中自增列功能,完美的匹配了 Timeline 模型中所需要的最關鍵的 SeqId 自增。
TableStore(表格存儲)是阿里云自主研發(fā)的專業(yè)級分布式 NoSQL 數(shù)據(jù)庫,是基于共享存儲的高性能、低成本、易擴展、全托管的半結(jié)構(gòu)化數(shù)據(jù)存儲平臺,支撐互聯(lián)網(wǎng)和物聯(lián)網(wǎng)數(shù)據(jù)的高效計算與分析。IM 系統(tǒng)的消息推送和存儲場景,是 TableStore 在社交領域的重要應用之一。
基于 Timeline 的消息存儲和推送模型,將不光應用在 IM 消息系統(tǒng)中,還可應用在例如 Feeds 流、實時消息同步、直播彈幕等場景。
作者:木洛,阿里云高級技術(shù)專家來源:https://yq.aliyun.com/articles/253242?utm_content=m_35131版權(quán)申明:內(nèi)容來源網(wǎng)絡,版權(quán)歸原創(chuàng)者所有。除非無法確認,我們都會標明作者及出處,如有侵權(quán)煩請告知,我們會立即刪除并表示歉意。謝謝。
看到這里,說明你喜歡本文
你的轉(zhuǎn)發(fā),好看的人都點了好看↓↓↓
總結(jié)
以上是生活随笔為你收集整理的消息已读未读的模型设计_阿里云技术专家分享:现代 IM 系统中消息推送和存储架构的实现...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java软件工程_java复习
- 下一篇: python监控windows日志_Py