阿里IM技術(shù)分享(十):深度揭密釘釘后端架構(gòu)的單元化演進(jìn)之路
本文由釘釘技術(shù)專家嘯臺(tái)、萬泓分享,為了獲得更好的閱讀效果,本文已對(duì)內(nèi)容進(jìn)行少修訂和重新排版。
1、引言
釘釘后端架構(gòu)的單元化工作從2018年開始到今年,已經(jīng)是第五個(gè)年頭了。五年的時(shí)間,釘釘單元化迭代了三個(gè)版本,從最初的毛頭小子,到達(dá)今年已經(jīng)小有成就。
我們?cè)谶M(jìn)行單元化架構(gòu)建設(shè)的過程中,除了網(wǎng)上能找到的屈指可數(shù)的文章外,可以直接使用的系統(tǒng)更是乏善可陳,使我們不得不從最基礎(chǔ)的系統(tǒng)開始造輪子,極大的影響建設(shè)效率。幸運(yùn)的是,近幾年云原生技術(shù)的興起,讓我們能復(fù)用很多基礎(chǔ)設(shè)施,進(jìn)而快速提升我們的單元化建設(shè)能力,助力釘釘?shù)陌l(fā)展。
今天想借此文和大家分享我們?cè)卺斸攩卧軜?gòu)實(shí)施過程中的心路歷程和一些最佳實(shí)踐。因涉及的技術(shù)和業(yè)務(wù)面太廣,本文的分享無法做到面面俱到,主要是想在同路人中形成共鳴,進(jìn)而能復(fù)用一些架構(gòu)或子系統(tǒng)的設(shè)計(jì)和實(shí)現(xiàn)思路。

學(xué)習(xí)交流:
- 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM》
- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點(diǎn)此)
(本文同步發(fā)布于:http://www.52im.net/thread-4122-1-1.html)
2、系列文章
本文是系列文章的第?10?篇,總目錄如下:
《阿里IM技術(shù)分享(一):企業(yè)級(jí)IM王者——釘釘在后端架構(gòu)上的過人之處》
《阿里IM技術(shù)分享(二):閑魚IM基于Flutter的移動(dòng)端跨端改造實(shí)踐》
《阿里IM技術(shù)分享(三):閑魚億級(jí)IM消息系統(tǒng)的架構(gòu)演進(jìn)之路》
《阿里IM技術(shù)分享(四):閑魚億級(jí)IM消息系統(tǒng)的可靠投遞優(yōu)化實(shí)踐》
《阿里IM技術(shù)分享(五):閑魚億級(jí)IM消息系統(tǒng)的及時(shí)性優(yōu)化實(shí)踐》
《阿里IM技術(shù)分享(六):閑魚億級(jí)IM消息系統(tǒng)的離線推送到達(dá)率優(yōu)化》
《阿里IM技術(shù)分享(七):閑魚IM的在線、離線聊天數(shù)據(jù)同步機(jī)制優(yōu)化實(shí)踐》
《阿里IM技術(shù)分享(八):深度解密釘釘即時(shí)消息服務(wù)DTIM的技術(shù)設(shè)計(jì)》
《阿里IM技術(shù)分享(九):深度揭密RocketMQ在釘釘IM系統(tǒng)中的應(yīng)用實(shí)踐》
《阿里IM技術(shù)分享(十):深度揭密釘釘后端架構(gòu)的單元化演進(jìn)之路》(* 本文)
3、術(shù)語概念
本文內(nèi)容中使用了一些專有的技術(shù)名詞,為了方便大家理解,我把關(guān)鍵的幾個(gè)術(shù)語概念的縮寫及其含義專門列出來,供大家參考。
主要是以下幾個(gè):
1)Geo:釘釘專有化部署單位,解決數(shù)據(jù)合規(guī)需求,Geo間數(shù)據(jù)按需互通,并且互通數(shù)據(jù)在Geo內(nèi)部做鏡像拷貝,解決兩化問題;
2)Unit: Geo內(nèi)部資源物理分區(qū)隔離的最小單位,解決Geo內(nèi)的容災(zāi)和容量的問題;
3)L0:客戶端路由,決定了用戶客戶端接入釘釘服務(wù)器的所屬單元,用戶長(zhǎng)連接所在的邏輯單元,起到連接加速作用。用戶接入單元;
4)L1:接入層路由,以用戶為維度進(jìn)行調(diào)度,即用戶操作發(fā)生的單元。用戶歸屬單元;
5)L2:業(yè)務(wù)層路由,以業(yè)務(wù)資源為維度進(jìn)行調(diào)度,大部分的業(yè)務(wù)資源所在單元應(yīng)該和用戶調(diào)度單元一致,但一些業(yè)務(wù)無法按照用戶劃分單元,如IM的會(huì)話,音視頻的會(huì)議。 業(yè)務(wù)歸屬單元;
6)DMB:負(fù)責(zé)釘釘應(yīng)用跨單元RPC調(diào)用的轉(zhuǎn)發(fā),可以認(rèn)為是釘釘單元化RPC路由中間件;
7)DMR:負(fù)責(zé)釘釘應(yīng)用跨單元MQ消息的轉(zhuǎn)發(fā),可以認(rèn)為是釘釘單元化MQ路由中間件;
8)DTIM:釘釘IM系統(tǒng)。
4、單元化架構(gòu)1.0版:合規(guī)驅(qū)動(dòng)下的部署架構(gòu)
2018年,部分大客戶出于法律政策、商業(yè)機(jī)密數(shù)據(jù)存儲(chǔ)的要求,要求釘釘?shù)臄?shù)據(jù)存儲(chǔ)、訪問接入、服務(wù)部署需要在其信任的區(qū)域內(nèi)。既需要滿足其數(shù)據(jù)存儲(chǔ)私有化要求,同時(shí)需要滿足跨地區(qū)網(wǎng)絡(luò)的rt性能要求。
于是我們結(jié)合阿里云機(jī)房部署位置、物理距離、用戶數(shù)據(jù)安全等方面出發(fā),釘釘在客戶的阿里云機(jī)房?jī)?nèi)建設(shè)了一個(gè)單元,將通訊錄、IM信息等企業(yè)數(shù)據(jù)單獨(dú)存儲(chǔ)在客戶機(jī)房。

