瓜子IM智能客服系統(tǒng)的數(shù)據(jù)架構(gòu)設(shè)計(jì)(整理自現(xiàn)場演講)
Posted on 2019-10-25 15:29 Jack Jiang 閱讀(149) 評論(0) 編輯 收藏本文由ITPub根據(jù)封宇在【第十屆中國系統(tǒng)架構(gòu)師大會(SACC2018)】現(xiàn)場演講內(nèi)容整理而成。
1、引言
瓜子業(yè)務(wù)重線下,用戶網(wǎng)上看車、預(yù)約到店、成交等許多環(huán)節(jié)都發(fā)生在線下。瓜子IM智能客服系統(tǒng)的目的是要把這些線下的活動搬到線上,對線下行為進(jìn)行追溯,積累相關(guān)數(shù)據(jù)。系統(tǒng)連接用戶、客服、電銷、銷售、AI機(jī)器人、業(yè)務(wù)后臺等多個(gè)角色及應(yīng)用,覆蓋網(wǎng)上咨詢、瀏覽、預(yù)約看車、到店體驗(yàn)、后服、投訴等眾多環(huán)節(jié),各個(gè)角色間通過可直接操作的卡片傳遞業(yè)務(wù)。
例如,用戶有買車意向時(shí),電銷或AI機(jī)器人會及時(shí)給用戶推送預(yù)約看車的卡片,用戶只需選擇時(shí)間即可完成預(yù)約操作。整個(gè)系統(tǒng)邏輯復(fù)雜,及時(shí)性、可靠性要求高,涉及IM消息、業(yè)務(wù)卡片、各種實(shí)時(shí)統(tǒng)計(jì)。此次演講,從數(shù)據(jù)架構(gòu)層面講解系統(tǒng)遇到的挑戰(zhàn)及解決辦法。
補(bǔ)充說明:本文對應(yīng)的演講PPT詳見《瓜子IM智能客服系統(tǒng)的數(shù)據(jù)架構(gòu)設(shè)計(jì)(PPT) [附件下載]》。
學(xué)習(xí)交流:
- 即時(shí)通訊/推送技術(shù)開發(fā)交流5群:215477170 [推薦]
- 移動端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動端IM》
(本文同步發(fā)布于:http://www.52im.net/thread-2807-1-1.html)
2、分享者

封宇:瓜子二手車高級技術(shù)專家,中國計(jì)算機(jī)學(xué)會專業(yè)會員。2017年2月入職瓜子二手車,主要負(fù)責(zé)瓜子即時(shí)消息解決方案及相關(guān)系統(tǒng)研發(fā)工作。在瓜子期間,主持自研消息系統(tǒng)用于支持瓜子內(nèi)效工具呱呱,滿足瓜子兩萬多員工移動辦公需求;作為項(xiàng)目經(jīng)理,負(fù)責(zé)瓜子服務(wù)在線化項(xiàng)目,該項(xiàng)目對瓜子二手車交易模式及流程帶來深遠(yuǎn)影響。
在入職瓜子二手車之前,封宇曾供職于58同城、58到家、華北計(jì)算技術(shù)研究所,參與到家消息系統(tǒng)、58爬蟲系統(tǒng)以及多個(gè)國家級軍工科研項(xiàng)目的架構(gòu)及研發(fā)工作。在消息系統(tǒng)、后端架構(gòu)、存儲架構(gòu)等方面有豐富經(jīng)驗(yàn)。
封宇分享的其它IM技術(shù)資料:
《一套海量在線用戶的移動端IM架構(gòu)設(shè)計(jì)實(shí)踐分享(含詳細(xì)圖文)》
《即時(shí)通訊安全篇(七):用JWT技術(shù)解決IM系統(tǒng)Socket長連接的身份認(rèn)證痛點(diǎn)》
《移動端IM中大規(guī)模群消息的推送如何保證效率、實(shí)時(shí)性?》
《從零開始搭建瓜子二手車IM系統(tǒng)(PPT) [附件下載]》
《瓜子IM智能客服系統(tǒng)的數(shù)據(jù)架構(gòu)設(shè)計(jì)(PPT) [附件下載]》
《瓜子IM智能客服系統(tǒng)的數(shù)據(jù)架構(gòu)設(shè)計(jì)(整理自現(xiàn)場演講,有配套PPT)》
3、正文概述
今天分享的題目是“瓜子IM智能客服數(shù)據(jù)架構(gòu)設(shè)計(jì)”,這個(gè)系統(tǒng)和旺旺比較像。
簡單說一下分享的幾大部分內(nèi)容:
第一部分:項(xiàng)目背景,項(xiàng)目背景需要稍微講一下,有助于大家理解;
第二部分:是系統(tǒng)架構(gòu),為什么要簡單講一下系統(tǒng)架構(gòu)呢?因?yàn)椴恢v業(yè)務(wù)的架構(gòu)都是耍流氓,所以說我們講存儲,都要知道系統(tǒng)是怎么回事;
第三部分:重點(diǎn)講一下存儲,在這塊我們講分享一下我們的實(shí)踐經(jīng)驗(yàn),以及演進(jìn)過程,更多的是采到的一些坑,我們怎么解決的。
4、項(xiàng)目背景
比較熟悉的都知道瓜子二手車沒有中間商賺差價(jià),其實(shí)瓜子在中間要做很多事情。

首先二手車很難,它不是一個(gè)標(biāo)品,我們要去收車,收車都是在社會上去收,通過網(wǎng)站收,你要驗(yàn)車。我們要把它放到我們的網(wǎng)站上,有些車要收到我們的場地,有些車可能是在用戶家里樓下停著。如果一個(gè)用戶來買車,在網(wǎng)上點(diǎn)了之后,你可能下單要去看這個(gè)車,我們的銷售要去跟到線下去陪你看車選車試駕,還有一系列的復(fù)檢等等,有很多的事情。

現(xiàn)在瓜子這塊我們做的還不夠好,為什么不夠好?我們站在瓜子內(nèi)部的角度來看這個(gè)事情,有很多的行為發(fā)生在線下,我們很難防就會帶來很多問題。比如飛單,有些去跟別的企業(yè)串,這個(gè)車就沒有在平臺上賣,這些問題都很難解決。
第二個(gè)就是銷售到底跟用戶在做什么,他沒準(zhǔn)罵那些用戶或者什么的,回頭企業(yè)發(fā)現(xiàn)的投訴很難查。那我們這個(gè)項(xiàng)目的一個(gè)重要的問題,就要解決一個(gè)線上化,就是把這些線下的行為搬到線上,我們利用通訊,在IM過程當(dāng)中傳遞一些業(yè)務(wù),這樣把整個(gè)的一些業(yè)務(wù)線上化固化下來。
第三個(gè)是電商化,我比較喜歡用京東,我覺得他的物流和客服都很好,瓜子也是希望做成電商,還有一個(gè)就降本增效快一點(diǎn),如果現(xiàn)在你用瓜子,你會發(fā)現(xiàn)你到網(wǎng)上去瀏覽,就會有電銷人員給你打電話,這個(gè)是很煩的,對用戶的體驗(yàn)很不好,再一個(gè)對瓜子來說成本也很高,我們也養(yǎng)了很多的電銷,所以說我們就啟動了這樣一個(gè)項(xiàng)目來解決這些問題。

