IM 去中心化概念模型與架構設計

今天打算寫寫關於 IM 去中心化涉及的架構模型變化和設計思路,去中心化的概念就是說用戶的訪問不是集中在一個數據中心,這裏的去中心是針對數據中心而言的。html

站在這個角度而言,實際上並不是全部的業務都能作去中心化設計,對於一致性要求越高的業務去中心化越難作。好比電商領域的庫存就是一個對一致性要求很高的業務,不能超賣也不能少賣,這在單中心容易實現,但多中心純從技術層面感受無解,可能須要從業務和技術層面一塊兒去作個折衷。git

反過來看 IM 的業務場景是很是適合作去中心化設計的,由於其業務場景都是弱一致性需求。打開你的微信或 QQ 仔細觀察下,對大部分人來講與你聯繫最頻繁的實際可能是在地域上離你最近的人,人與人之間的心理距離和物理距離會隨着時間漸趨保持一致。因此根據這個特色,按地域來分佈數據中心和聚合人羣是比較合適的。github

在進入去中心化 IM 架構模型以前,咱們先看看中心化架構是怎樣的,分析其關鍵設計再來看若是要去中心化須要作哪些變化?數據庫

中心化

IM 的中心化架構並不意味着只有一個數據中心,它也能夠是多數據中心的,以下圖。微信

之因此說它是中心化架構,關鍵特徵是其存在共享的數據存儲。部署在兩個數據中心的應用須要共享訪問統一的數據存儲,而這種共享訪問實際是依賴數據中心之間的專線連通,這樣的架構也限制了能選取的數據中心地理位置的距離。而實現去中心架構的關鍵點就在於規避跨數據中心的共享存儲訪問,使得應用在其自身數據中心實現訪問閉環。網絡

咱們這裏只分析下實現 IM 消息互通這個最重要場景下共享數據存儲裏須要存些什麼數據呢?一個是用戶上線後的「座標」,主要指用戶本次在線接入了哪臺機器的哪根鏈接,這個「座標」用於在線消息投遞。而另外一方面若用戶離線時,別人給它發消息,這些消息也須要存儲下來,通常稱爲用戶的「離線消息」,下次用戶上線就能夠自動收取本身的離線消息。架構

中心化架構實際能作到的極致就是把讀實現自有數據中心閉環,而寫依然須要向主數據中心所在的存儲寫入。而 IM 的寫入場景還不算是一個低頻操做,那麼要實現去中心化架構關鍵點就在如何解決寫的問題上。ide

去中心化

在設計 IM 的去中心化架構以前,但願去實現這個架構並編寫代碼時,不須要去考慮最終部署究竟是去中心的仍是中心的。編碼時就像開發中心化架構同樣去實現場景的功能,而去中心化的能力作爲純基礎的技術能力,經過附加的方式來得到,先看看架構圖的變化,以下。編碼

這裏的變化是爲「座標」增長一個「數據中心」緯度,當按通用的方式去本地存儲定位用戶時,發現一個非本地的座標時消息該怎麼投遞?這裏能夠在每一個本地數據中心額外添加一個消息網關程序,註冊到本地存儲中,並負責接收全部非本地座標的消息,這有點像路由網絡中的邊界網關。spa

消息網關統一接收應當發往其餘數據中心的消息,以實現跨數據中心的消息流轉。這裏有個疑問是其餘數據中心的「座標」是怎麼跑到本地來的?離線消息的場景又該如何處理呢?關於這兩個問題,就涉及到咱們解決跨數據中心同步數據的關鍵技術了。

關鍵技術

結合 IM 的業務場景,實際它對同步的延時具備必定的容忍度。因此我以爲基於 Gossip 協議的小道消息傳播特性就能很好的知足這個同步場景。

關於 Gossip 我是在新近的 NoSQL 數據庫 Cassandra 上據說的,後來 Redis Cluster 也利用了該協議來實現無中心化集羣架構。但 Gossip 協議可不是什麼新東西,實際關於它的誕生能夠追溯到好幾十年前的施樂研究中心,就是爲了解決數據庫同步問題被咱們的前前前輩想出來的。