我們通過一條專線,將兩個(gè)機(jī)房邏輯串聯(lián)到一起,內(nèi)部通過DMB/DMR系統(tǒng),實(shí)現(xiàn)了請(qǐng)求互通,這就是釘釘單元化架構(gòu)的1.0版。
1.0版比較簡(jiǎn)單,純粹是業(yè)務(wù)驅(qū)動(dòng),和支付寶單元化建設(shè)的初衷——“容災(zāi)驅(qū)動(dòng)”有較大區(qū)別。兩個(gè)站點(diǎn)通過UID分段,將用戶劃分為中心用戶和專有用戶。
上圖只是一個(gè)簡(jiǎn)化的邏輯結(jié)構(gòu),內(nèi)部實(shí)現(xiàn)遠(yuǎn)比上圖復(fù)雜,但是1.0建設(shè)主要是從0到1,和大多數(shù)異地多活的系統(tǒng)較相似,這里就只簡(jiǎn)單的和大家分享一下。
5、單元化架構(gòu)2.0版:逼出來的容量架構(gòu)
2020年是一個(gè)特殊的年份,由于疫情的原因,帶給大家非常多的改變,其中也包括釘釘。
由于在線辦公與教育流量的突增,開年第一天上班就給釘釘一個(gè)下馬威,平峰的流量已經(jīng)和除夕跨年的持平,但是和除夕不同的是這個(gè)流量是持續(xù)的,即使節(jié)前準(zhǔn)備了三倍容量,也抵擋不住流量對(duì)系統(tǒng)的沖擊。只能借助阿里云的能力,不斷的擴(kuò)容。

但是每天將近30%的流量增幅,單純的擴(kuò)容也能難保障服務(wù)的連續(xù)性,最終也遇到了擴(kuò)無可擴(kuò)的場(chǎng)景,張北機(jī)房沒有機(jī)位了,有機(jī)器資源但是沒有機(jī)位讓我們有力無處使。我們不得不不斷進(jìn)行系統(tǒng)優(yōu)化,同時(shí)借助限流、降級(jí)、雙推等措施,勉強(qiáng)抗住了流量的最高峰。
疫情之前,我們一直在做高可用,但是這個(gè)高可用主要集中在容災(zāi)機(jī)制上,比如搭建容災(zāi)單元。如同支付寶一樣,是因?yàn)楫?dāng)時(shí)光纖被挖斷;又比如銀行的兩地三中心架構(gòu),是擔(dān)心某一個(gè)地域由于天災(zāi)或者戰(zhàn)爭(zhēng)導(dǎo)致數(shù)據(jù)丟失。疫情的流量給我們上了一課,僅僅關(guān)注容災(zāi)是不夠的,特別是釘釘?shù)腄AU從千萬走向億級(jí)別之后,更需要在容量上做出提前規(guī)劃。
正因如此,我們認(rèn)為“容量架構(gòu)不是設(shè)計(jì)出來而是真真切切被逼出來的”,所以容量架構(gòu)就成為我們單元化核心要素之一。
容量架構(gòu)是將流量劃分到不同單元,每個(gè)單元承載各自的流量。容災(zāi)架構(gòu)是單元異常時(shí),能保障核心的能力可用,也可以將流量動(dòng)態(tài)調(diào)度到別的單元,實(shí)現(xiàn)服務(wù)的快速恢復(fù)。
因此釘釘單元化進(jìn)入了2.0時(shí)代,專注于容量和容災(zāi)的建設(shè)。