剛才提到了很復(fù)雜,整個(gè)系統(tǒng)串聯(lián)了很多角色,有用戶、銷售、電銷、評估師,還有AI和機(jī)器人。做系統(tǒng)要善于抽象,我們先有一個(gè)基于通訊的即時(shí)通訊系統(tǒng)。第二我們是要把通訊系統(tǒng)集成到業(yè)務(wù),或者叫把這些業(yè)務(wù)搬到通訊系統(tǒng)上面來,核心就是這樣子。

這是截了幾個(gè)圖,我們看第一個(gè)圖,我們上邊就有一個(gè)車,下邊有個(gè)預(yù)約,用戶事實(shí)上是可以直接在聊天界面里面去點(diǎn)預(yù)約了。這個(gè)就是我說的跟一般的客服不一樣的,它可以做一些叫做導(dǎo)購或者叫營銷也好,直接通過這樣一個(gè)途徑,因?yàn)楣献拥墨@客成本很高,每個(gè)訪問瓜子的用戶我們都希望及時(shí)跟他溝通,這個(gè)圖有助于大家理解。
5、系統(tǒng)架構(gòu)

整個(gè)系統(tǒng)不是一個(gè)單一的系統(tǒng),它結(jié)合了一些業(yè)務(wù),我們可以把它拆分成這么幾個(gè)層次。最上面是一個(gè)端,那端首先就是瓜子的APP,當(dāng)然還有毛豆的,現(xiàn)在瓜子的業(yè)務(wù)有好幾個(gè),除此之外有些員工用的,比如說電銷的、客服的、售后的、金融的、我們可能都是一些APP或者是一些桌面系統(tǒng),這是我們的客戶端。
第二是一個(gè)路由層,我們要打通這些業(yè)務(wù)。要讓這些業(yè)務(wù)在這個(gè)系統(tǒng)里邊及時(shí)的傳遞,所謂傳遞剛才前面有個(gè)圖案,比如說你想約車了,那客服就給你或者電銷就給你發(fā)一個(gè)約車的卡片,你就可以直接選時(shí)間約,這是傳遞業(yè)務(wù)。再往下邊是一些業(yè)務(wù)層,那就是原來瓜子有很多有什么業(yè)務(wù)就涉及什么業(yè)務(wù),最底下是一個(gè)存儲。這次后邊主要講的就是站在存儲層的角度來看整個(gè)系統(tǒng),重點(diǎn)會講存儲層怎么對路由層進(jìn)行支持。
6、存儲架構(gòu)
存儲這塊會講大概幾個(gè)點(diǎn),包括:
1)數(shù)據(jù)庫的拆分;
2)消息怎么存,消息里邊也會特別提一下群的模型,大規(guī)模的群是比較麻煩的;
3)還有一些存儲邏輯以及業(yè)務(wù)怎么在上邊run起來;
4)最后是統(tǒng)計(jì)分析,實(shí)時(shí)計(jì)算這樣一些設(shè)備。
6.1 數(shù)據(jù)庫的拆分

這個(gè)圖是現(xiàn)在的一個(gè)數(shù)據(jù)庫的圖,我們看著這些就是數(shù)據(jù)庫已經(jīng)分得很好了,比如通訊的數(shù)據(jù)庫,有調(diào)度的有卡片有分析。
我在這里介紹一下“調(diào)度”這個(gè)新出現(xiàn)的名詞,它是干嘛的?就是你在這個(gè)系統(tǒng)里邊點(diǎn)開一個(gè)車也好,點(diǎn)開的人也好,聊天時(shí)用戶看到的是一個(gè)瓜子的客服,后邊瓜子內(nèi)部實(shí)際上是一個(gè)瓜子的客戶團(tuán)隊(duì)非常大的團(tuán)隊(duì)來支持你,所以說到底你跟哪個(gè)客服聊天,是有一些策略的。
我們感覺這樣一個(gè)拆分實(shí)際上是順理成章的,但是事實(shí)上根本就不是。我舉個(gè)例子,2015年大概是京東內(nèi)部有一個(gè)分享,劉強(qiáng)東分享流露出來了,說有一個(gè)二手車企業(yè)一年還是一個(gè)月,我忘了,賣了兩輛車出去,估值就到了2億美金。簡直不敢相信。
我分享這個(gè)例子并不是說話有什么不對,當(dāng)然我相信他也不是說的瓜子,因?yàn)楣献覣輪它不止這個(gè)數(shù),我想說最初企業(yè)是很小的,業(yè)務(wù)量是很小的,我們根本就不可能是這樣一個(gè)數(shù)據(jù)庫的結(jié)構(gòu),就跟沈老師說的一樣,其實(shí)它就是一個(gè)庫也沒有什么IM,沒有什么調(diào)度,這些卡片可能就是一個(gè)賣車的一個(gè)數(shù)據(jù)庫。
我是去年的2月份進(jìn)入瓜子的,快兩年了,那時(shí)候瓜子的業(yè)務(wù)量非常小,具體我也不知道,就是一個(gè)數(shù)據(jù)庫,一個(gè)數(shù)據(jù)庫其實(shí)是非常好的。因?yàn)楹芏嗳藖砹酥缶驼f要拆庫,一個(gè)數(shù)據(jù)庫的好處是寫業(yè)務(wù)很快,十幾個(gè)人快速的就把系統(tǒng)就搭起來了。
我們事實(shí)上庫拆成這么幾個(gè)也經(jīng)歷了一個(gè)過程,最初是做IM只有一個(gè)IM的庫,后來有了調(diào)度加了一個(gè)庫,再后來有什么卡片,有分析逐步得往外擴(kuò)。
這個(gè)庫它其實(shí)是有一定的成本,如果你拆分得不好,你會去做很多接口,比如說你像關(guān)聯(lián)查一下,發(fā)現(xiàn)不是我團(tuán)隊(duì)的庫也要做各種各樣接口,產(chǎn)生了分布式的事物的一致性的問題,都產(chǎn)生了。所以說數(shù)據(jù)庫的拆分,尤其垂直拆分,實(shí)際上是隨著你不同的階段,你選擇不同的拆分方式,以后隨著系統(tǒng)的擴(kuò)大瓜子業(yè)務(wù)擴(kuò)大這個(gè)系統(tǒng)它會拆的更多數(shù)據(jù)庫,但拆的更多,對你的運(yùn)維監(jiān)控這些團(tuán)隊(duì)的挑戰(zhàn)都會帶來一些成本,也會帶來一些挑戰(zhàn)。我們現(xiàn)在把它拆成了這樣一個(gè)庫,各司其職。

