餓了么技術(shù)團(tuán)隊(duì)花了1年多的時(shí)間吁伺,實(shí)現(xiàn)了業(yè)務(wù)的整體異地多活涛目,能夠靈活的在多個(gè)異地機(jī)房之間調(diào)度用戶,實(shí)現(xiàn)了自由擴(kuò)容和多機(jī)房容災(zāi)的目標(biāo)愧捕。本文介紹這個(gè)項(xiàng)目的整體結(jié)構(gòu),還簡(jiǎn)要介紹實(shí)現(xiàn)多活的5大核心基礎(chǔ)組件申钩,為讀者建立基本的概念模型次绘,后續(xù)會(huì)有系列文章陸續(xù)介紹每個(gè)組件的實(shí)現(xiàn)細(xì)節(jié)。讀者能夠從中了解到做異地多活的大方向撒遣,為實(shí)現(xiàn)自己的異地多活邮偎,或者是容災(zāi)備份提供參考。
背景:為什么要做異地多活义黎?
餓了么要做多活禾进,是受業(yè)務(wù)發(fā)展的驅(qū)動(dòng),經(jīng)過幾年的高速發(fā)展廉涕,我們的業(yè)務(wù)已經(jīng)擴(kuò)大到單個(gè)數(shù)據(jù)中心撐不住了泻云,主要機(jī)房已經(jīng)不能再加機(jī)器艇拍,業(yè)務(wù)卻不斷的要求加擴(kuò)容,所以我們需要一個(gè)方案能夠把服務(wù)器部署到多個(gè)機(jī)房宠纯。另外一個(gè)更重要的原因是卸夕,整個(gè)機(jī)房級(jí)別的故障時(shí)有發(fā)生,每次都會(huì)帶來嚴(yán)重的后果婆瓜,我們需要在發(fā)生故障時(shí)快集,能夠把一個(gè)機(jī)房的業(yè)務(wù)全部遷移到別的機(jī)房,保證服務(wù)可用勃救。
歸納起來碍讨,我們要達(dá)到兩個(gè)目標(biāo):
- 服務(wù)可以擴(kuò)展到多個(gè)機(jī)房
- 能夠應(yīng)對(duì)整個(gè)機(jī)房級(jí)別的故障
解決這兩個(gè)問題的常見辦法是做異地多活,把服務(wù)分散到多個(gè)機(jī)房蒙秒,自然擴(kuò)展和高可用的問題就迎刃而解了勃黍。
餓了么有自己的特殊情況,對(duì)于其他大部分公司來說晕讲,其實(shí)要不要做多活覆获,主要就是看下圖這樣一個(gè)曲線。
對(duì)于一個(gè)業(yè)務(wù)快速增長(zhǎng)的企業(yè)瓢省,每次故障帶來的損失也相應(yīng)是加速增長(zhǎng)的弄息,而技術(shù)的投入總體上是線性的,初期故障損失小于技術(shù)投入勤婚,在某個(gè)時(shí)間點(diǎn)摹量,故障的損失會(huì)超過技術(shù)投入,這時(shí)就要用一些高可用方案馒胆,來避免故障缨称,多活就是其中最重要的一種。
異地多活面臨的主要挑戰(zhàn)是網(wǎng)絡(luò)延遲祝迂,以北京到上海 1468 公里睦尽,即使是光速傳輸,一個(gè)來回也需要接近10ms型雳,我們?cè)趯?shí)際測(cè)試的過程中当凡,發(fā)現(xiàn)上海到北京的網(wǎng)絡(luò)延遲,一般是 30 ms纠俭。這 30 ms可以和運(yùn)算系統(tǒng)中其他的延遲時(shí)間做個(gè)比較:
L1 cache reference ......................... 0.5 ns
Branch mispredict ............................ 5 ns
L2 cache reference ........................... 7 ns
Mutex lock/unlock ........................... 25 ns
Main memory reference ...................... 100 ns
Compress 1K bytes with Zippy ............. 3,000 ns = 3 μs
Send 2K bytes over 1 Gbps network ....... 20,000 ns = 20 μs
SSD random read ........................ 150,000 ns = 150 μs
Read 1 MB sequentially from memory ..... 250,000 ns = 250 μs
Round trip within same datacenter ...... 500,000 ns = 0.5 ms
Read 1 MB sequentially from SSD* ..... 1,000,000 ns = 1 ms
上海之間兩個(gè)機(jī)房的網(wǎng)絡(luò)延時(shí)................. 1,000,000 ns = 1 ms
Disk seek ........................... 10,000,000 ns = 10 ms
Read 1 MB sequentially from disk .... 20,000,000 ns = 20 ms
北京到上海的網(wǎng)絡(luò)延時(shí).................... 30,000,000 ns = 30 ms
Send packet CA->Netherlands->CA .... 150,000,000 ns = 150 ms
北京上海兩地的網(wǎng)絡(luò)延遲時(shí)間沿量,大致是內(nèi)網(wǎng)網(wǎng)絡(luò)訪問速度的 60 倍(30ms/0.5ms),如果不做任何改造冤荆,一方直接訪問另外一方的服務(wù)朴则,那么我們的APP的反應(yīng)會(huì)比原來慢 60 倍,其實(shí)考慮上多次往返匙赞,可能會(huì)慢600倍佛掖。
如果機(jī)房都在上海,那么網(wǎng)絡(luò)延遲只有內(nèi)網(wǎng)速度的2倍涌庭,可以當(dāng)成一個(gè)機(jī)房使用芥被。所有有些公司的多活方案,會(huì)選擇同城機(jī)房坐榆,把同城的幾個(gè)機(jī)房當(dāng)成一個(gè)機(jī)房部署拴魄,可以在不影響服務(wù)架構(gòu)的情況下擴(kuò)展出多個(gè)機(jī)房,不失為一個(gè)快速見效的方法席镀。我們?cè)谧龆嗷畹某跗谝灿懻撨^同城方案匹中,比如在北京周邊建設(shè)一個(gè)新機(jī)房,遷移部分服務(wù)到新機(jī)房豪诲,兩個(gè)機(jī)房專線連接顶捷,服務(wù)間做跨機(jī)房調(diào)用。雖然這個(gè)方案比較容易屎篱,也解決了機(jī)房的擴(kuò)展問題服赎,但是對(duì)高可用卻沒有好處,相反還帶來了更高的風(fēng)險(xiǎn)交播。
與同城多活的方案不同重虑,異地多活的方案會(huì)限制機(jī)房間的相互調(diào)用,需要定義清晰的服務(wù)邊界秦士,減少相互依賴缺厉,讓每個(gè)機(jī)房都成為獨(dú)立的單元,不依賴于其他機(jī)房隧土。經(jīng)過幾番考量提针,我們最終選擇了異地多活的方案,對(duì)這兩個(gè)方案的比較和思考可以見下表次洼,異地多活雖然更困難一點(diǎn)关贵,但是能同時(shí)達(dá)到我們的兩個(gè)核心目標(biāo),更為可行卖毁。
設(shè)計(jì):異地多活的實(shí)現(xiàn)思路和方法
我們的異地多活方案的揖曾,有幾條基本原則,整個(gè)多活方案都是這些原則的自然推導(dǎo)亥啦。但在介紹一下這些原則之前炭剪,先要說明一下餓了么的服務(wù)流程,才能讓大家更好的理解這些原則的來由
下面這張簡(jiǎn)圖是我們的主流程:
業(yè)務(wù)過程中包含3個(gè)最重要的角色翔脱,分別是用戶奴拦、商家和騎手,一個(gè)訂單包含3個(gè)步驟:
- 用戶打開我們的APP届吁,系統(tǒng)會(huì)推薦出用戶位置附近的各種美食错妖,推薦順序中結(jié)合了用戶習(xí)慣绿鸣,推薦排序,商戶的推廣等暂氯。用戶找到中意的食物 潮模,下單并支付,訂單會(huì)流轉(zhuǎn)到商家痴施。
- 商家接單并開始制作食物擎厢,制作完成后,系統(tǒng)調(diào)度騎手趕到店面辣吃,取走食物
- 騎手按照配送地址动遭,把食物送到客戶手中。
整個(gè)下單到配送完成神得,有嚴(yán)格的時(shí)間要求厘惦,必須在短短的幾十分鐘內(nèi)完成,我們的服務(wù)和地理位置強(qiáng)相關(guān)循头,并且實(shí)時(shí)性要求高绵估,服務(wù)的地域性和實(shí)時(shí)性是我們的核心特性,多活設(shè)計(jì)最重要的是滿足這兩個(gè)特性卡骂。
進(jìn)過反復(fù)討論国裳,我們的多活架構(gòu)通過遵循以下幾條基本原則,來滿足這兩個(gè)核心特性:
- 業(yè)務(wù)內(nèi)聚:?jiǎn)蝹€(gè)訂單的旅單過程全跨,要在一個(gè)機(jī)房中完成缝左,不允許跨機(jī)房調(diào)用。這個(gè)原則是為了保證實(shí)時(shí)性浓若,旅單過程中不依賴另外一個(gè)機(jī)房的服務(wù)渺杉,才能保證沒有延遲。我們稱每個(gè)機(jī)房為一個(gè) ezone挪钓,一個(gè) ezone 包含了餓了么需要的各種服務(wù)是越。一筆業(yè)務(wù)能夠內(nèi)聚在一個(gè) ezone 中,那么一個(gè)定單涉及的用戶碌上,商家趁餐,騎手蝉娜,都會(huì)在相同的機(jī)房园匹,這樣訂單在各個(gè)角色之間流轉(zhuǎn)速度最快深纲,不會(huì)因?yàn)楦鞣N異常情況導(dǎo)致延時(shí)。恰好我們的業(yè)務(wù)是地域化的霞丧,通過合理的地域劃分呢岗,也能夠?qū)崿F(xiàn)業(yè)務(wù)內(nèi)聚。
- 可用性優(yōu)先:當(dāng)發(fā)生故障切換機(jī)房時(shí),優(yōu)先保證系統(tǒng)可用后豫,首先讓用戶可以下單吃飯悉尾,容忍有限時(shí)間段內(nèi)的數(shù)據(jù)不一致,在事后修復(fù)挫酿。每個(gè) ezone 都會(huì)有全量的業(yè)務(wù)數(shù)據(jù)焕襟,當(dāng)一個(gè) ezone 失效后,其他的 ezone 可以接管用戶饭豹。用戶在一個(gè)ezone的下單數(shù)據(jù),會(huì)實(shí)時(shí)的復(fù)制到其他ezone务漩。
- 保證數(shù)據(jù)正確:在確敝羲ィ可用的情況下,需要對(duì)數(shù)據(jù)做保護(hù)以避免錯(cuò)誤饵骨,在切換和故障時(shí)翘悉,如果發(fā)現(xiàn)某些訂單的狀態(tài)在兩個(gè)機(jī)房不一致,會(huì)鎖定該筆訂單居触,阻止對(duì)它進(jìn)行更改妖混,保證數(shù)據(jù)的正確。
- 業(yè)務(wù)可感:因?yàn)榛A(chǔ)設(shè)施還沒有強(qiáng)大到可以抹去跨機(jī)房的差異轮洋,需要讓業(yè)務(wù)感知多活邏輯制市,業(yè)務(wù)代碼要做一些改造,包括:需要業(yè)務(wù)代碼能夠識(shí)別出業(yè)務(wù)數(shù)據(jù)的歸屬弊予,只處理本 ezone 的數(shù)據(jù)祥楣,過濾掉無關(guān)的數(shù)據(jù)。完善業(yè)務(wù)狀態(tài)機(jī)汉柒,能夠在數(shù)據(jù)出現(xiàn)不一致的時(shí)候误褪,通過狀態(tài)機(jī)發(fā)現(xiàn)和糾正。
這幾條基本原則碾褂,貫穿了餓了么多活的整個(gè)設(shè)計(jì)兽间。
基于這幾條原則,我們從服務(wù)劃分正塌,流量路由嘀略,業(yè)務(wù)改造等方面設(shè)計(jì)了多活方案,下面簡(jiǎn)要介紹一主要邏輯传货。
服務(wù)劃分(Sharding):
為了實(shí)現(xiàn)業(yè)務(wù)內(nèi)聚屎鳍,我們首先要選擇一個(gè)劃分方法(Sharding Key),對(duì)服務(wù)進(jìn)行分區(qū)问裕,讓用戶逮壁,商戶,騎手能夠正確的內(nèi)聚到同一個(gè) ezone 中粮宛。分區(qū)方案是整個(gè)多活的基礎(chǔ)窥淆,它決定了之后的所有邏輯卖宠。
根據(jù)餓了么的業(yè)務(wù)特點(diǎn),我們自然的選擇地理位置作為劃分業(yè)務(wù)的單元忧饭,把地理位置上接近的用戶扛伍,商戶,騎手劃分到同一個(gè)ezone词裤,這樣一個(gè)訂單的履單流程就會(huì)在一個(gè)機(jī)房完成刺洒,能夠保證最小的延時(shí),在某個(gè)機(jī)房出現(xiàn)問題的時(shí)候吼砂,也可以按照地理位置把用戶逆航,商戶,騎手打包遷移到別的機(jī)房即可渔肩。
所以我們最終選擇的方案如下圖因俐,自定義地理劃分圍欄,用圍欄把全國(guó)分為多個(gè) shard周偎,圍欄的邊界盡量按照行政省界抹剩,必要的時(shí)候做一些調(diào)整,避免圍欄穿過市區(qū)蓉坎。一個(gè)ezone可以包含多個(gè) shard澳眷,某個(gè) ezone 的 shard ,可以隨時(shí)切換到另外一個(gè) ezone 蛉艾,靈活的調(diào)度資源和failover境蔼。
這樣的劃分方案,基本解決了垮城市下單的問題伺通,線上沒有觀察到有跨 ezone 下單的情況箍土。圍欄的劃分是靈活的,可以隨著以后業(yè)務(wù)的拓展進(jìn)行修改罐监,因?yàn)槊總€(gè)機(jī)房都是全量數(shù)據(jù)吴藻,所以調(diào)整圍欄不會(huì)導(dǎo)致問題。
對(duì)這種劃分方法弓柱,有一些常見的疑問沟堡,比如:
1.如果兩個(gè)城市是接壤的,會(huì)出現(xiàn)商家和用戶處于不同 ezone 的情況矢空,豈不是破壞了內(nèi)聚性原則航罗?
這種情況確實(shí)會(huì)出現(xiàn),為了盡量避免屁药,我們?cè)趧澐謘hard的時(shí)候沒有簡(jiǎn)單的用城市名稱粥血,而是用了復(fù)雜的地理圍欄實(shí)現(xiàn),地理圍欄主體按照省界劃分,再加上局部微調(diào)复亏,我們最大限度的避免了跨ezone下單的情況趾娃。但如果真的出現(xiàn)了,用戶下單也不受影響缔御,最多只是狀態(tài)有1s左右的延遲抬闷。
2.用戶是會(huì)動(dòng)的,如果用戶從北京到了上海耕突,那么劃分規(guī)則應(yīng)該怎么應(yīng)對(duì)笤成?
用戶在北京下單,數(shù)據(jù)落在北京shard眷茁,到上海下單疹启,數(shù)據(jù)則落在上海的 shard,借助于底層的數(shù)據(jù)同步工具蔼卡,用戶無論在什么地方,都能看到自己的數(shù)據(jù)挣磨,但是有1s左右的延時(shí)雇逞,對(duì)于大部分的業(yè)務(wù)場(chǎng)景,這個(gè)延遲是可以承受的茁裙。當(dāng)然也有些業(yè)務(wù)場(chǎng)景不能接受這 1s 的延時(shí)塘砸,我們也提供了另外的方案來應(yīng)對(duì),參考下文介紹Globa Zone的章節(jié)晤锥。
3.為什么不簡(jiǎn)單點(diǎn)掉蔬,按照用戶的ID來切分?
阿里是按照用戶ID的取模來劃分單元的矾瘾,比較簡(jiǎn)潔女轿。我們?nèi)绻灿肐D做切分,同一地方的用戶壕翩,商戶蛉迹,騎手可能被劃分到不同 ezone,就會(huì)出現(xiàn)比較多的跨機(jī)房調(diào)用放妈,這樣就更可能出現(xiàn)延遲北救,難以保證實(shí)時(shí)性。所以芜抒,我們本地配送的業(yè)務(wù)模式珍策,決定了需要用地理位置來劃分服務(wù)。
流量路由:
基于地理位置劃分規(guī)則宅倒,我們開發(fā)了統(tǒng)一的流量路由層(API Router)攘宙,這一層負(fù)責(zé)對(duì)客戶端過來的 API 調(diào)用進(jìn)行路由,把流量導(dǎo)向到正確的 ezone。API Router 部署在多個(gè)公有云機(jī)房中模聋,用戶就近接入到公有云的API Router肩民,還可以提升接入質(zhì)量。
前端 APP 做了改造链方,為每個(gè)請(qǐng)求都帶上了分流標(biāo)簽持痰,API Router 會(huì)檢查流量上自帶的分流標(biāo)簽,把分流標(biāo)簽轉(zhuǎn)換為對(duì)應(yīng)的 Shard ID祟蚀,再查詢 Shard ID 對(duì)應(yīng)的 eZone工窍,最終決定把流量路由到哪個(gè) ezone。
最基礎(chǔ)的分流標(biāo)簽是地理位置前酿,有了地理位置患雏,AR 就能計(jì)算出正確的 shard 歸屬。但業(yè)務(wù)是很復(fù)雜的罢维,并不是所有的調(diào)用都能直接關(guān)聯(lián)到某個(gè)地理位置上淹仑,我們使用了一種分層的路由方案,核心的路由邏輯是地理位置肺孵,但是也支持其他的一些 High Level Sharding Key匀借,這些 Sharding Key 由 APIRouter 轉(zhuǎn)換為核心的 Sharding Key,具體如下圖平窘。這樣既減少了業(yè)務(wù)的改造工作量吓肋,也可以擴(kuò)展出更多的分區(qū)方法。
除了入口處的路由瑰艘,我們還開發(fā)了 SOA Proxy是鬼,用于路由SOA調(diào)用的,和API Router基于相同的路由規(guī)則紫新。APIRouter 和 SOAProxy 構(gòu)成了流量的路由通道均蜜,讓我們可以靈活的控制各種調(diào)用在多活環(huán)境下的走向。
數(shù)據(jù)復(fù)制:
為了實(shí)現(xiàn)可用優(yōu)先原則芒率,所有機(jī)房都會(huì)有全量數(shù)據(jù)兆龙,這樣用戶可以隨時(shí)切換到其他機(jī)房,全量數(shù)據(jù)就需要對(duì)數(shù)據(jù)進(jìn)行實(shí)時(shí)復(fù)制敲董,我們開發(fā)了相應(yīng)的中間件紫皇,對(duì) mysql,zookeeper 腋寨,消息隊(duì)列和 redis 的數(shù)據(jù)進(jìn)行復(fù)制聪铺。
Mysql 數(shù)據(jù)復(fù)制工具 DRC:
Mysql 的數(shù)據(jù)量最大,每個(gè)機(jī)房產(chǎn)生的數(shù)據(jù)萄窜,都通過 DRC 復(fù)制到其他 ezone铃剔,每個(gè)ezone的主鍵取值空間是ezoneid + 固定步長(zhǎng)撒桨,所以產(chǎn)生的 id 各不相同,數(shù)據(jù)復(fù)制到一起后不會(huì)發(fā)生主鍵沖突键兜。按照分區(qū)規(guī)則凤类,正常情況下,每個(gè) ezone 只會(huì)寫入自己的數(shù)據(jù)普气,但萬一出現(xiàn)異常谜疤,2個(gè) ezone 同時(shí)更新了同一筆數(shù)據(jù),就會(huì)產(chǎn)生沖突现诀。DRC 支持基于時(shí)間戳的沖突解決方案夷磕,當(dāng)一筆數(shù)據(jù)在兩個(gè)機(jī)房同時(shí)被修改時(shí),最后修改的數(shù)據(jù)會(huì)被保留仔沿,老的數(shù)據(jù)會(huì)被覆蓋坐桩。
ZooKeeper 復(fù)制:
有些全局的配置信息,需要在所有機(jī)房都完全一致封锉,我們開發(fā)了 zookeeper 復(fù)制工具绵跷,用于在多個(gè)機(jī)房中同步 ZK 信息。
消息隊(duì)列和Redis復(fù)制:
MQ,Redis 的復(fù)制與 ZK 復(fù)制類似成福,也開發(fā)了 相應(yīng)的復(fù)制工具碾局。
強(qiáng)一致保證:
對(duì)于個(gè)別一致性要求很高的應(yīng)用,我們提供了一種強(qiáng)一致的方案(Global Zone)闷叉,Globa Zone是一種跨機(jī)房的讀寫分離機(jī)制,所有的寫操作被定向到一個(gè) Master 機(jī)房進(jìn)行脊阴,以保證一致性握侧,讀操作可以在每個(gè)機(jī)房的 Slave庫執(zhí)行,也可以 bind 到 Master 機(jī)房進(jìn)行嘿期,這一切都基于我們的數(shù)據(jù)庫訪問層(DAL)完成品擎,業(yè)務(wù)基本無感知。
切換過程和各種異常保護(hù):
避免數(shù)據(jù)錯(cuò)誤非常重要备徐,在網(wǎng)絡(luò)斷開萄传,或者是切換過程中,特別容易產(chǎn)生錯(cuò)誤數(shù)據(jù)蜜猾。比如由于復(fù)制延時(shí)秀菱,訂單狀態(tài)不一致,用戶有可能會(huì)重復(fù)支付蹭睡。為了避免我們采取了一些保護(hù)措施衍菱,避免在切換時(shí)發(fā)生錯(cuò)誤。
- 在網(wǎng)絡(luò)中斷時(shí)肩豁,如果不是必要脊串,不做切換辫呻,因?yàn)槿我鈫蝹€(gè)機(jī)房能夠提供完整服務(wù)。
- 如果需要切換琼锋,對(duì)鎖定切換過程中的訂單放闺,直到切換完成,數(shù)據(jù)復(fù)制正常缕坎,才開放鎖定怖侦。這個(gè)過程也通過 DAL 來實(shí)現(xiàn)
- 對(duì)于標(biāo)記為其他機(jī)房的寫入數(shù)據(jù),DAL 會(huì)進(jìn)行保護(hù)念赶,拒絕寫入础钠。
- DRC 會(huì)檢查并報(bào)告錯(cuò)誤的寫入操作,方便檢查隱藏問題叉谜。
通過以上4條的保護(hù)旗吁,我們保證了數(shù)據(jù)的正確性,頻繁的切換也不會(huì)出現(xiàn)異常的業(yè)務(wù)數(shù)據(jù)停局。
多個(gè)機(jī)房的Cache刷新:
數(shù)據(jù)的變更信息很钓,通過 DRC 廣播到多個(gè)機(jī)房,實(shí)現(xiàn)緩存的刷新董栽,保證各個(gè)機(jī)房的緩存一致性码倦。
整體結(jié)構(gòu)
以上介紹了各個(gè)考慮的方面,現(xiàn)在可以綜合起來看锭碳,餓了么多活的整體結(jié)構(gòu)如下圖:
業(yè)務(wù)改造:
業(yè)務(wù)可感知是一條基本原則袁稽,通過中間件提供的服務(wù),多活邏輯會(huì)暴露給業(yè)務(wù)方擒抛,例如:當(dāng)前服務(wù)所屬的 ezone推汽,路由策略,數(shù)據(jù)的歸屬 shard 等歧沪,基于這些信息歹撒,業(yè)務(wù)可以執(zhí)行很多的邏輯。包括:
- 后臺(tái)任務(wù)可以過濾掉非本 ezone 的數(shù)據(jù)诊胞。
- 可以在發(fā)生切換時(shí)暖夭,執(zhí)行特定的邏輯,觸發(fā)特定動(dòng)作撵孤。
- 業(yè)務(wù)需要準(zhǔn)備一些數(shù)據(jù)修復(fù)邏輯迈着,在萬一發(fā)生不一致時(shí),手工或者自動(dòng)糾正數(shù)據(jù)邪码。
實(shí)現(xiàn):多活的基礎(chǔ)中間件
下面簡(jiǎn)要介紹一下支持以上功能的中間件寥假,我們歸納為多活 5 大基礎(chǔ)組件,之后會(huì)有系列文章霞扬,介紹每個(gè)基礎(chǔ)組件的具體實(shí)現(xiàn)糕韧。
APIRouter : 路由分發(fā)服務(wù)
API Router是一個(gè)HTTP反向代理和負(fù)載均衡器枫振,部署在公有云中作為HTTP API流量的入口,它能識(shí)別出流量的歸屬 shard 萤彩,并根據(jù) shard 將流量轉(zhuǎn)發(fā)到對(duì)應(yīng)的 ezone粪滤。API Router 支持多種路由鍵,可以是地理位置雀扶,也可以是商戶ID杖小,訂單ID等等,最終由 API Router 映射為統(tǒng)一的 Sharding ID愚墓。
Global Zone Service:全局狀態(tài)協(xié)調(diào)器
GZS 維護(hù)著整個(gè)多活的路由表予权,其他所有的服務(wù)都從 GZS 訂閱路由信息。切換機(jī)房的操作也在 GZS 控制臺(tái)中完成浪册。路由表包括:地理圍欄信息扫腺,shard 到 ezone 的歸屬信息,商鋪ID/訂單ID 等路由邏輯層到 shard id 的映射關(guān)系等村象。GZS 通過在 SDK 端建立 Cache笆环,來保證shard 邏輯能夠最快速度執(zhí)行,基本不需要和 GZS 交互厚者,同時(shí)也有實(shí)時(shí)推送機(jī)制躁劣,確保在數(shù)據(jù)變更后能夠快速通知到其他的服務(wù)。
SOA Proxy:內(nèi)部網(wǎng)關(guān)
SOA Proxy 實(shí)現(xiàn)了對(duì) SOA 調(diào)用的路由库菲,執(zhí)行和 API Router 相似的邏輯账忘,但只用在機(jī)房之間進(jìn)行通信的場(chǎng)景。業(yè)務(wù)使用 SOA Proxy 需要對(duì)代碼做一些修改熙宇,把路由信息加入到調(diào)用的上下文中鳖擒。
Data Replication Center:數(shù)據(jù)復(fù)制
DRC 負(fù)責(zé) Mysql 數(shù)據(jù)的實(shí)時(shí)雙向復(fù)制,保證跨機(jī)房延時(shí)在 1s 以內(nèi)奇颠。提供了基于時(shí)間的沖突解決方案败去,確保各個(gè)機(jī)房的數(shù)據(jù)一致放航。DRC 除了復(fù)制數(shù)據(jù)烈拒,還對(duì)外提供了數(shù)據(jù)變更的通知,讓業(yè)務(wù)能夠感知到其他機(jī)房的數(shù)據(jù)變化广鳍,做相應(yīng)的處理荆几,例如清除Cache等。除了DRC赊时,我們還有 ZK復(fù)制工具吨铸,RMQ 復(fù)制工具,Redis復(fù)制工具祖秒,基本每個(gè)數(shù)據(jù)層次诞吱,都有對(duì)應(yīng)的復(fù)制方案舟奠。
Data Access Layer:數(shù)據(jù)訪問
數(shù)據(jù)訪問層支撐了 Globa Zone 的邏輯,還提供了最后一道保護(hù)房维,拒絕路由錯(cuò)誤的數(shù)據(jù)寫入沼瘫,是多活最底層的支撐。
未來:下一步多活的計(jì)劃
目前餓了么的服務(wù)已經(jīng)部署到2個(gè)異地機(jī)房咙俩,下一步我們會(huì)擴(kuò)展到3-4個(gè)機(jī)房耿戚,并且在公有云上建立一個(gè)新的ezone,充分利用公有云的強(qiáng)大的擴(kuò)展能力阿趁,未來我們將能夠快速的在全世界各地搭建數(shù)據(jù)中心膜蛔,也能夠快速的利用各種公有云基礎(chǔ)設(shè)施,實(shí)現(xiàn)全球規(guī)模的高可用和擴(kuò)展性脖阵。
文獻(xiàn)引用:
Latency numbers every programmer should know
作者介紹:
李雙濤皂股,餓了么框架工具部高級(jí)架構(gòu)師,參與了整個(gè)餓了么多活的設(shè)計(jì)和實(shí)施過程独撇。職業(yè)生涯中屑墨,有兩次參與這種大規(guī)模的整站高可用改造,一次在 Cisco Webex纷铣,一次在餓了么卵史,積累了一些高可用和異地多活方面的經(jīng)驗(yàn)。
轉(zhuǎn)自:https://zhuanlan.zhihu.com/p/32009822