6、2.0版是基于什么維度進(jìn)行流量劃分的?
要實(shí)現(xiàn)流量的劃分,必然要基于一個(gè)維度進(jìn)行劃分,一部分到A單元,一部分到B單元。
釘釘單元化架構(gòu)也是參考了淘系和支付寶的單元化架構(gòu),前兩者都是基于UID劃分,釘釘單元化的第一個(gè)版本其實(shí)也是一樣的,基于UID做拆分。
但是當(dāng)我們?cè)O(shè)計(jì)容量架構(gòu)時(shí),發(fā)現(xiàn)基于UID劃分無法解決我們的容量問題。
以IM為例:一條消息其實(shí)屬于聊天雙方的,群聊亦是如此。用戶能和任意一個(gè)人聊天,這樣我們根本無法找到一個(gè)切入點(diǎn)來劃分流量,強(qiáng)行按照UID拆分,必然導(dǎo)致一個(gè)用戶的消息出現(xiàn)在N個(gè)單元,單元的自封閉就無法做了。
也有同學(xué)會(huì)說:為什么消息不按照每個(gè)人存儲(chǔ),這不就能按照UID劃分了嗎?結(jié)論是不行。首先這個(gè)消息變成了寫擴(kuò)散,持久化的時(shí)候會(huì)變成多單元寫,其次是成本翻倍,在DTIM這種過億規(guī)模的場(chǎng)景這條路走不通。這里可以多說一點(diǎn),因?yàn)檫@個(gè)觀點(diǎn)來之不易,大家都知道,人是有慣性的,既然淘寶、支付寶甚至是微信都是UID劃分,為什么釘釘要特立獨(dú)行?當(dāng)時(shí)我們團(tuán)隊(duì)受到了絕大部分釘釘技術(shù)團(tuán)隊(duì)的挑戰(zhàn),持續(xù)長(zhǎng)達(dá)將近一個(gè)月的技術(shù)選型的“爭(zhēng)吵”,最終還是達(dá)成了一致意見。
DTIM主要有3個(gè)維度,分別是UID、會(huì)話(CID)、消息。其中會(huì)話和消息是綁定的,而系統(tǒng)中最大量的是消息,按照第一性原則來看,一定要將消息劃分開來,才能做到將容量劃分開來的效果。
我們?cè)賮砜纯匆粢曨l,是按照房間維度組織流量和數(shù)據(jù)的,和IM又完全不同。
同樣,文檔其實(shí)更適合按照企業(yè)維度來劃分。
不同的業(yè)務(wù)擁有不同的維度,因此我們認(rèn)為:單元化最重要的找到自身“最大”的業(yè)務(wù)維度,將這個(gè)維護(hù)拆分,才能實(shí)現(xiàn)單元的橫向擴(kuò)展,我們稱之為“業(yè)務(wù)路由”。
回頭來看:我們之前其實(shí)是進(jìn)入了思考誤區(qū),以為淘系和支付寶都是UID維度,我們也要這個(gè)維度,其實(shí)UID正是前者的業(yè)務(wù)維度,比如訂單,也是圍繞用戶,并不會(huì)有交集的情況,會(huì)話就是IM的劃分維度,因此做單元化之前要先找到屬于自己的業(yè)務(wù)維度。
7、2.0版是如何實(shí)現(xiàn)IM消息的全局路由能力的?
7.1概述
UID路由有個(gè)最大的好處,就是可以按照UID分段,能實(shí)現(xiàn)高效的靜態(tài)路由,也不用擔(dān)心多單元之間的一致性問題。但是這種分段路由局限性也比較明顯,需要預(yù)先分配,單元之間動(dòng)態(tài)調(diào)度流量和數(shù)據(jù)成本極高,而且只能支持這種數(shù)值+順序的場(chǎng)景。
在釘釘?shù)膱?chǎng)景中,有會(huì)話維度、房間維度、企業(yè)維度等等,想簡(jiǎn)單采用這種預(yù)分段機(jī)制難以滿足業(yè)務(wù)需求。因此我們需要構(gòu)建一個(gè)業(yè)務(wù)路由系統(tǒng)(RoutingService),實(shí)現(xiàn)消息流量的精確路由。
?