(原圖來自《現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲方案探討》)
6.2 消息怎么存
下面就重點(diǎn)說一下消息,這塊我們怎么存?
我們看一下左邊這個(gè)圖,左邊這個(gè)圖是一般來說很容易理解的消息,怎么存的方式?
以前桌面系統(tǒng)經(jīng)常這么干:比如說A要給B發(fā)一個(gè)消息,他怎么發(fā)?他就說A用戶端,A這個(gè)端我發(fā)一個(gè)消息,如果B在線,我就把消息直接發(fā)給他,他給我一個(gè)確認(rèn),這個(gè)過程就存儲好就結(jié)束了。
其實(shí)我服務(wù)當(dāng)中不需要存這個(gè)消息,如果是A發(fā)給一個(gè)C這個(gè)C不在線怎么辦?
我們也有策略:A把這個(gè)消息發(fā)給了C,C如果沒有確認(rèn)說我收到這個(gè)消息,我就把這個(gè)下邊的第二步,我就把它存到一個(gè)離線的數(shù)據(jù)庫里邊等著你C什么時(shí)候上線,你就把這個(gè)消息拉回去,這個(gè)過程就完結(jié)了,這個(gè)消息我就給送到了,所以說這個(gè)時(shí)候的存儲非常簡單,我就一個(gè)離線庫,存一下某個(gè)人的消息就好了。
但是這種模式其實(shí)是有很多問題的,真正使用的時(shí)候,很多產(chǎn)品現(xiàn)在是移動端的手機(jī)端,網(wǎng)絡(luò)首先是不穩(wěn)定,長期處于一個(gè)C的狀態(tài),如果你都去監(jiān)控它的狀態(tài),送沒送到,再存儲性能會很差。

(原圖來自《現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲方案探討》)
第二個(gè)現(xiàn)在的端有很多:有桌面的、有手機(jī)的、有APP端、還有PAD端,有好幾個(gè)端。如果都用這種模式,需要為每個(gè)端都這里判斷去看傳輸數(shù)據(jù)其實(shí)也是很困難的。
我們就變了一個(gè)方式:第1步來了消息,我們就把消息存到存儲庫,你只要發(fā)消息我就先給你存下來,第2步,同時(shí)我還存到一個(gè)同步庫里邊。
這兩個(gè)庫要稍微解釋一下,存儲和同步庫分別來做什么?
存儲庫比較好理解,你什么時(shí)候都能從庫里邊還原你的消息,把它讀回去,比如說你換了手機(jī),你都可以把消息拉回來。
這個(gè)同步庫是什么意思?同步庫就是說你沒有換手機(jī),也沒有重新裝系統(tǒng),就是你可能有一段時(shí)間離線,離線起來之后,就說我比如假設(shè)一個(gè)消息序列,1到100發(fā)給你了,就A發(fā)給C,1到100了。結(jié)果但是C從第70號消息的時(shí)候,他就離線了,他就不在線。這樣子,C這個(gè)端上線后,第四步把70號消息傳給這個(gè)服務(wù)端,說我有70消息同步庫就知道,把70到100的消息發(fā)給C。這樣子消息就是可以送達(dá)這個(gè)端,這兩個(gè)概念稍微是會有一點(diǎn)模糊,但是沒有關(guān)系,后邊我會接著展開來講。
也就說一個(gè)消息,我們會存一個(gè)消息同步庫和一個(gè)存儲庫,這個(gè)實(shí)際上是一個(gè)消息同步庫,它是一個(gè)模型,我下一張PPT應(yīng)該會講用什么東西來存它。
如果我們把它理解成一個(gè)郵件,你很好理解。我們的郵件,有一個(gè)收件箱,同步庫就像一個(gè)收件箱,不管是誰發(fā)給你的郵件,群發(fā)地也好,單發(fā)的也好,反正我都給你放一份,在收件箱里面放一份,A把這個(gè)郵件放進(jìn)去了消息,你從另一個(gè)要取出來,你不管用這個(gè)手機(jī)也好用你的蘋果系統(tǒng)筆記本或者windows本也好,也都要去收這個(gè)郵件,收的過程就是什么?比如說剛才說第一蘋果系統(tǒng)筆記本,B1說我之前收了前兩封B游標(biāo),它本地有一個(gè)消息最大的,說我在2號消息,我收到了,那他把2號消息傳給服務(wù)端,服務(wù)端就說好,后邊2到20號消息都可以收走了,這樣子可以保證這個(gè)消息不重不漏地送給客戶端去。
B2說我之前這個(gè)端其實(shí)收了十封了,我就從11分開始收,B3說就收過一封,我就從第二封郵件開始收就好了,這樣子就解決了,消息就送過去了。這里有幾個(gè)問題,我們同步的過程就是理論上是可以了,但是有幾個(gè)問題,第一個(gè)就是擴(kuò)散寫擴(kuò)散讀,在這塊跟存儲很相關(guān),擴(kuò)散寫和擴(kuò)散讀有很多討論。
舉個(gè)例子:是什么地方產(chǎn)生的?比如我如果是一個(gè)單聊,我們兩個(gè)人聊天沒有問題,我肯定把消息都寫給你了。但是事實(shí)上很多時(shí)候我們是在一個(gè)群里邊聊天,給我們銷售,我們的評估師或者機(jī)器人,他們都在里邊聊,用戶也在里邊聊,這個(gè)消息我是為每人寫一份,還是我為整個(gè)會話也就是這個(gè)群,我只寫只存一份,你們都來讀。一個(gè)會話的消息,或者說你自己手里的收件箱,我先說結(jié)論,我們是在消息的同步庫里邊采用的擴(kuò)散寫,后邊還有一個(gè)存儲庫,存儲庫里邊我們是采用的擴(kuò)散讀的方式,在同步庫里邊,我們每人都寫了一份,這樣子讀的時(shí)候很方便。而在存儲的時(shí)候,由于我們的存儲速度慢一些,我們是只寫了一份數(shù)據(jù),這一個(gè)會話只有一條消息。
第二個(gè)點(diǎn)是事實(shí)上在同步過程中,我們遇到了一些問題,有很多的策略需要我們考慮。就是一個(gè)消息TimeLine,有時(shí)候不同的端有不同的同步策略,比如說有些場景下,我們要求它的每一個(gè)端都收到這一條消息,那就是我們的通知,在公司發(fā)的優(yōu)惠券什么的,每個(gè)端都要送達(dá)。有些場景人他是希望說你的手機(jī)收了,那你打開桌面,我們就不再給你送這個(gè)消息了,按照剛才這一個(gè)同步模型,有一些困難的每個(gè)端可能都會去搜這個(gè)消息,所以說我們就準(zhǔn)備了三個(gè)這樣的存儲的號。
那比如說這個(gè)圖上的B1B2B3,當(dāng)前消息的我們另外存在一個(gè)最大消息的號。第三個(gè)號你所有的里邊搜的消息最靠前的一塊就說比較像B2這樣通過這三個(gè)位置的組合,我們可以確定你收取消息的位置或者一個(gè)策略,這是這個(gè)模型,我們存儲采用什么?我們采用了Redis cluster,我們用了SortedSet結(jié)構(gòu)。

