本文由作者jhon_11分享,有大量修訂和改動(dòng)溯捆。
1丑搔、引言
如何設(shè)計(jì)一款高性能、高并發(fā)、高可用的im綜合消息平臺(tái)是很多公司發(fā)展過(guò)程中會(huì)碰到且必須要解決的問(wèn)題啤月。比如一家公司內(nèi)部的通訊系統(tǒng)煮仇、各個(gè)互聯(lián)網(wǎng)平臺(tái)的客服咨詢系統(tǒng),都是離不開(kāi)一款好用且維護(hù)的方便im綜合消息系統(tǒng)谎仲。
那么浙垫,我們應(yīng)該怎么樣來(lái)設(shè)計(jì)一款三高特性的im系統(tǒng),并能同時(shí)支持各個(gè)業(yè)務(wù)線的接入(比如:內(nèi)部OA通訊郑诺、客服咨詢夹姥、消息推送等等功能)有呢?
下面就由我來(lái)介紹一下我所負(fù)責(zé)的公司IM綜合消息系統(tǒng)所經(jīng)歷的架構(gòu)設(shè)計(jì)歷程间景,以及架構(gòu)設(shè)計(jì)過(guò)程中的一些思路和總結(jié)佃声,希望能給你帶來(lái)啟發(fā)。
(本文已同步發(fā)布于:http://www.52im.net/thread-3954-1-1.html)
2倘要、初版IM架構(gòu)
2.1 概述
im第一版設(shè)計(jì)的初衷是公司需要一款im消息中間件用于支撐客服咨詢業(yè)務(wù)圾亏。
但是,考慮到為了方便日后其他業(yè)務(wù)線也能接入消息溝通平臺(tái)封拧,所以一開(kāi)始就將整個(gè)消息中心的能力需求給到中間件團(tuán)隊(duì)進(jìn)行開(kāi)發(fā)志鹃,以便除客服外的各業(yè)務(wù)線接入綜合消息中心,從而實(shí)現(xiàn)多元的消息實(shí)時(shí)觸達(dá)能力泽西。
2.2 初版架構(gòu)介紹
初版架構(gòu)圖如下圖所示:
針對(duì)上面的架構(gòu)圖曹铃,我們逐個(gè)解釋一下各模塊的作用。
1)存儲(chǔ)端:
在初版的架構(gòu)下捧杉,存儲(chǔ)端我們使用tidb陕见、redis作為主要存儲(chǔ):
[1]?redis用于存儲(chǔ)消息已讀未讀,緩存連接信息等功能味抖;
[2]?tidb作為開(kāi)源的分布式數(shù)據(jù)庫(kù)评甜,選擇它是為了方便消息的存儲(chǔ)。
2)mq消息總線:
我們使用rocketmq來(lái)實(shí)現(xiàn)消息總線(PS:即分布式情況下仔涩,不同im實(shí)例間通過(guò)MQ進(jìn)行消息交互)忍坷。
消息總線是整個(gè)im的核心,使用rocketmq能支持十萬(wàn)級(jí)別的tps熔脂∨逖校基本所有服務(wù)都要從消息總線中消費(fèi)消息進(jìn)行業(yè)務(wù)處理。
3)zookeeper注冊(cè)中心:各個(gè)服務(wù)會(huì)注冊(cè)到zk中霞揉,方便服務(wù)之間內(nèi)部進(jìn)行調(diào)用旬薯,同樣也可以暴露服務(wù)給外部進(jìn)行調(diào)用。
4)link服務(wù):
link服務(wù)主要用于接收客戶端的ws(WebSocket協(xié)議)适秩、tcp袍暴、udp等協(xié)議的連接些侍。
同時(shí)調(diào)用用戶服務(wù)進(jìn)行認(rèn)證,并投遞連接成功的消息給位置服務(wù)進(jìn)行消費(fèi)政模,存儲(chǔ)連接信息。
ws(WebSocket協(xié)議)過(guò)來(lái)的消息先到link再投遞到消息總線蚂会。
5)消息分發(fā)服務(wù):
消息分發(fā)服務(wù)主要用于接收消息總線推過(guò)來(lái)的消息進(jìn)行處理淋样,按照im內(nèi)部消息協(xié)議構(gòu)造好消息體后,又推送到消息總線中(比如會(huì)推給會(huì)話服務(wù)胁住、消息盒子趁猴、link服務(wù))。
6)位置服務(wù):
存儲(chǔ)link的(WebSocket協(xié)議)連接彪见、tcp連接等信息儡司,并使用redis進(jìn)行緩存(key為userId),方便根據(jù)UserId查詢到該用戶所登錄的客戶端連接在哪個(gè)link上余指。
一個(gè)用戶在相同設(shè)備只能登錄一個(gè)捕犬,但可以支持多端登錄。
7)用戶服務(wù):用于存儲(chǔ)所有用戶酵镜,提供認(rèn)證查詢接口碉碉。
8)消息盒子:存儲(chǔ)所有消息,提供消息查詢淮韭、消息已讀未讀垢粮、消息未讀數(shù)、消息檢索等功能靠粪。
9)會(huì)話服務(wù):管理會(huì)話蜡吧、群聊會(huì)話、單聊會(huì)話等功能占键。
2.3 整體時(shí)序圖
整體架構(gòu)的時(shí)序圖如下:
3昔善、初版IM架構(gòu)存在的問(wèn)題及思考
在上節(jié)的架構(gòu)設(shè)計(jì)介紹中,我們?cè)敿?xì)分享了初版IM系統(tǒng)架構(gòu)的設(shè)計(jì)思路以及具體流程捞慌。
那么在初版IM架構(gòu)設(shè)計(jì)中還存在什么樣的問(wèn)題耀鸦,又該如何優(yōu)化呢?我們一條條來(lái)看看啸澡。
3.1 使用MQ消息總線的問(wèn)題
正如上節(jié)所分享的那樣袖订,我們初版IM架構(gòu)中,link服務(wù)到消息分發(fā)服務(wù)的消息使用的MQ消息總線嗅虏。
初版架構(gòu)設(shè)計(jì)中洛姑,link服務(wù)將消息下推給消息分發(fā)服務(wù)進(jìn)行處理時(shí),使用的是mq消息總線(通俗了說(shuō)皮服,IM集群內(nèi)不同IM實(shí)例間的通信是依賴于MQ進(jìn)行的消息傳遞)楞艾,而mq消息總線必然做對(duì)有一定的時(shí)延(而且時(shí)延受制于MQ本身的系統(tǒng)實(shí)現(xiàn)和技術(shù)策略)参咙。
舉個(gè)例子:
當(dāng)兩個(gè)處于不同IM實(shí)例的客戶端A和B聊天時(shí),A用戶發(fā)送消息到link?-->?消息總線?-->?消息分發(fā)服務(wù)?-->?消息總線?-->?link?-->?B用戶硫眯。
正如上面這個(gè)例子蕴侧,im消息投遞流程太長(zhǎng)了,并且這樣也會(huì)大大降低系統(tǒng)的吞吐量两入。
3.2 消息落庫(kù)為寫(xiě)擴(kuò)散的問(wèn)題
其實(shí)現(xiàn)階段我們使用的是跟微信一樣的寫(xiě)擴(kuò)散策略(詳見(jiàn)《企業(yè)微信的IM架構(gòu)設(shè)計(jì)揭秘:消息模型净宵、萬(wàn)人群、已讀回執(zhí)裹纳、消息撤回等》)择葡。
那么為啥微信使用寫(xiě)擴(kuò)散不是缺陷,而對(duì)于我們的IM架構(gòu)來(lái)說(shuō)確是缺陷呢剃氧?
微信的技術(shù)特性:
1)微信號(hào)稱沒(méi)有存儲(chǔ)用戶的聊天記錄敏储,全是實(shí)時(shí)推送;
2)微信聊天記錄全部會(huì)在我們手機(jī)端存儲(chǔ)一份朋鞍,兩臺(tái)手機(jī)終端上的聊天記錄并不互通已添,并且互不可見(jiàn)。
我們的IM綜合消息中心技術(shù)特性:
1)綜合消息中心是會(huì)有拉取歷史聊天記錄(服務(wù)端拉确摺)的功能酝碳,存儲(chǔ)了全量消息;
2)綜合消息中心的客戶端恨狈,需要支持網(wǎng)頁(yè)版本疏哗。
綜上所述:
1)寫(xiě)擴(kuò)散對(duì)微信這樣有移動(dòng)端的富客戶端版本的即時(shí)通訊產(chǎn)品十分友好,每個(gè)消息在消息分發(fā)的時(shí)候給處于這個(gè)會(huì)話(單聊禾怠,群聊)下的所有用戶所在客戶端先推送消息返奉,沒(méi)找到連接就針對(duì)這個(gè)用戶寫(xiě)一個(gè)離線緩存消息,那么下次該用戶登錄進(jìn)來(lái)吗氏,可以從緩存中拉取到該消息芽偏,并且清掉緩存;
2)寫(xiě)擴(kuò)散對(duì)于我們這類通用綜合消息平臺(tái)并不友好弦讽,由于接入方大部分是網(wǎng)頁(yè)版的客戶端污尉,所以沒(méi)有緩存消息的能力,瀏覽器刷新就沒(méi)有了任何消息往产,所以需要實(shí)時(shí)去服務(wù)端拉取歷史消息被碗。假設(shè)我是寫(xiě)擴(kuò)散,在一個(gè)群聊中有五百個(gè)用戶仿村,針對(duì)這五百個(gè)用戶在這個(gè)會(huì)話锐朴,我需要去寫(xiě)五百條消息,大大的增加了寫(xiě)io蔼囊,并且還不能寫(xiě)緩存(得寫(xiě)數(shù)據(jù)庫(kù))焚志。
3.3 tidb存在不穩(wěn)定性和事務(wù)并發(fā)的問(wèn)題
tidb是目前主流的開(kāi)源分布式數(shù)據(jù)庫(kù)衣迷,查詢效率高、無(wú)需分庫(kù)分表酱酬。
但同樣的壶谒,tidb存在一些隱藏的問(wèn)題:
1)tidb在高并發(fā)情況下,并發(fā)事務(wù)會(huì)導(dǎo)致事務(wù)失敗膳沽,具體原因不知佃迄;
2)tidb排錯(cuò)成本高,公司很少有tidb專業(yè)運(yùn)維贵少,經(jīng)常遇到不走索引的情況。
3.4 群聊堆缘、單聊冗余在同一個(gè)服務(wù)的問(wèn)題
在我們初版的IM架構(gòu)設(shè)計(jì)中滔灶,單聊和群聊是冗余在會(huì)話服務(wù)中的,并且冗余在同一張表的吼肥。
其實(shí)單聊录平、群聊從數(shù)據(jù)角度來(lái)說(shuō),還是會(huì)有些不同(比如業(yè)務(wù)屬性)雖然都是會(huì)話缀皱,我們還是需要將這兩個(gè)服務(wù)拆分開(kāi)斗这,細(xì)粒度的服務(wù)拆分能更好的把控整體的邏輯。
4啤斗、升級(jí)版IM架構(gòu)
4.1 初始架構(gòu)問(wèn)題
正如前面兩節(jié)分享的那樣表箭,漸漸的我們發(fā)現(xiàn)初版im架構(gòu)有很大的不足之處。
在生產(chǎn)上暴露出了以下問(wèn)題:
1)tps沒(méi)達(dá)到預(yù)期钮莲,吞吐量不能滿足公司業(yè)務(wù)的發(fā)展免钻;
2)使用的存儲(chǔ)中間件難以維護(hù)(主要是tidb),試錯(cuò)成本高崔拥,經(jīng)常在生產(chǎn)暴露問(wèn)題极舔,并且速度越來(lái)越慢;
3)消息寫(xiě)擴(kuò)散沒(méi)有太大必要链瓦,并大大增加了系統(tǒng)io次數(shù)(原因見(jiàn)上一節(jié))拆魏;
4)一些特性無(wú)法支持,比如消息圖文檢索慈俯,消息已讀未讀渤刃。
4.2 升級(jí)版im架構(gòu)介紹
本次升級(jí)后的im架構(gòu)如下圖所示:
如上圖所示,改版后的各模塊情況如下:
1)存儲(chǔ)端:存儲(chǔ)端我們改用了mysql肥卡,針對(duì)消息服務(wù)單獨(dú)使用了主從mysql集群(主節(jié)點(diǎn)用于寫(xiě)消息溪掀、從節(jié)點(diǎn)用于消息檢索)——;
2)mq消息總線:與第一版相比沒(méi)有改動(dòng)步鉴;
3)link服務(wù):與第一版相比揪胃,改動(dòng)了link服務(wù)到消息分發(fā)服務(wù)的消息推送方式(由MQ總線方式變更為tcp實(shí)時(shí)推送)璃哟;
4)消息分發(fā)服務(wù):集成了消息處理能力、路由能力喊递,每臺(tái)消息分發(fā)服務(wù)擁有所有l(wèi)ink服務(wù)的tcp連接随闪;
5)單聊服務(wù):負(fù)責(zé)單聊會(huì)話的管理能力;
6)群聊服務(wù):負(fù)責(zé)群聊會(huì)話的管理能力骚勘;
7)用戶服務(wù):提供用戶認(rèn)證铐伴,登錄\注冊(cè)能力。
5俏讹、詳細(xì)對(duì)比針對(duì)初版IM架構(gòu)的改動(dòng)
升級(jí)版的IM架構(gòu)当宴,對(duì)比初始初始,具體主要是下面這些改動(dòng)泽疆。
5.1 改進(jìn)了不同im實(shí)例間的消息分發(fā)方式
針對(duì)初版MQ消息總結(jié)的問(wèn)題户矢,升級(jí)版架構(gòu)中,我們將link到消息分發(fā)服務(wù)改為tcp實(shí)時(shí)連接殉疼,百萬(wàn)客戶端連接同一臺(tái)link機(jī)器梯浪,消息實(shí)時(shí)觸達(dá)能力tps達(dá)到16萬(wàn)。
link到消息分發(fā)服務(wù)的改版是本次設(shè)計(jì)的亮點(diǎn)之一瓢娜,完全消除了mq推送的時(shí)延性挂洛,并且路由簡(jiǎn)單,幾乎實(shí)時(shí)觸達(dá)眠砾。
舉個(gè)例子:(當(dāng)兩個(gè)處于不同IM實(shí)例的客戶端A和B聊天時(shí))
1)初版架構(gòu)中是:A用戶發(fā)送消息到link --> 消息總線 --> 消息分發(fā)服務(wù) --> 消息總線 --> link --> B用戶虏劲;
2)升級(jí)版架構(gòu)是:用戶A --> link --> 消息分發(fā) --> link --> 用戶B。
而且:link服務(wù)到消息分發(fā)服務(wù)集群的消息推送使用輪詢負(fù)載均衡的方式荠藤,保證公平伙单,不會(huì)導(dǎo)致個(gè)別機(jī)器負(fù)載過(guò)高。
5.2 取消了位置服務(wù)
取消了位置服務(wù)(這里的位置不是指的IM消息里的地理位置消息哦)哈肖,消息分發(fā)服務(wù)集成位置服務(wù)的能力吻育。
消息分發(fā)服務(wù)本身業(yè)務(wù)簡(jiǎn)單,不需要再單獨(dú)劃分位置服務(wù)淤井,因?yàn)闀?huì)增加網(wǎng)絡(luò)io布疼,并且消息分發(fā)服務(wù)直連link,而讓它負(fù)責(zé)路由則更加方便币狠。
5.3 存儲(chǔ)由tidb改成了mysql
存儲(chǔ)端由tidb改成了mysql游两,增強(qiáng)了可維護(hù)性,消息服務(wù)使用mysql主從讀寫(xiě)分離方式漩绵,提高了消息落庫(kù)速度與檢索速度的同時(shí)贱案,也減輕數(shù)據(jù)庫(kù)壓力。
前面有提到過(guò)使用tidb這樣維護(hù)成本高止吐,排查問(wèn)題難的分布式數(shù)據(jù)庫(kù)是一件很痛苦的事情宝踪。
而我們使用mysql更加穩(wěn)定侨糟,大家對(duì)mysql的學(xué)習(xí)成本相對(duì)較低。針對(duì)消息服務(wù)使用讀寫(xiě)分離的方式瘩燥,能大大提高消息的吞吐量秕重。
5.4 實(shí)現(xiàn)了初版無(wú)法實(shí)現(xiàn)的特性功能
升級(jí)版架構(gòu)中,我們實(shí)現(xiàn)了初版無(wú)法實(shí)現(xiàn)的特性功能厉膀,比如消息已讀未讀溶耘、紅包推送、商品鏈接推送等功能服鹅。
新版綜合消息中心加入了消息已讀未讀凳兵、發(fā)送紅包、鏈接推送等功能企软,但這些功能帶有一定的業(yè)務(wù)特性留荔,畢竟不是所有Im都需要,可通過(guò)配置取消這些功能澜倦。
5.5 消息由寫(xiě)擴(kuò)散改為讀擴(kuò)散
升級(jí)版IM架構(gòu)中,消息存儲(chǔ)由寫(xiě)擴(kuò)散改為了讀擴(kuò)散杰妓。
前面我們有提到寫(xiě)擴(kuò)散和讀擴(kuò)散的利弊藻治,對(duì)于網(wǎng)頁(yè)端IM我們更適合使用讀擴(kuò)散,只需要落一條消息巷挥,大大提高消息服務(wù)的吞吐量.
5.6 增加了門(mén)面服務(wù)
升級(jí)版IM架構(gòu)中桩卵,我們?cè)黾娱T(mén)面服務(wù)?im-logic,用于暴露給第三方業(yè)務(wù)線接口調(diào)用倍宾。
初版架構(gòu)中雏节,都是im的各個(gè)服務(wù)各自暴露接口給到外部進(jìn)行調(diào)用, 而升級(jí)版架中我們統(tǒng)一使用logic服務(wù)暴露給外部調(diào)用哮奇。
在logic服務(wù)針對(duì)調(diào)用可以做一些處理亥贸,這樣不會(huì)影響到整體im的通用卤档,不會(huì)增加im底層代碼的復(fù)雜度,從而將業(yè)務(wù)邏輯與底層進(jìn)行解耦寥粹。
6、優(yōu)化后的效果對(duì)比
針對(duì)升級(jí)版和初版IM架構(gòu)埃元,我們也做了一些對(duì)比測(cè)試涝涤,具體的測(cè)試過(guò)程就是詳細(xì)展開(kāi)了。
以下是測(cè)試結(jié)果:
7岛杀、業(yè)務(wù)線接入im綜合消息系統(tǒng)的業(yè)務(wù)劃分思考
7.1 到底該如何設(shè)計(jì)高性能通用im綜合消息系統(tǒng)
關(guān)于業(yè)務(wù)線接入im綜合消息系統(tǒng)的業(yè)務(wù)劃分阔拳,我也做了一些總結(jié)和思考,為了更形象和易于理解类嗤,我這里以客服系統(tǒng)以及企業(yè)微信為例來(lái)進(jìn)行分析糊肠。
假如我開(kāi)發(fā)了一款通用的im綜合消息系統(tǒng)辨宠,現(xiàn)在有很多業(yè)務(wù)方需要接入我們,我們?cè)撊绾芜M(jìn)行業(yè)務(wù)域的清晰劃分就顯得尤為重要罪针,需要在妥協(xié)與不妥協(xié)中進(jìn)行平衡彭羹。
就像當(dāng)前市面上開(kāi)源的im消息平臺(tái)來(lái)說(shuō),存在的問(wèn)題主要是:要么是集成了很多的業(yè)務(wù)邏輯泪酱,要么就只是一款單純的客服系統(tǒng)派殷,再或者就是一款I(lǐng)M好友聊天系統(tǒng),中間的業(yè)務(wù)劃分并不明確墓阀。當(dāng)然毡惜,這也有好處,拿來(lái)就能用斯撮,并不需要進(jìn)行二次業(yè)務(wù)封裝经伙。
那么,到底如何將im設(shè)計(jì)為一款真正的高性能通用im綜合消息系統(tǒng)呢勿锅?
通用的綜合消息消息平臺(tái)只需要有通用的底層能力:
以下案例假設(shè)在我已經(jīng)按照上述架構(gòu)設(shè)計(jì)了一版im綜合消息中心帕膜。
7.2 以客服系統(tǒng)為例
客服系統(tǒng):
客服系統(tǒng)不光需要實(shí)現(xiàn)自身業(yè)務(wù),還需要整合im的消息能力(消費(fèi)im的消息)溢十,來(lái)進(jìn)行場(chǎng)景分析垮刹,實(shí)現(xiàn)會(huì)話變更、信令消息推送等邏輯张弛。
客服系統(tǒng)內(nèi)部需要根據(jù)im的底層支持能力進(jìn)行相應(yīng)的業(yè)務(wù)封裝以及客服系統(tǒng)的客服用戶池荒典,c端用戶池如何初始化到im的用戶中心這些問(wèn)題都是需要考慮進(jìn)去的。
7.3 內(nèi)部OA通信為例
內(nèi)部OA通信:
員工內(nèi)部OA通信系統(tǒng)需要集成IM好友功能吞鸭,需要根據(jù)im的用戶中心封裝組織架構(gòu)寺董,用戶權(quán)限等功能。
同時(shí)刻剥,內(nèi)部通信系統(tǒng)需要根據(jù)im實(shí)現(xiàn)消息已讀未讀遮咖,群聊列表,會(huì)話列表拉取等功能造虏。
8盯滚、本文小結(jié)
im的綜合消息平臺(tái)是一款需要高度結(jié)合業(yè)務(wù)的中間件系統(tǒng),它直接與業(yè)務(wù)打交道酗电,跟普通的中間件有根本的區(qū)別魄藕。
一款好用的im綜合消息平臺(tái),直接取決于你的通用性撵术,可擴(kuò)展性以及系統(tǒng)吞吐能力背率。
希望這篇文章所分享的內(nèi)容,能對(duì)大家開(kāi)發(fā)im時(shí)候的思路有所啟迪。
9寝姿、參考資料
[1]?從零到卓越:京東客服即時(shí)通訊系統(tǒng)的技術(shù)架構(gòu)演進(jìn)歷程
[2]?從游擊隊(duì)到正規(guī)軍(一):馬蜂窩旅游網(wǎng)的IM系統(tǒng)架構(gòu)演進(jìn)之路
[3]?瓜子IM智能客服系統(tǒng)的數(shù)據(jù)架構(gòu)設(shè)計(jì)(整理自現(xiàn)場(chǎng)演講交排,有配套PPT)
[4]?阿里釘釘技術(shù)分享:企業(yè)級(jí)IM王者——釘釘在后端架構(gòu)上的過(guò)人之處
[5]?新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM
[6]?零基礎(chǔ)IM開(kāi)發(fā)入門(mén)(一):什么是IM系統(tǒng)?
[7]?基于實(shí)踐:一套百萬(wàn)消息量小規(guī)模IM系統(tǒng)技術(shù)要點(diǎn)總結(jié)
[8]?一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(上篇):整體架構(gòu)饵筑、服務(wù)拆分等
[9]?一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(下篇):可靠性埃篓、有序性、弱網(wǎng)優(yōu)化等
[10]?從新手到專家:如何設(shè)計(jì)一套億級(jí)消息量的分布式IM系統(tǒng)
[11]?企業(yè)微信的IM架構(gòu)設(shè)計(jì)揭秘:消息模型根资、萬(wàn)人群架专、已讀回執(zhí)、消息撤回等
[12]?阿里IM技術(shù)分享(三):閑魚(yú)億級(jí)IM消息系統(tǒng)的架構(gòu)演進(jìn)之路
[13]?一套高可用玄帕、易伸縮部脚、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計(jì)實(shí)踐
(本文已同步發(fā)布于:http://www.52im.net/thread-3954-1-1.html)