?以IM為例:每次消息的發(fā)送,在單元化框架層面,會(huì)通過消息的會(huì)話(CID),查詢路由信息,如果是本單元,流量下行并持久化;如果是非本單元,路由到對(duì)應(yīng)的單元中。
下圖是三個(gè)會(huì)話:分別是cid:1001、cid:1002、cid:1003,三個(gè)會(huì)話隸屬不同單元,不管用戶從哪個(gè)單元發(fā)送消息,都會(huì)路由到會(huì)話所在的單元。比如:用戶在Unit B的cid:1001 中發(fā)送消息,當(dāng)消息進(jìn)入Receiver之后,會(huì)先查詢此cid:1001所在的單元,發(fā)現(xiàn)是Unit A,路由框架將請(qǐng)求轉(zhuǎn)到A單元,消息在A單元持久化并通過A單元的同步協(xié)議,將數(shù)據(jù)推送到客戶端。

?
?

?從上圖可知:每次消息發(fā)送,都要查詢路由服務(wù),DTIM百萬的峰值,對(duì)路由必然會(huì)帶來超大的壓力,同時(shí)我們能發(fā)現(xiàn),路由數(shù)據(jù)在多單元實(shí)現(xiàn)一致性是一個(gè)巨大的挑戰(zhàn)。
7.2邊緣計(jì)算:端到端路由
在DTIM的場(chǎng)景中,會(huì)話的路由信息幾乎不會(huì)變更,只有當(dāng)我們決定將某些超大的會(huì)話或者企業(yè)騰挪到新單元時(shí),才會(huì)發(fā)起路由的變更,因此會(huì)話的路由信息幾乎可以認(rèn)為是恒定不變的。那么每次查詢路由服務(wù)端,效費(fèi)比太低,是極大的浪費(fèi)。
既然路由信息幾乎不可變,是否將路由信息緩存呢?最常見的是使用一個(gè)集中式的Cache系統(tǒng),緩存Hot的會(huì)話,我們也是這么做的,但是這么做還是不夠,一旦Cache系統(tǒng)失效,DTIM還是會(huì)出現(xiàn)大面積故障,而且這個(gè)百萬級(jí)的請(qǐng)求對(duì)Cache也是一個(gè)極大的壓力。
考慮到釘釘有強(qiáng)大的客戶端,借用邊緣計(jì)算的思路,我們將用戶的會(huì)話數(shù)據(jù)緩存到客戶端。對(duì)于客戶端來說,也只用緩存用戶自身最熱的N會(huì)話路由數(shù)據(jù),消息發(fā)送時(shí),通過Header將路由數(shù)據(jù)攜帶到服務(wù)端,服務(wù)端路由SDK只要做合法性和續(xù)約即可,這樣就將路由流量降低了95%以上。當(dāng)路由服務(wù)出現(xiàn)異常時(shí),還可以繼續(xù)使用客戶端路由,將路由的可用性提升到一個(gè)新的高度。
SDK本地會(huì)依據(jù)上行請(qǐng)求的返回中是否有新的路由信息,進(jìn)而更新客戶端路由。同時(shí)可以借助釘釘有主動(dòng)下推的能力,通過同步協(xié)議將新的路由信息主動(dòng)推送給客戶端,使會(huì)話遷移做到更平順。

7.3計(jì)算下沉:多單元一致性
對(duì)于新會(huì)話:比如小明要?jiǎng)?chuàng)建一個(gè)群聊,是應(yīng)該創(chuàng)建在那個(gè)單元呢?
如果在A單元?jiǎng)?chuàng)建了,當(dāng)會(huì)話消息來到B單元,系統(tǒng)怎么能第一時(shí)間知道會(huì)話已經(jīng)在被綁定到A單元。
這里一般的方式有兩種:
1)單元之間的存儲(chǔ)系統(tǒng)采用類似DTS的機(jī)制進(jìn)行異步同步,這種機(jī)制有秒級(jí)延遲;
2)在應(yīng)用層主動(dòng)同步,比如接入消息隊(duì)列。
這兩種方式由于都是異步的原因,都會(huì)出現(xiàn)不一致的問題,如果會(huì)話同時(shí)被綁定在兩個(gè)單元,邏輯上會(huì)導(dǎo)致用戶的歷史消息丟失,這個(gè)是不能接受的。
多地域(Region)數(shù)據(jù)同步其實(shí)是通用的技術(shù)挑戰(zhàn),我們認(rèn)為存儲(chǔ)系統(tǒng)提供是最好的方式,正如Google的Spanner一樣,這樣對(duì)我們上層才是最友好的方式。
因此我們找到了存儲(chǔ)的OTS、Nuwa團(tuán)隊(duì)一起共建了GlobalTable。GlobalTable的核心原理還是借助Nuwa的一致性組,組分布在多個(gè)地域,采用多數(shù)派寫入成功即返回的原理,做到20ms以內(nèi)的一致性寫。