我專門把它提出來了,因?yàn)槲覀兤鋵?shí)在這還踩過一個(gè)坑,我要存這個(gè)消息了,怎么都得知道這個(gè)結(jié)構(gòu)的效率,我們查了一下SortedSet效率還可以,就說它是一個(gè)ln這樣子一個(gè)效率,所以說在同步庫,如果我們每個(gè)用戶只存一部分消息,它的性能是非常高的。這個(gè)結(jié)構(gòu)本質(zhì)上是個(gè)跳表,跳表結(jié)構(gòu)其實(shí)很復(fù)雜,我想在這會上講清楚很難,最后放了兩個(gè)圖,就是一本書。
我們知道這些結(jié)構(gòu),比如像二叉樹或者一些紅黑樹,檢索都有比較好的索引策略,跳表也類似。它比較類似什么,就像我們比如說一本書上有一千頁,我想翻到856頁怎么翻?其實(shí)我們有一種方法去前面去找索引去定位什么東西,還有我大概翻到800頁,逐步修正。跳表結(jié)構(gòu)本質(zhì)上比較像翻書,我覺得是翻到一個(gè)大的頁,先翻800頁,翻到850,在逐漸翻到860頁。

下面分享一下這塊我們遇到了一個(gè)什么問題!我們SortedSet存儲,存消息,而我們存消息為了全局一致性,用了一個(gè)思路。這個(gè)算法我們消息是一個(gè)長整型,就是上班卡,我先講的是沒關(guān)系,先講下面精度丟失的問題,我們的消息是一個(gè)長整型。這個(gè)場景下總共是64位,所以說snowflake這個(gè)算法,它的前面第一位不用,它其實(shí)表示正整數(shù)它是有意義的。用41表示一個(gè)時(shí)間區(qū)間,這里面產(chǎn)生一些ID代表了大概有六七十年或者三四十年,反正是肯定是夠用了。
中間十位是一個(gè)工作機(jī)編號,他可以支持1024個(gè)臺機(jī)器,我們現(xiàn)階段用不了這么多機(jī)器,最后的12位是一個(gè)毫秒內(nèi)的一個(gè)序號,所以說構(gòu)成了我們消息的ID因此消息是很長的一串,算下來得18位的整數(shù)。
放到SortedSet里邊之后,我們后來就發(fā)現(xiàn)一些問題,發(fā)現(xiàn)這個(gè)時(shí)間靠的近的消息,我們區(qū)分不出來它的先后順序。就這深挖下去,發(fā)現(xiàn)SortedSet它十個(gè)字實(shí)際上是個(gè)double類型的,下邊這個(gè)圖是double類型的描述,它的精度只有52位,上邊長整型它是有63位的精度,這里邊就有11位的差距。所以說在那個(gè)毫?xí)r間很接近的消息,它的精度丟失,我們檢索拉取的時(shí)候,這些順序就出了問題。

因此我們采用了一個(gè)策略,也可以借鑒一下,根據(jù)我們的當(dāng)時(shí)的負(fù)載量以及機(jī)器數(shù),這個(gè)最終保證了我們幾乎遇不到這種精度丟失的問題,就把精度主動的轉(zhuǎn)換降低了。這個(gè)case上說明就是我們選擇存儲的時(shí)候,數(shù)據(jù)類型很重要,你得根據(jù)你的業(yè)務(wù)類型看一下。
我們還在這同步的時(shí)候遇到一些問題,就是這個(gè)問題更多出現(xiàn)在我們內(nèi)部的一個(gè)工具,我們有很多的人數(shù)比較大的群,因?yàn)槲覀兊南⑾褚粋€(gè)收件箱,他的大小是有限制的,有些大群它瘋狂的刷消息,那這樣子這個(gè)群里邊可能就有成百上千上萬的消息,因?yàn)槲覀兪占浯笮∮邢拗疲覀兙蜁阎案绲南⑻蕴簦瑢?dǎo)致一些單聊比較重要的消息就丟失了,這個(gè)是我們的遇到的問題,后邊的PPT會有解決方案。
第二個(gè)問題就是還有一些web端,我們web端,其實(shí)本地的緩存是很難用的,這個(gè)就是我們用戶一打開之后,它有多少未讀數(shù),只能先通過我們把消息拉回去算一下,新拉到多少消息,才能計(jì)算出它有多少未讀數(shù)。這個(gè)實(shí)際上對我們也是一個(gè)挑戰(zhàn),很不友好。
6.3 消息的落庫存儲
接下來我們講一下存儲這塊,我們存儲消息要落庫了,我們怎么存消息?
我們剛才提到了,是按照每個(gè)會話你看到的每個(gè)人跟你聊天的一個(gè)維度來存儲。我們也是采用了分庫的策略,分庫比較簡單。
這舉個(gè)例子:事實(shí)上這個(gè)庫不止這么多個(gè),我們把一個(gè)他的消息繪畫的ID除以四,取它的模來確定它到底放到哪個(gè)庫里邊,剛才提到了我們很多ID是用snowflake算法來生成的,我們有個(gè)方法來防止它的生存不均,看一下。這是一個(gè)我們防止它的ID分布不均的一個(gè)方案。我們看到最后有一個(gè)12位的序列號,如果你不加任何干預(yù),他每次都從零開始,事實(shí)上當(dāng)你并發(fā)比較小的時(shí)候,你會發(fā)現(xiàn)它后邊都是零,就最后幾位都是你這樣子,如果都是零,你用是你用固定的取模的算法,他就絕對是不平均了。
更多有關(guān)消息ID的算法和策略,可以詳細(xì)讀讀以下文章:
《美團(tuán)技術(shù)分享:深度解密美團(tuán)的分布式ID生成算法》
《融云技術(shù)分享:解密融云IM產(chǎn)品的聊天消息ID生成策略》
比如說你的數(shù)據(jù)庫不夠了,你到時(shí)要擴(kuò)容的時(shí)候你就發(fā)現(xiàn)很困難,你不知道以前的數(shù)據(jù),你只能把以前的數(shù)據(jù)全部翻出來,簡直是災(zāi)難,所以說我們需要人為的干預(yù),我們就是用取模的方式,把分庫進(jìn)行特殊的處理,加上一些分庫的行為,在這個(gè)里邊我們用了一個(gè)ID生成的時(shí)間,給他一個(gè)最后八位的一個(gè)遮罩,他在128個(gè)數(shù)據(jù)庫的時(shí)候,它分布會很平均。

