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

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

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

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

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

這是截了幾個(gè)圖,我們看第一個(gè)圖,我們上邊就有一個(gè)車,下邊有個(gè)預(yù)約,用戶事實(shí)上是可以直接在聊天界面里面去點(diǎn)預(yù)約了。這個(gè)就是我說(shuō)的跟一般的客服不一樣的,它可以做一些叫做導(dǎo)購(gòu)或者叫營(yíng)銷也好,直接通過(guò)這樣一個(gè)途徑,因?yàn)楣献拥墨@客成本很高,每個(gè)訪問(wèn)瓜子的用戶我們都希望及時(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è),除此之外有些員工用的,比如說(shuō)電銷的、客服的、售后的、金融的、我們可能都是一些APP或者是一些桌面系統(tǒng),這是我們的客戶端。
第二是一個(gè)路由層,我們要打通這些業(yè)務(wù)。要讓這些業(yè)務(wù)在這個(gè)系統(tǒng)里邊及時(shí)的傳遞,所謂傳遞剛才前面有個(gè)圖案,比如說(shuō)你想約車了,那客服就給你或者電銷就給你發(fā)一個(gè)約車的卡片,你就可以直接選時(shí)間約,這是傳遞業(yè)務(wù)。再往下邊是一些業(yè)務(wù)層,那就是原來(lái)瓜子有很多有什么業(yè)務(wù)就涉及什么業(yè)務(wù),最底下是一個(gè)存儲(chǔ)。這次后邊主要講的就是站在存儲(chǔ)層的角度來(lái)看整個(gè)系統(tǒng),重點(diǎn)會(huì)講存儲(chǔ)層怎么對(duì)路由層進(jìn)行支持。
6、存儲(chǔ)架構(gòu)
存儲(chǔ)這塊會(huì)講大概幾個(gè)點(diǎn),包括:
1)數(shù)據(jù)庫(kù)的拆分;
2)消息怎么存,消息里邊也會(huì)特別提一下群的模型,大規(guī)模的群是比較麻煩的;
3)還有一些存儲(chǔ)邏輯以及業(yè)務(wù)怎么在上邊run起來(lái);
4)最后是統(tǒng)計(jì)分析,實(shí)時(shí)計(jì)算這樣一些設(shè)備。
6.1 數(shù)據(jù)庫(kù)的拆分

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

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

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

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

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

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

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

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

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

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

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

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

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

我們這個(gè)項(xiàng)目于對(duì)實(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,就是通道的以及送給客服的一些銷售評(píng)估師等等,他們業(yè)務(wù)線的這些邏輯,我們通過(guò)kafka傳遞一些比較多的數(shù)據(jù)。我們?cè)谙肽懿荒苡媒栌胟afka來(lái)簡(jiǎn)單的實(shí)現(xiàn)技術(shù),事實(shí)上是可以,這概念是一個(gè)流式數(shù)據(jù)庫(kù),我們最初的結(jié)構(gòu)就是圖左邊這一塊,整個(gè)系統(tǒng)中間走的消息都通過(guò)了一個(gè)kafka.

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