8、2.0版的容災(zāi)能力
釘釘單元化的容災(zāi)能力是深度結(jié)合釘釘?shù)臉I(yè)務(wù)層場(chǎng)景落地的,和淘系支付寶等有明確的區(qū)別。
以DTIM為例,最大的特點(diǎn)是當(dāng)服務(wù)單元異常時(shí),服務(wù)側(cè)仍能提供最核心的服務(wù),保障最基本的能力。本質(zhì)上是由于DTIM是最終一致性系統(tǒng),可以短暫允許部分環(huán)節(jié)失敗。
可以看一下DTIM發(fā)送消息的容災(zāi)場(chǎng)景。當(dāng)某個(gè)單元完全不可用的情況下,用戶消息發(fā)送鏈路通過降級(jí)為local模式,在本地校驗(yàn)非本單元會(huì)話數(shù)據(jù)通過之后直接做消息發(fā)送,processor遇到非本單元的會(huì)話消息數(shù)據(jù)可以做單元間投遞做數(shù)據(jù)回放,本地是否落庫可選,同步協(xié)議推送不必區(qū)分是否為本單元會(huì)話消息數(shù)據(jù)直接通過本單元的topic推送給客戶端,配合用戶無狀態(tài)快速遷移能力,單元間可以實(shí)現(xiàn)真正的分鐘級(jí)別容災(zāi)切換能力。

9、2.0版的成果與突破

以上是釘釘單元化2.0提供給應(yīng)用的核心能力,在滿足容災(zāi)和容量設(shè)計(jì)需求之后,釘釘單元化給應(yīng)用帶來了更多的能力和想象空間。
比如:
1)快速遷移:當(dāng)某一地域資源不足時(shí),釘釘單元化可以將業(yè)務(wù)快速的從A單元遷移到B單元;
2)常態(tài)化切流:比如新建的教育會(huì)話,可以放到獨(dú)立的單元;
3)熱點(diǎn)治理:當(dāng)前某一個(gè)會(huì)話過熱,特殊時(shí)期可以遷移到獨(dú)立集群;
4)SLA:滿足不同的VIP客戶需求,基于不同的SLA和售賣價(jià)格,將VIP客戶放到對(duì)應(yīng)地單元。
核心還是我們擁有單元化能力之后,實(shí)現(xiàn)了多單元流量的快速調(diào)度,為業(yè)務(wù)解決了后顧之憂。
10、2.0版在新時(shí)代面臨的新挑戰(zhàn)
10.1魚和熊掌不可兼得
2022年對(duì)釘釘來說是成本之年,成本的壓力不光落到了團(tuán)隊(duì),還落到了每個(gè)人身上。
正如存儲(chǔ)的CAP理論是一樣的,我們同時(shí)只能滿足兩個(gè)維度,對(duì)于流量(性能P)、成本(C)、體驗(yàn)(E)也是一樣,在流量不可預(yù)知和干預(yù)的情況下,選擇成本必然導(dǎo)致體驗(yàn)受損,反之選擇體驗(yàn),必然導(dǎo)致成本升高。進(jìn)入下半年,疫情反復(fù)帶來流量的反復(fù),為了實(shí)現(xiàn)可控的教育成本,只能在高峰期降級(jí)部分能力,這又導(dǎo)致體驗(yàn)受損,這段時(shí)間的工單量可以窺見一斑。
流量是用戶側(cè)觸發(fā)的,我們無法干預(yù),只能在成本和體驗(yàn)之間尋求平衡。和前面提及的一樣,為了減小成本的消耗這就導(dǎo)致我們?cè)跀U(kuò)容和縮容之間疲于奔命,反應(yīng)不及時(shí)甚至有故障的危險(xiǎn),這種機(jī)制不可取也不可持續(xù)。到底是要流量與成本,還是要流量與體驗(yàn),給我們技術(shù)團(tuán)隊(duì)帶來了巨大的挑戰(zhàn)和矛盾。
10.2商業(yè)化路在何方
當(dāng)前釘釘為支持大客戶提供了多種解決方案,專業(yè)釘釘、專屬存儲(chǔ)與打包、專有釘釘。
專屬釘釘通過APP專屬化以及部分專屬功能,比如為一個(gè)企業(yè)定制一個(gè)擁有獨(dú)立Logo的APP,能滿足一般的中大型客戶的業(yè)務(wù)訴求。
對(duì)于大型以及超大型客戶,我們提供專有釘釘,提供專有化輸出,完全隔離的方案,比如浙政釘。
伴隨著釘釘?shù)纳虡I(yè)化進(jìn)入深水區(qū),客戶對(duì)釘釘提出了新的訴求,特別是數(shù)據(jù)安全與歸屬、互聯(lián)互通、完整的能力棧等訴求,當(dāng)前釘釘輸出產(chǎn)品形態(tài)都無法同時(shí)地滿足以上需求。
前幾年互聯(lián)網(wǎng)上出現(xiàn)的幾起數(shù)據(jù)安全事件,數(shù)據(jù)丟失與泄露,未經(jīng)客戶授權(quán)私自訪問客戶數(shù)據(jù),讓大多數(shù)客戶不信任服務(wù)提供商,即使服務(wù)商的安全能力已經(jīng)是業(yè)界一線能力。其實(shí)這個(gè)是可以理解的,數(shù)據(jù)即客戶的生命線,數(shù)據(jù)無法在自身可控范圍內(nèi),特別是對(duì)于很多特殊行業(yè),這是無法接受的,自身性命豈能假手于人。專屬釘釘在面臨這種客戶時(shí),前線售賣同學(xué)是無能為力。
那么很多同學(xué)肯定會(huì)提“如果專屬釘釘滿足不了需求,我們專有釘釘不是能解決這些問題嗎?”,其實(shí)單單從訴求來看,專有釘釘場(chǎng)景是切合客戶的業(yè)務(wù)訴求,提供完全獨(dú)立運(yùn)行環(huán)境、可控的數(shù)據(jù)安全。但是專有釘釘由于其獨(dú)特的架構(gòu)帶來高昂的售價(jià)以及后期的運(yùn)維代價(jià),對(duì)于超大型的客戶來說也難以承擔(dān)如此高的成本。對(duì)于釘釘自身來說,從研發(fā)到后續(xù)運(yùn)維,維護(hù)一套獨(dú)立體系也難以在客戶側(cè)大面積推廣。