說一下怎么擴(kuò)容:剛才之前提到的最開始業(yè)務(wù)量很少,但是前幾天瓜子一天已經(jīng)賣出1萬輛的車了,所以說這個(gè)量現(xiàn)在我們是逐步的會在起來,當(dāng)成交1萬輛,用戶量是非常大的。我們怎么擴(kuò)容,這就是擴(kuò)容的基本方法。我們最初有db0123這樣幾個(gè)庫,我們看一下左邊有就是這個(gè)圖的左邊,一個(gè)msg:chatid=100和msg:chatid=104,以前chatid除以四的時(shí)候,100和104這兩個(gè)數(shù)據(jù),這兩個(gè)數(shù)據(jù)它都會并重db0這個(gè)庫。
我們分庫的時(shí)候怎么做?第一步我們把db0123這樣的庫同時(shí)進(jìn)項(xiàng),我就要主從同步,反正在搞db4567,db0和db4數(shù)據(jù)一樣的db1和db5數(shù)據(jù)也一樣,相對應(yīng)的一樣。我們把分庫策略改成除以八求余,之后的結(jié)果就出現(xiàn)什么?
我們就發(fā)現(xiàn)按照新的分庫策略,chatid104還在db0里面,chatid100它由于除了之后他就到db4了,這樣子我們就相當(dāng)于是從四個(gè)庫直接就變成了八個(gè)庫,之后的過程就是分庫規(guī)則上線之后,我們再由DBA把不屬于庫的其他數(shù)據(jù)給刪掉,這個(gè)庫的擴(kuò)容就搞定了,所以說業(yè)務(wù)可以接著跑,但是這樣子是不是就解決問題了?
其實(shí)沒有簡單,遠(yuǎn)遠(yuǎn)沒有,因?yàn)槟阆裎覀兊臄?shù)據(jù)庫前面的數(shù)據(jù)庫是MySQL,為了安全,他有一重兩重可能還有擴(kuò)庫,簡直這個(gè)數(shù)據(jù)庫越來越多,它運(yùn)維和DBA他就不干了,說你這庫越來越多,我怎么維護(hù),這個(gè)受不了了。
所以說還有一個(gè)就是這種關(guān)系型數(shù)據(jù)庫,它可以支持像事務(wù)有好多事務(wù)關(guān)聯(lián)性查詢這些非常豐富的邏輯,但事實(shí)上我們一個(gè)消息都最多的一個(gè)數(shù)據(jù)量的應(yīng)用,它用不上這么復(fù)雜,它是很簡單的,我要么根據(jù)消息ID查某一條消息,要么根據(jù)一個(gè)消息要檢索這個(gè)范圍之間的消息,真的用不上這么復(fù)雜的一些邏輯,所以說存儲用關(guān)系型數(shù)據(jù)庫并不是說特別適合,那我們就去研究了。

我們首先一查發(fā)現(xiàn)有一個(gè)時(shí)序型的數(shù)據(jù)庫是一個(gè)OpenTSDB,他的應(yīng)用場景跟這個(gè)業(yè)務(wù)很相似。OpenTSDB它內(nèi)部是用Hbase來實(shí)現(xiàn)的,我們覺得Hbase就很好。我們?yōu)槭裁催x擇Hbase?因?yàn)橛袌F(tuán)隊(duì)維護(hù),非常現(xiàn)實(shí)。選用了Hbase之后,這個(gè)接下來如果用過Hbase的同學(xué)就知道,除了我們要分片,這些做好了之后,最關(guān)鍵的是要設(shè)計(jì)Rowkey設(shè)計(jì)是需要結(jié)合業(yè)務(wù),而且需要設(shè)計(jì)得非常精妙,我們的Rowkey結(jié)果就是一個(gè)會話chatid ID,Chatid可以分散region,msgid 時(shí)間有序用于范圍檢索。
而如果我們用這個(gè)你去咨詢,你會經(jīng)常的一個(gè)場景,我打開了看到的最新的消息,我往下劃一劃才是加載更老的消息,這個(gè)結(jié)構(gòu)正好一來了之后,檢索你最新的消息,你往下滑的時(shí)候,我們就接著去查后邊的消息,這樣子非常快,而如果當(dāng)?shù)厥裁炊紱]有,你重新新裝一個(gè)非常方便,你直接來Hbase里邊查詢最新的Rowkey你就找到你最新的消息了,這個(gè)就解決了。
還有一點(diǎn)就是region,就像分庫一樣,Hbase做的比較好,它可以自己幫你維護(hù)這個(gè)分片,但是我們不建議這么搞自己維護(hù)分片,當(dāng)你像這種消息的數(shù)據(jù)它存儲量是很小的,它很小會導(dǎo)致默認(rèn)給你一個(gè)region,但是這樣一個(gè)讀寫瓶頸就來了,所以說我們需要提前規(guī)劃我們分庫的region.

下面是一些群,群有一些特殊的地方,在我們的二手車APP上,這種大規(guī)模的群比較小,但是我想分享的是我們在內(nèi)部通訊里邊群遇到的一些問題也帶上來,就一起把它跟大家交流一下。
第一個(gè)就是剛才提到的減少存儲量。這個(gè)是下面的存儲庫,比如有很多群,可能有2000多人有,如果我發(fā)一條消息就存2000份,那簡直是災(zāi)難,所以說我們只能存一份,因此我們看這個(gè)圖就是左邊的藍(lán)色之后,我們只存了一份,標(biāo)明了這個(gè)消息ID,標(biāo)明了這是哪個(gè)會話或者是哪個(gè)群的。
因?yàn)榇媪艘环荩诙€(gè)問題就帶來了:如果今天加群的人,昨天加群的人其實(shí)看到的消息應(yīng)該是不一樣的。
正常業(yè)務(wù)是這樣,有時(shí)候你還可以看到最近多少條的邏輯怎么實(shí)現(xiàn),就是我們在再給它擴(kuò)展一個(gè)數(shù)據(jù)庫表,這個(gè)表是關(guān)系型數(shù)據(jù)庫里的,記錄上群的號碼,記錄上這個(gè)人的ID,記錄上他加群的時(shí)間,加群的時(shí)間我們可以通過一個(gè)函數(shù)把它運(yùn)算。所以說msg ID的策略很重要,我們經(jīng)過加群時(shí)間,由于它是一個(gè)時(shí)間的函數(shù),我們可以跟這個(gè)加群的時(shí)間進(jìn)行一個(gè)映射關(guān)系,這樣子我通過加群時(shí)間能夠大概定位到他從哪條消息可以檢索,如果你需要去做策略,也可以說上面看多少條,下邊看多少條都可以做。第三個(gè)就是有一個(gè)會話排序的問題,這種對話的場景里邊,我們可以看到會有很多的會話,所以說這是一個(gè)策略的選擇。
第一種做法:你可以為每個(gè)人建一個(gè)會話,他每有一條消息,你就把他的最后時(shí)間更新一下,這個(gè)過程就能滿足會話的排序,但事實(shí)上我們能不能這么做?我覺得我們不能這么做,因?yàn)橛行r(shí)候消息很多,而且有些時(shí)候用戶很大,我們發(fā)一條消息。有一千個(gè)人要去更新他的狀態(tài),不管你用多少都是扛不住的,所以會話的策略,我們也是在緩存轉(zhuǎn)存會話的最后一條消息量。當(dāng)用戶要來拉取他的會話列表,或者更新他的會話列表的時(shí)候,由服務(wù)器端給他預(yù)算好了之后返回給他,我們用的時(shí)候正常情況下與客戶端它本地是可以收到消息,如果你在線他是自己知道調(diào)整這個(gè)數(shù)據(jù)的。拉取會話的行為,當(dāng)它發(fā)生離線了再次打開,這個(gè)時(shí)候需要更新一下,如果這個(gè)頻率比較低這樣一個(gè)取舍,我們的存儲模型也就出來了,所以說其他很多業(yè)務(wù)都是在發(fā)生的時(shí)候我們就跟蹤她的狀態(tài),而這個(gè)會話排序我們是在比如說讀取的時(shí)候我們才可以建立這個(gè)過程。
后邊的已讀未讀,這個(gè)點(diǎn)不再細(xì)講,沒有什么特征。我們知道緩存里為每條消息都建了一個(gè)存儲結(jié)構(gòu),說這條消息哪些人已讀哪些未讀,在比較短的時(shí)間把它淘汰。消息撤回這塊提一下,之前有個(gè)小同學(xué)這么干,這個(gè)消息怎么撤回?在關(guān)系型數(shù)據(jù)庫里邊,這個(gè)消息要撤回,我在表里邊把這條消息標(biāo)記上,這條消息是撤回來的,這個(gè)做法有沒有問題?一點(diǎn)都沒有問題。
之后他又來了個(gè)需求,說我就想看一下這些沒有撤回的消息拿出來怎么辦?這個(gè)同學(xué)也是剛畢業(yè)沒多久,就調(diào)整,就想到了建索引,他就把索引建好了,就可以這么去拉取數(shù)據(jù),結(jié)果跑一段時(shí)間數(shù)據(jù)庫報(bào)警了。這不行,怎么回事?因?yàn)槌坊氐南⒏]撤回的消息比例是失衡的非常小一間隔索引,所以毫無意義,而且還消耗了寫消息的性能,因此我們撤回消息后來兩種做法,第一是把它從這個(gè)消息庫里邊刪掉,挪到一個(gè)撤回的消息表里邊,這是顯而易見的。還有一種做法就是我們也打標(biāo)記,但是不做索引,我也不支持你過濾接受,而我是無差別的拉出來之后在存儲的邏輯層那邊把它過濾掉,這樣子做。
下邊有提到了,我們講存儲結(jié)構(gòu)不光是一個(gè)簡單的一個(gè)數(shù)據(jù)庫這樣一個(gè)簡單的概念,它其實(shí)在db到業(yè)務(wù)之間還會有一些叫做約定也好,規(guī)范也好,或者降低復(fù)雜度也好,因?yàn)槟阒苯幼寴I(yè)務(wù)去處理它是不好的,所以我們有存儲的邏輯,這樣邏輯層做一些基本的邏輯。