這個協議的靈感來自於辦公室小道消息的傳播路徑,當一我的知道了一條小道消息,他碰到一個朋友並隨口告訴了他,朋友又告訴了朋友的朋友,沒多久整個辦公室都知道了,也就完成了信息的同步。借用這個模型,實際上咱們須要同步的信息就是用戶的在線「座標」和「離線消息」。

由於 Gossip 自好幾十年前已經有不少論文證實並公開發表,並且近年也有 Cassandra 和 Redis 的成功工程實踐,因此我就先不用去懷疑其可行性,而是直接利用其結論了。根據其特性,分析 IM 的去中心場景在引入 Gossip 後有些什麼可供觀察的變化和值得注意的方面。

在一個稍具規模的 IM 場景下,用戶老是在上上下下,消息也在不停的在「在線」和「離線」之間變化,因此須要經過 Gossip 同步的信息是時時存在的。因此假設咱們在某個時刻去拍一個快照(實際作不到),獲得的結果是多個數據中心的數據確定是不一致的,幾乎不存在所謂的全局最終一致性的某一時刻。在這樣的客觀環境下,對 IM 的業務場景有多大影響?

當用戶A在 IDC#1 在線,用戶B 在 IDC#2 剛上線,這裏存在一個同步時差,那麼此時用戶A給用戶B發消息,在本地沒有用戶B的座標,因此進入離線消息池。用戶B此時不能馬上收到用戶A的消息,但離線消息池會在隨後經過 Gossip 協議同步到用戶B所在的 IDC#2,用戶B此時就能夠經過離線消息收取用戶A的消息。

上面描述了一種臨界場景,在這種臨界場景下,用戶收消息存在延時。而這種臨界場景實際上並非常態,並且 IM 用戶實際對這種剛上線的消息延時存在很高的容忍度。這一點我想你們用 QQ 可能體會過,有時一上線都一分鐘了,還會收到以前的離線消息,我不知道這是有意的延時仍是真有這麼長的系統延時。

那麼使用 Gossip 協議從理論上來估算下會產生多久的延時?假設咱們在全國東西南北中各部署一個數據中心,一共五個。五個數據中心之間無專線,走公網互通,網絡延時最大 200 ms。使用 Gossip 完成在五個數據中心的最終一致性同步最大須要多長時間?這裏我直接引用 Gossip 論文結論:

Cycles = log(N) + ln(N) + O(1)

當 N=5 時,完成所有同步,須要節點間私下傳播的次數,套用公式獲得 3.3 次,取整得 4 次。按最大網絡延時 200 ms,每次 Gossip 交換信息間隔 100 ms,那麼協議自己固有延時大約 4x200 + 4x100 = 1.2s,而再算上程序開銷,這個延時極可能在數秒內波動,這個量級的延時對於少數的臨界場景是徹底能夠接受的。

總結

本文的標題是概念模型,但它不像另一篇《RPC 的概念模型與實現解析》跟了實現解析,說明這只是一個理論推導。由於裏面最關鍵的是如何配合 Gossip 的共享存儲彷佛沒有找到特別適合的產品,要是本身作一個呢就會產生一種今天只想出去兜兜風,卻要先本身動手造輛車的感受。

參考

[1]. Wikipedia. Gossip protocol. 2016.03.29
[2]. ALVARO VIDELA. GOSSIP PROTOCOLS, WHERE TO START. 2015.12.02
[3]. Anne-Marie et al. Gossiping in Distributed Systems. 2007
[4]. Márk Jelasity. Gossip Protocols
[5]. Alberto Montresor. Gossip protocols for large-scale distributed systems. 2010


寫點程序世間的文字,畫點生活瞬間的畫兒。
微信公衆號「瞬息之間」,碰見了不妨就關注看看。

相關文章
相關標籤/搜索