11、單元化架構(gòu)3.0版:混合云架構(gòu)
11.1概述
釘釘單元化經(jīng)過四年的發(fā)展,在容災(zāi)和容量上做出一定的積淀,同時(shí)完成了一些核心技術(shù)的積累。
當(dāng)整體架構(gòu)成熟之后,我們也在思考,單元化能否從技術(shù)架構(gòu)升級(jí)為業(yè)務(wù)架構(gòu),比如搭建獨(dú)立的高可用單元,按照售賣的SLA提供給VIP客戶,支持釘釘商業(yè)化的發(fā)展。
同時(shí)我們?cè)谠圃鸩桨l(fā)力,將部分核心應(yīng)用放到云上,經(jīng)過這一年多的運(yùn)行,遇到了新的挑戰(zhàn),但更獲得云下無法獲得的計(jì)算彈性能力,云上的彈性對(duì)云下是一個(gè)降維打擊,從一個(gè)新的方向解決計(jì)算問題。
如上文提到的兩個(gè)核心挑戰(zhàn),釘釘單元化同樣面臨這個(gè)問題,在持續(xù)的發(fā)展中找到了一個(gè)合適的架構(gòu)方向。
基本思路是:
1)云下作為基本盤,保障核心流量的問題,畢竟云下經(jīng)過集團(tuán)多年的打磨,不管是穩(wěn)定性還是流程的合理性都有保障;
2)云上應(yīng)對(duì)高漲異常的流量,比如和疫情正相關(guān)的教育流量,既保證了服務(wù)的穩(wěn)定性,又能充分利用云上彈性能力,在提供完整能力的前提下做到一個(gè)相對(duì)較低的成本。
其次是升級(jí)Geo概念:
1)將Geo作為一個(gè)獨(dú)立的業(yè)務(wù)域,實(shí)現(xiàn)Geo級(jí)別完全獨(dú)立部署,分布式云模式;
2)同時(shí)Geo之間按需互通,從研發(fā)體系上能做到一套代碼。