這里跟大家分享一下:瓜子它APP的地位還不夠高,我第一次用的時(shí)候一點(diǎn)它要登陸,因此我們要做一些匿名的策略,我們希望匿名的狀態(tài)下你已經(jīng)能建立溝通了,如果你覺得可以我們再接著聊,賣車也好,買車也好,所以說匿名就對我們這個(gè)業(yè)務(wù)帶來一個(gè)挑戰(zhàn),匿名的時(shí)候,我們可能給他分了一個(gè)ID,他聊著聊著覺得可以了,它就登錄了,登錄了之后,他實(shí)名的時(shí)候,他實(shí)名有可能是新創(chuàng)建的一個(gè),也可能他之前就登過,但是由于忘了,或者是時(shí)間久了過期了,這個(gè)時(shí)候他在這一次的業(yè)務(wù)過程當(dāng)中,他就兩個(gè)ID,如果一直讓它成為兩個(gè)ID其實(shí)對后邊的電銷人員是很郁悶的,說我們開始跟我聊了一下,過會變了個(gè)人其實(shí)是一個(gè)人,前面的業(yè)務(wù)也中斷了,所以說我們對這個(gè)消息層面我們就進(jìn)行了一個(gè)Merge,這個(gè)我們并沒有說你實(shí)名,我們就把你的數(shù)據(jù)給搬家,按照這個(gè)實(shí)名的就是匿名有一個(gè)時(shí)間序列,實(shí)名是不是也有一個(gè),我們并沒有這么搞,我們還是兩個(gè),而是在存儲中間的一個(gè)層次進(jìn)行拉取的過程,在需要Merge的時(shí)候,我們在存儲邏輯上給他Merge。
但是匿名到實(shí)名遠(yuǎn)沒有簡單,只是一個(gè)延伸,事實(shí)上你這個(gè)消息里面的匿名很好做,但是你的業(yè)務(wù)匿名到實(shí)名很難,還有我們經(jīng)常遇到這個(gè)問題,機(jī)器人給他發(fā)了一個(gè)東西,匿名狀態(tài),后來他登陸了,他一打開,拉回去了之后,這個(gè)消息還在他那里,他變成實(shí)名了。他進(jìn)行操作,這個(gè)時(shí)候業(yè)務(wù)的匿名到實(shí)名其實(shí)是更難的,如果有做這樣想法的,提前想好,更多的是業(yè)務(wù)層面的理論都是。

這個(gè)是消息的最后一部分了,實(shí)際上還會遇到一些問題,事實(shí)上消息同步是非常復(fù)雜的一個(gè)事情,我們后來越做越覺得它復(fù)雜。這個(gè)有些人會出現(xiàn)一個(gè)什么情況,比如說我用A手機(jī)收了幾條消息,我在B手機(jī)上又收了幾條消息,過一段時(shí)間我在A手機(jī)上又來收幾條消息。
你看剛才那種模型就會導(dǎo)致中間出現(xiàn)很多斷層,中間出現(xiàn)了很多,就像Client右邊這個(gè)圖,就345的消息他并沒有收到,但是服務(wù)端其實(shí)是所有消息都有的。這時(shí)候我們做了一些策略,我們?yōu)槊總€(gè)消息嚴(yán)格的編號,msg index:1,2,3,每個(gè)消息嚴(yán)格的編號。如果是這樣子,客戶端知道了之后,他就知道我原來少了345這三個(gè)號對不對?我就可以到服務(wù)端去說,我缺345這幾個(gè)消息,你給我解索出來。
有沒有這么容易?客戶端可能覺得這個(gè)是很容易的,但是到了服務(wù)端事情不是這么回事,345是你自己編的一個(gè)號,而我們的消息之前說了snowflake這樣一個(gè)唯一的編號,那你拿著345并不能找到你到底是哪個(gè)消息ID,所以說我是不是服務(wù)端要用哪個(gè)消息建立這么一個(gè)索引,還是應(yīng)該是一個(gè)編號到msg ID索引?
可以做,但是存儲量工作量非常的大,那我們怎么干?
我們在邏輯層里邊做了一些事情,服務(wù)端每次返回客戶端的消息,我們把這個(gè)消息把它做成一個(gè)鏈表的結(jié)構(gòu),當(dāng)你來拉取,因?yàn)槭欠聪蛳⒑枚嗍前?拉去2號消息的時(shí)候,我就說,這個(gè)我告訴你,你的下一條消息是msg7,你拉取,也可以一段一段拉取沒關(guān)系。你拉到msg6的時(shí)候,我告訴你說你的消息msg5,我客戶端說原來少這個(gè)消息5,這樣子客戶端可以通過這個(gè)消息ID到服務(wù)端來檢索消息,由于是消息ID不管我們是OK也好,或者我們的關(guān)系型數(shù)據(jù)庫是基于索引也好,都很容易做,現(xiàn)成的,也不需要再維護(hù)其他的索引關(guān)系。所以說這也是一個(gè)策略的點(diǎn)。這種斷層我們就解決了。
但是還有問題,有時(shí)候消息非常多,如果你一次都把這些就是我們剛才說的同步庫的消息收過去,過程其實(shí)是很慢的,尤其在深度用戶的時(shí)候這個(gè)方案不好。
有一種做法:你把這個(gè)消息壓縮一下送過去,簡直傳遞。但是其實(shí)還是不好,客戶端要渲染,要計(jì)算數(shù)量很慢,這就是剛才提到的擴(kuò)散讀和擴(kuò)散寫的問題,最早有一個(gè),所以說后來更好的辦法是說同步庫里邊也并不是去同步的具體的消息,你可以去做這個(gè)用戶有哪些變更的會話,這么一個(gè)會話,它有多少未接收的數(shù)據(jù),記錄好這個(gè)數(shù)字有多少未讀。這樣客戶端可以把這些數(shù)據(jù)拉到本地,你看到了有多少未讀的會話之后,你點(diǎn)進(jìn)去的時(shí)候,你再照這個(gè)存儲庫里邊反向的通過這個(gè)來拉取你的消息,再加上我們剛才說的中間空蕩的一個(gè)補(bǔ)齊的策略,一個(gè)列表補(bǔ)齊的策略,這樣的體驗(yàn)非常好。
所以說我們就解決了我們這個(gè)項(xiàng)目,我們就解決了消息的問題。后邊我們看一下消息解決了還沒有完,我們要推廣這個(gè)項(xiàng)目,我們要落地,需要做業(yè)務(wù),因?yàn)橹皇莻饕粋€(gè)消息沒有意義,對觀眾來說我們就在做業(yè)務(wù)了,我們承載業(yè)務(wù)的就是叫我們的業(yè)務(wù)卡片,最初那個(gè)圖里邊我們看到的那些傳過去可以直接操作的這個(gè)東西,應(yīng)該我們還申請了專利,當(dāng)時(shí)去查了一下沒人這么搞的,但是由于沒人這么搞,其實(shí)我們在實(shí)施過程中遇到一些問題,下面我們看一下這個(gè)圖。