因此,釘釘單元化來到了3.0版本,我們稱之為釘釘單元化混合云架構(gòu)。
混合云主要是從兩個(gè)維度來看:
第一:是云上云下,我們認(rèn)為云上云下并不是取代的關(guān)系,而是相互補(bǔ)充的關(guān)系,是一個(gè)長(zhǎng)期的狀態(tài),正如很多大客戶隨著規(guī)模的持續(xù)擴(kuò)張,最終依賴的部分核心能力必然走向自研道理一樣,這能做成本的進(jìn)一步降低,所以架構(gòu)是一個(gè)混合云架構(gòu);
第二:業(yè)務(wù)架構(gòu)上也是混合云架構(gòu),通過不同的Geo,將不同的業(yè)務(wù)邏輯上聚合到一起,構(gòu)建起一張釘釘?shù)拇缶W(wǎng),不同Geo按需互通,實(shí)現(xiàn)了業(yè)務(wù)架構(gòu)的混合。
3.0從系統(tǒng)架構(gòu)上相對(duì)于2.0,最大的區(qū)別就是云原生技術(shù)的運(yùn)用和互通網(wǎng)關(guān)的建立。
11.2云原生技術(shù) :抵抗系統(tǒng)架構(gòu)熵增的有效手段
近幾年,互聯(lián)網(wǎng)圈最火的技術(shù)莫過于以Docker為代表的云原生技術(shù)最為火熱,各大云廠商也都在不遺余力的推廣云原生技術(shù)以及對(duì)應(yīng)的產(chǎn)品。同時(shí)釘釘服務(wù)過億DAU的客戶,面對(duì)各種可靠性、服務(wù)連續(xù)性、并發(fā)、容災(zāi)等技術(shù)挑戰(zhàn),也都走到了現(xiàn)有技術(shù)的邊界。
所以我們也在不斷吸收新的技術(shù)和架構(gòu),希望從體系與架構(gòu)上降低我們的技術(shù)復(fù)雜度,以抵抗熵增。
我們?cè)?021年底啟動(dòng)了云原生升級(jí)戰(zhàn)略,升級(jí)云原生技術(shù)并不是為了技術(shù)而升級(jí),而是切實(shí)面臨巨大的技術(shù)挑戰(zhàn)。
1)首先我們面臨多語言的挑戰(zhàn):
我們以IM為例,IM的核心邏輯都是使用C++構(gòu)建,但是我們常用的中間件三大件:存儲(chǔ)、緩存、異步隊(duì)列,其中緩存和異步隊(duì)列在C++客戶端上長(zhǎng)期建設(shè)不足,導(dǎo)致IM長(zhǎng)期在使用低版本。
低版本由于長(zhǎng)時(shí)間缺乏維護(hù),經(jīng)常會(huì)出現(xiàn)異常,比如隊(duì)列假死、消費(fèi)不均等,導(dǎo)致我們自己不得不親自上陣修改SDK的代碼,以致最后難以使用到產(chǎn)品的新能力,阻礙IM服務(wù)能力的提升。
2)其次是多產(chǎn)品多云的挑戰(zhàn):
我們以阿里云為例,數(shù)據(jù)庫類目下的產(chǎn)品,從類別上就有關(guān)系數(shù)據(jù)庫、NoSQL數(shù)據(jù)庫、數(shù)倉等等,還有存儲(chǔ)也是一樣。
對(duì)于我們上層業(yè)務(wù),其實(shí)絕大部分服務(wù)都只依賴了底層的CURD,這么多產(chǎn)品,每次對(duì)接一個(gè)產(chǎn)品都要開發(fā)一輪。
配置系統(tǒng)也是一樣,彈內(nèi)有Diamond,云上有Nacos、Mse,K8s有自己的Configmap等,而且這些配置系統(tǒng)不像數(shù)據(jù)庫有標(biāo)準(zhǔn),而是百花齊放,但是這樣卻苦了我們使用者。
這些內(nèi)容不是我們的核心路徑,浪費(fèi)大把時(shí)間在各種產(chǎn)品接口的適配上,明顯拖累了釘釘?shù)陌l(fā)展。
3)最后就是通用的流量治理挑戰(zhàn):
釘釘很多系統(tǒng)都是最終一致的系統(tǒng),IM就是典型的最終一致系統(tǒng),這類系統(tǒng)和強(qiáng)同步系統(tǒng)在架構(gòu)設(shè)計(jì)有一個(gè)明顯的區(qū)別,強(qiáng)一致系統(tǒng)如果遇到失敗,必須要持續(xù)重試直到成功,所以一般編程上都是重試+退避。
但是最終一致系統(tǒng)不是,這類系統(tǒng)允許部分節(jié)點(diǎn)失敗,不要阻礙其他流程,失敗的流量通過一個(gè)異步回旋的隊(duì)列,將數(shù)據(jù)逐步回放回來即可。這種回旋需要借助異步隊(duì)列,而且要設(shè)計(jì)各種消費(fèi)機(jī)制,比如限速、比如丟棄等等,這是一個(gè)通用的邏輯,但是每個(gè)業(yè)務(wù)方或多或少都在實(shí)現(xiàn)自己的回旋系統(tǒng),重復(fù)的造輪子。又比如各種故障注入,單元化路由流量等等,要想擁有這個(gè)能力,團(tuán)隊(duì)不得不投入人力研發(fā)。
在對(duì)付架構(gòu)復(fù)雜度上,我們主要從兩個(gè)維度來屏蔽復(fù)雜度。
首先代碼層面我們選擇了DDD模式,我們使用DDD分層核心是把對(duì)外系統(tǒng)的依賴全部收攏到Infrastructure這一層,全部采用純虛函數(shù)(Interface)對(duì)外提供接口。屏蔽底層中間件差異和細(xì)節(jié)。
在架構(gòu)上采用Sidecar的模式,類似于Dapr的思想,通過標(biāo)準(zhǔn)的GRPC和PB實(shí)現(xiàn)應(yīng)用與中間件解耦。Sidecar中集成了各種中間件、配置系統(tǒng)、灰度系統(tǒng)等,等價(jià)實(shí)現(xiàn)了應(yīng)用和中間件的解耦。上文中提到的不管是多語言挑戰(zhàn)、多云多產(chǎn)品的挑戰(zhàn)、重復(fù)造輪子等問題,都能很好的解決。