這個(gè)圖右邊有一個(gè)卡片的代理,右圖有個(gè)綠色的卡片代理是我們對這個(gè)業(yè)務(wù)設(shè)置的一個(gè)特殊的東西,我們在推廣的時(shí)候遇到很多問題,我們這些業(yè)務(wù)原有的業(yè)務(wù)部門,他們都做得有接口是現(xiàn)成的,由于你把它搬到了IM交互里面有幾種方法:第一你們?nèi)拷o我改一下,這個(gè)是很困難,有些業(yè)務(wù)說他不愿意,我們就設(shè)計(jì)了這么一個(gè)代理的產(chǎn)出的卡片的所有響應(yīng)試點(diǎn),先打到我們的一個(gè)代理模塊,代理模塊再去適配你原有的業(yè)務(wù)邏輯,這樣子代理模塊,知道用戶操作行為到底是什么樣,成沒成功,成功了或者沒成功,他再通過調(diào)度,通過他們的通道通知相關(guān)業(yè)務(wù)的各方結(jié)果,這是一種策略。
同時(shí)它要高可靠,比如說我們預(yù)約看車就相當(dāng)于下班了,就相當(dāng)于這個(gè)是很重要的業(yè)務(wù)。你這個(gè)不行,鏈條太長了,風(fēng)險(xiǎn)太高,寧可我們加點(diǎn)東西都可以,那就是左邊這個(gè)邏輯,這業(yè)務(wù)服務(wù)愿意說我自己改一下,可控性我得自己把控,不能說因?yàn)橥ㄓ嵱袉栴},我的業(yè)務(wù)就不跑了。那就是他改一下,來觸發(fā)調(diào)度的一些邏輯。這個(gè)是我們在整個(gè)推廣的過程當(dāng)中最重要的一個(gè)策略,實(shí)際上也是探索出來的,因?yàn)椴还馐且粋€(gè)技術(shù)問題,還是個(gè)組織結(jié)構(gòu)問題。

簡單提一下調(diào)度問題,因?yàn)椴皇侵攸c(diǎn),你怎么知道到底是哪個(gè)客戶來服務(wù)你?我們提出了一個(gè)場景的概念,就是你每次從各種入口進(jìn)到對話界面的時(shí)候,這些入口我們是有狀態(tài)的。A入口B入口,比如你約車還是砍價(jià)什么之類的,我們它先把這個(gè)場景到調(diào)度去注冊一下,說我從這兒進(jìn)來,同時(shí)調(diào)度會有一些大數(shù)據(jù)來支撐,原來你是誰誰,你就從這個(gè)場景進(jìn)來,我們認(rèn)為你可能是要干什么事情。這樣給他返回場景里,他再次跟通道間發(fā)生關(guān)系的時(shí)候,帶上這個(gè)場景,我們這個(gè)調(diào)度就知道把你推給具體的誰,是銷售也好,機(jī)器人也好,是我們具體的解決投訴的客服或者解決什么電銷的客服了。
6.4 分析統(tǒng)計(jì)
接下來再提一下分析統(tǒng)計(jì),像瓜子的規(guī)模已經(jīng)比較大了,我們現(xiàn)在有超過一千個(gè)研發(fā)團(tuán)隊(duì),但是在大數(shù)據(jù)這塊投入也比較多,但是事實(shí)上現(xiàn)在公司都是數(shù)據(jù)驅(qū)動化,這個(gè)團(tuán)隊(duì)的力量依然是很有限的,它支持各種各樣的業(yè)務(wù)線,非常吃力的還是很忙,所以我們在分析統(tǒng)計(jì)有兩塊,第一塊是T+1的分析是離線的,還有一塊是實(shí)時(shí)的一個(gè)分析。

我們這個(gè)項(xiàng)目于對實(shí)時(shí)統(tǒng)計(jì)的要求很高,比如及時(shí)回復(fù)率這些各種各樣的統(tǒng)計(jì)要求實(shí)時(shí)的監(jiān)控報(bào)警,怎么做呢?這是我們整個(gè)系統(tǒng)另一個(gè)角度的一個(gè)架構(gòu),和我們一些跟消息相關(guān)的或跟一些業(yè)務(wù)調(diào)度相關(guān)的,我們都走了一個(gè)kafka,就是通道的以及送給客服的一些銷售評估師等等,他們業(yè)務(wù)線的這些邏輯,我們通過kafka傳遞一些比較多的數(shù)據(jù)。我們在想能不能用借用kafka來簡單的實(shí)現(xiàn)技術(shù),事實(shí)上是可以,這概念是一個(gè)流式數(shù)據(jù)庫,我們最初的結(jié)構(gòu)就是圖左邊這一塊,整個(gè)系統(tǒng)中間走的消息都通過了一個(gè)kafka.

我們可以保證業(yè)務(wù)在上面跑,其次kafka它緩存的這段數(shù)據(jù),我們是可以對他進(jìn)行流式計(jì)算,我們整體的架構(gòu)是上圖這樣。
7、最后
我簡單重復(fù)一下我們的過程:
第一:我們這個(gè)系統(tǒng)通過數(shù)據(jù)層面展示了一個(gè)通訊,就是即時(shí)通訊的這樣一個(gè)系統(tǒng),大概是怎么做的,數(shù)據(jù)庫怎么存的;
第二:是把我們通訊的能力應(yīng)用到業(yè)務(wù)系統(tǒng),我們解決了技術(shù)上或者組織上遇到了一些什么困難;
第三:是我們找一個(gè)比較簡單的方法,處理我們的一些離線計(jì)算,當(dāng)然他做T+1也是可以的。
謝謝大家。
附錄:更多有關(guān)IM架構(gòu)設(shè)計(jì)的文章
《淺談IM系統(tǒng)的架構(gòu)設(shè)計(jì)》
《簡述移動端IM開發(fā)的那些坑:架構(gòu)設(shè)計(jì)、通信協(xié)議和客戶端》
《一套海量在線用戶的移動端IM架構(gòu)設(shè)計(jì)實(shí)踐分享(含詳細(xì)圖文)》
《一套原創(chuàng)分布式即時(shí)通訊(IM)系統(tǒng)理論架構(gòu)方案》
《從零到卓越:京東客服即時(shí)通訊系統(tǒng)的技術(shù)架構(gòu)演進(jìn)歷程》
《蘑菇街即時(shí)通訊/IM服務(wù)器開發(fā)之架構(gòu)選擇》
《騰訊QQ1.4億在線用戶的技術(shù)挑戰(zhàn)和架構(gòu)演進(jìn)之路PPT》
《微信后臺基于時(shí)間序的海量數(shù)據(jù)冷熱分級架構(gòu)設(shè)計(jì)實(shí)踐》
《微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(演講全文)》
《如何解讀《微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡》》
《快速裂變:見證微信強(qiáng)大后臺架構(gòu)從0到1的演進(jìn)歷程(一)》
《17年的實(shí)踐:騰訊海量產(chǎn)品的技術(shù)方法論》
《移動端IM中大規(guī)模群消息的推送如何保證效率、實(shí)時(shí)性?》
《現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲方案探討》
《IM開發(fā)基礎(chǔ)知識補(bǔ)課(二):如何設(shè)計(jì)大量圖片文件的服務(wù)端存儲架構(gòu)?》
《IM開發(fā)基礎(chǔ)知識補(bǔ)課(三):快速理解服務(wù)端數(shù)據(jù)庫讀寫分離原理及實(shí)踐建議》
《IM開發(fā)基礎(chǔ)知識補(bǔ)課(四):正確理解HTTP短連接中的Cookie、Session和Token》
《WhatsApp技術(shù)實(shí)踐分享:32人工程團(tuán)隊(duì)創(chuàng)造的技術(shù)神話》
《微信朋友圈千億訪問量背后的技術(shù)挑戰(zhàn)和實(shí)踐總結(jié)》
《王者榮耀2億用戶量的背后:產(chǎn)品定位、技術(shù)架構(gòu)、網(wǎng)絡(luò)方案等》
《IM系統(tǒng)的MQ消息中間件選型:Kafka還是RabbitMQ?》
《騰訊資深架構(gòu)師干貨總結(jié):一文讀懂大型分布式系統(tǒng)設(shè)計(jì)的方方面面》
《以微博類應(yīng)用場景為例,總結(jié)海量社交系統(tǒng)的架構(gòu)設(shè)計(jì)步驟》
《快速理解高性能HTTP服務(wù)端的負(fù)載均衡技術(shù)原理》
《子彈短信光鮮的背后:網(wǎng)易云信首席架構(gòu)師分享億級IM平臺的技術(shù)實(shí)踐》
《知乎技術(shù)分享:從單機(jī)到2000萬QPS并發(fā)的Redis高性能緩存實(shí)踐之路》
《IM開發(fā)基礎(chǔ)知識補(bǔ)課(五):通俗易懂,正確理解并用好MQ消息隊(duì)列》
《微信技術(shù)分享:微信的海量IM聊天消息序列號生成實(shí)踐(算法原理篇)》
《微信技術(shù)分享:微信的海量IM聊天消息序列號生成實(shí)踐(容災(zāi)方案篇)》
《新手入門:零基礎(chǔ)理解大型分布式架構(gòu)的演進(jìn)歷史、技術(shù)原理、最佳實(shí)踐》
《一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計(jì)實(shí)踐》
《阿里技術(shù)分享:深度揭秘阿里數(shù)據(jù)庫技術(shù)方案的10年變遷史》
《阿里技術(shù)分享:阿里自研金融級數(shù)據(jù)庫OceanBase的艱辛成長之路》
《社交軟件紅包技術(shù)解密(一):全面解密QQ紅包技術(shù)方案——架構(gòu)、技術(shù)實(shí)現(xiàn)等》
《社交軟件紅包技術(shù)解密(二):解密微信搖一搖紅包從0到1的技術(shù)演進(jìn)》
《社交軟件紅包技術(shù)解密(三):微信搖一搖紅包雨背后的技術(shù)細(xì)節(jié)》
《社交軟件紅包技術(shù)解密(四):微信紅包系統(tǒng)是如何應(yīng)對高并發(fā)的》
《社交軟件紅包技術(shù)解密(五):微信紅包系統(tǒng)是如何實(shí)現(xiàn)高可用性的》
《社交軟件紅包技術(shù)解密(六):微信紅包系統(tǒng)的存儲層架構(gòu)演進(jìn)實(shí)踐》
《社交軟件紅包技術(shù)解密(七):支付寶紅包的海量高并發(fā)技術(shù)實(shí)踐》
《社交軟件紅包技術(shù)解密(八):全面解密微博紅包技術(shù)方案》
《社交軟件紅包技術(shù)解密(九):談?wù)勈諵紅包的功能邏輯、容災(zāi)、運(yùn)維、架構(gòu)等》
《即時(shí)通訊新手入門:一文讀懂什么是Nginx?它能否實(shí)現(xiàn)IM的負(fù)載均衡?》
《即時(shí)通訊新手入門:快速理解RPC技術(shù)——基本概念、原理和用途》
《多維度對比5款主流分布式MQ消息隊(duì)列,媽媽再也不擔(dān)心我的技術(shù)選型了》
《從游擊隊(duì)到正規(guī)軍(一):馬蜂窩旅游網(wǎng)的IM系統(tǒng)架構(gòu)演進(jìn)之路》
《從游擊隊(duì)到正規(guī)軍(二):馬蜂窩旅游網(wǎng)的IM客戶端架構(gòu)演進(jìn)和實(shí)踐總結(jié)》
《IM開發(fā)基礎(chǔ)知識補(bǔ)課(六):數(shù)據(jù)庫用NoSQL還是SQL?讀這篇就夠了!》
《瓜子IM智能客服系統(tǒng)的數(shù)據(jù)架構(gòu)設(shè)計(jì)(整理自現(xiàn)場演講,有配套PPT)》
>> 更多同類文章 ……
(本文同步發(fā)布于:http://www.52im.net/thread-2807-1-1.html)
作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
出處:http://www.52im.net/space-uid-1.html
交流:歡迎加入即時(shí)通訊開發(fā)交流群 215891622
討論:http://www.52im.net/
Jack Jiang同時(shí)是【原創(chuàng)Java
Swing外觀工程BeautyEye】和【輕量級移動端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
本博文
歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處(也可前往 我的52im.net 找到我)。