11.3互通網(wǎng)關(guān) :混合架構(gòu)的基石
云上云下互通,或者說多個(gè)云賬戶VPC之間的互通,我們常見的有兩種方案:
1)其一是VPC直接打通,讓多個(gè)VPC之間形成一個(gè)大的局域網(wǎng),RealServer實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)互通;
2)其一是中間搭建一個(gè)負(fù)載均衡器,通過暴露EIP實(shí)現(xiàn)互通。
兩個(gè)方案都有自己的優(yōu)缺點(diǎn)。
對(duì)于方案一:打通的VPC涉及到IP規(guī)劃,如果前期沒有合理規(guī)劃,后續(xù)很難打通;還有這種方案有水桶短板安全問題,一旦一個(gè)VPC被攻破,這張網(wǎng)也被攻破;但是對(duì)于內(nèi)部的應(yīng)用來說架構(gòu)就比較簡(jiǎn)單,可以僅僅借助K8s DNS service就能做到服務(wù)發(fā)現(xiàn)。
對(duì)于方案二:最大的缺點(diǎn)就是中間有一個(gè)集中式的負(fù)載均衡,需要申請(qǐng)獨(dú)立的LB才可訪問;但是這種方案隔離性好。
對(duì)于釘釘單元化來說,涉及N個(gè)業(yè)務(wù)方,N * M個(gè)應(yīng)用,對(duì)應(yīng)X個(gè)VPC,要想VPC之間打通,幾乎沒有可能性,而且VPC打通,還面臨應(yīng)用之間的安全性問題。要實(shí)現(xiàn)Geo之間互通,環(huán)境之間的隔離性是基本要求,與此同時(shí),我們也要考慮到系統(tǒng)的可擴(kuò)展性,所以我們必須要構(gòu)建一套獨(dú)立的流量網(wǎng)關(guān),實(shí)現(xiàn)流量加密、尋址、轉(zhuǎn)發(fā)等通用能力。
釘釘互通網(wǎng)關(guān)是構(gòu)建在Envoy之上的系統(tǒng),雙向Ingress和Egress,支持GRPC和釘釘自研協(xié)議。具備流量管理、傳輸加密、單元尋址等能力。釘釘單元化借助互通網(wǎng)關(guān)的能力,再配合全局流控系統(tǒng),我們可以在多單元之間實(shí)現(xiàn)精確的流量控制和調(diào)度。
12、寫在最后
伴隨著專屬集群的持續(xù)輸出,客戶對(duì)專屬的場(chǎng)景需求會(huì)越來越多,需要我們投入更多的人力持續(xù)的建設(shè)。
比如:
1)在架構(gòu)側(cè):首先是Sidecar持續(xù)強(qiáng)化,支持更多的中間件和環(huán)境,提供不同維度的安全能力,滿足客戶和應(yīng)用的安全需求;
2)在運(yùn)維側(cè):我們需要構(gòu)建多Geo管理能力,完善Geo和單元之間流量快速調(diào)度能力,提供自動(dòng)化的自檢系統(tǒng)等;
3)在交付側(cè):如果實(shí)現(xiàn)快速交付,比如是否能做到新應(yīng)用一周完成單元化改造,新Geo一天部署完成。這些挑戰(zhàn)都是接下來我們要重點(diǎn)投入的方向。
對(duì)于標(biāo)準(zhǔn)釘釘來說,這個(gè)是我們的基本盤,一個(gè)穩(wěn)定可靠且低成本的釘釘是我們持之以恒的目標(biāo),接下來我們會(huì)加大云上流量的占比,充分的借助云上彈性能力,實(shí)現(xiàn)可控的成本。
今天我們只是站在釘釘?shù)慕嵌壬蠏伭艘粋€(gè)“磚”,希望在異地多活這個(gè)領(lǐng)域激起一層浪花,歡迎大家一起討論。
13、相關(guān)資料
[1]?現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲(chǔ)方案探討
[2]?企業(yè)級(jí)IM王者——釘釘在后端架構(gòu)上的過人之處
[3]?深度解密釘釘即時(shí)消息服務(wù)DTIM的技術(shù)設(shè)計(jì)
[4]?釘釘——基于IM技術(shù)的新一代企業(yè)OA平臺(tái)的技術(shù)挑戰(zhàn)(視頻+PPT)
[5]?企業(yè)微信的IM架構(gòu)設(shè)計(jì)揭秘:消息模型、萬人群、已讀回執(zhí)、消息撤回等
[6]?IM系統(tǒng)的MQ消息中間件選型:Kafka還是RabbitMQ?
[7]?深度揭密RocketMQ在釘釘IM系統(tǒng)中的應(yīng)用實(shí)踐
(本文同步發(fā)布于:http://www.52im.net/thread-4122-1-1.html)