作者:湯波
“
自 2008 年雙 11 以來拣技,在每年雙 11 超大規(guī)模流量的沖擊上千诬,螞蟻金服都會(huì)不斷突破現(xiàn)有技術(shù)的極限。
2010 年雙 11 的支付峰值為 2 萬筆/分鐘膏斤,到 2017 年雙 11 時(shí)這個(gè)數(shù)字變?yōu)榱?25.6 萬筆/秒徐绑。
2018 年雙 11 的支付峰值為 48 萬筆/秒,2019 年雙 11 支付峰值為 54.4 萬筆/秒莫辨,創(chuàng)下新紀(jì)錄傲茄,是 2009 年第一次雙 11 的 1360 倍。
在如此之大的支付 TPS 背后除了削峰等錦上添花的應(yīng)用級(jí)優(yōu)化沮榜,最解渴最實(shí)質(zhì)的招數(shù)當(dāng)數(shù)基于分庫分表的單元化了盘榨,螞蟻技術(shù)稱之為 LDC(邏輯數(shù)據(jù)中心)。
本文不打算討論具體到代碼級(jí)的分析蟆融,而是嘗試用最簡(jiǎn)單的描述來說明其中最大快人心的原理草巡。
我想關(guān)心分布式系統(tǒng)設(shè)計(jì)的人都曾被下面這些問題所困擾過:
支付寶海量支付背后最解渴的設(shè)計(jì)是啥?換句話說型酥,實(shí)現(xiàn)支付寶高 TPS 的最關(guān)鍵的設(shè)計(jì)是啥山憨?
LDC 是啥?LDC 怎么實(shí)現(xiàn)異地多活和異地災(zāi)備的弥喉?
CAP 魔咒到底是啥郁竟?P 到底怎么理解?
什么是腦裂由境?跟 CAP 又是啥關(guān)系棚亩?
什么是 PAXOS蓖议,它解決了啥問題?
PAXOS 和 CAP 啥關(guān)系讥蟆?PAXOS 可以逃脫 CAP 魔咒么勒虾?
Oceanbase 能逃脫 CAP 魔咒么?
如果你對(duì)這些感興趣攻询,不妨看一場(chǎng)赤裸裸的論述从撼,拒絕使用晦澀難懂的詞匯,直面最本質(zhì)的邏輯钧栖。
LDC 和單元化
LDC(logic data center)是相對(duì)于傳統(tǒng)的(Internet Data Center-IDC)提出的低零,邏輯數(shù)據(jù)中心所表達(dá)的中心思想是無論物理結(jié)構(gòu)如何的分布,整個(gè)數(shù)據(jù)中心在邏輯上是協(xié)同和統(tǒng)一的拯杠。這句話暗含的是強(qiáng)大的體系設(shè)計(jì)掏婶,分布式系統(tǒng)的挑戰(zhàn)就在于整體協(xié)同工作(可用性,分區(qū)容忍性)和統(tǒng)一(一致性)潭陪。單元化是大型互聯(lián)網(wǎng)系統(tǒng)的必然選擇趨勢(shì)雄妥,舉個(gè)最最通俗的例子來說明單元化。我們總是說 TPS 很難提升依溯,確實(shí)任何一家互聯(lián)網(wǎng)公司(比如淘寶老厌、攜程、新浪)它的交易 TPS 頂多以十萬計(jì)量(平均水平)黎炉,很難往上串了枝秤。因?yàn)閿?shù)據(jù)庫存儲(chǔ)層瓶頸的存在再多水平擴(kuò)展的服務(wù)器都無法繞開,而從整個(gè)互聯(lián)網(wǎng)的視角看慷嗜,全世界電商的交易 TPS 可以輕松上億淀弹。這個(gè)例子帶給我們一些思考:為啥幾家互聯(lián)網(wǎng)公司的 TPS 之和可以那么大,服務(wù)的用戶數(shù)規(guī)模也極為嚇人庆械,而單個(gè)互聯(lián)網(wǎng)公司的 TPS 卻很難提升薇溃?究其本質(zhì),每家互聯(lián)網(wǎng)公司都是一個(gè)獨(dú)立的大型單元缭乘,他們各自服務(wù)自己的用戶互不干擾沐序。這就是單元化的基本特性,任何一家互聯(lián)網(wǎng)公司堕绩,其想要成倍的擴(kuò)大自己系統(tǒng)的服務(wù)能力薄啥,都必然會(huì)走向單元化之路。它的本質(zhì)是分治逛尚,我們把廣大的用戶分為若干部分,同時(shí)把系統(tǒng)復(fù)制多份刁愿,每一份都獨(dú)立部署绰寞,每一份系統(tǒng)都服務(wù)特定的一群用戶。以淘寶舉例,這樣之后滤钱,就會(huì)有很多個(gè)淘寶系統(tǒng)分別為不同的用戶服務(wù)觉壶,每個(gè)淘寶系統(tǒng)都做到十萬 TPS 的話,N 個(gè)這樣的系統(tǒng)就可以輕松做到 N十萬的 TPS 了件缸。LDC 實(shí)現(xiàn)的關(guān)鍵就在于單元化系統(tǒng)架構(gòu)設(shè)計(jì)铜靶,所以在螞蟻內(nèi)部,LDC 和單元化是不分家的他炊,這也是很多同學(xué)比較困擾的地方争剿,看似沒啥關(guān)系,實(shí)則是單元化體系設(shè)計(jì)成就了 LDC痊末。小結(jié):*分庫分表解決的最大痛點(diǎn)是數(shù)據(jù)庫單點(diǎn)瓶頸蚕苇,這個(gè)瓶頸的產(chǎn)生是由現(xiàn)代二進(jìn)制數(shù)據(jù)存儲(chǔ)體系決定的(即 I/O 速度)。單元化只是分庫分表后系統(tǒng)部署的一種方式凿叠,這種部署模式在災(zāi)備方面也發(fā)揮了極大的優(yōu)勢(shì)涩笤。
系統(tǒng)架構(gòu)演化史
幾乎任何規(guī)模的互聯(lián)網(wǎng)公司,都有自己的系統(tǒng)架構(gòu)迭代和更新盒件,大致的演化路徑都大同小異蹬碧。
最早一般為了業(yè)務(wù)快速上線,所有功能都會(huì)放到一個(gè)應(yīng)用里炒刁,系統(tǒng)架構(gòu)如下圖所示:
這樣的架構(gòu)顯然是有問題的恩沽,單機(jī)有著明顯的單點(diǎn)效應(yīng),單機(jī)的容量和性能都是很局限的切心,而使用中小型機(jī)會(huì)帶來大量的浪費(fèi)飒筑。
隨著業(yè)務(wù)發(fā)展,這個(gè)矛盾逐漸轉(zhuǎn)變?yōu)橹饕苷阑瑁虼斯こ處焸儾捎昧艘韵录軜?gòu):
這是整個(gè)公司第一次觸碰到分布式协屡,也就是對(duì)某個(gè)應(yīng)用進(jìn)行了水平擴(kuò)容,它將多個(gè)微機(jī)的計(jì)算能力團(tuán)結(jié)了起來全谤,可以完勝同等價(jià)格的中小型機(jī)器肤晓。慢慢的,大家發(fā)現(xiàn)认然,應(yīng)用服務(wù)器 CPU 都很正常了补憾,但是還是有很多慢請(qǐng)求,究其原因卷员,是因?yàn)閱吸c(diǎn)數(shù)據(jù)庫帶來了性能瓶頸盈匾。
于是程序員們決定使用主從結(jié)構(gòu)的數(shù)據(jù)庫集群,如下圖所示:
其中大部分讀操作可以直接訪問從庫毕骡,從而減輕主庫的壓力削饵。然而這種方式還是無法解決寫瓶頸岩瘦,寫依舊需要主庫來處理,當(dāng)業(yè)務(wù)量量級(jí)再次增高時(shí)窿撬,寫已經(jīng)變成刻不容緩的待處理瓶頸启昧。
這時(shí)候,分庫分表方案出現(xiàn)了:
分庫分表不僅可以對(duì)相同的庫進(jìn)行拆分劈伴,還可以對(duì)相同的表進(jìn)行拆分密末,對(duì)表進(jìn)行拆分的方式叫做水平拆分。不同功能的表放到不同的庫里跛璧,一般對(duì)應(yīng)的是垂直拆分(按照業(yè)務(wù)功能進(jìn)行拆分)严里,此時(shí)一般還對(duì)應(yīng)了微服務(wù)化。這種方法做到極致基本能支撐 TPS 在萬級(jí)甚至更高的訪問量了赡模。然而隨著相同應(yīng)用擴(kuò)展的越多田炭,每個(gè)數(shù)據(jù)庫的鏈接數(shù)也巨量增長,這讓數(shù)據(jù)庫本身的資源成為了瓶頸漓柑。這個(gè)問題產(chǎn)生的本質(zhì)是全量數(shù)據(jù)無差別的分享了所有的應(yīng)用資源教硫,比如 A 用戶的請(qǐng)求在負(fù)載均衡的分配下可能分配到任意一個(gè)應(yīng)用服務(wù)器上,因而所有應(yīng)用全部都要鏈接 A 用戶所在的分庫辆布,數(shù)據(jù)庫連接數(shù)就變成笛卡爾乘積了瞬矩。在本質(zhì)點(diǎn)說,這種模式的資源隔離性還不夠徹底锋玲。要解決這個(gè)問題景用,就需要把識(shí)別用戶分庫的邏輯往上層移動(dòng),從數(shù)據(jù)庫層移動(dòng)到路由網(wǎng)關(guān)層惭蹂。這樣一來伞插,從應(yīng)用服務(wù)器 a 進(jìn)來的來自 A 客戶的所有請(qǐng)求必然落庫到 DB-A,因此 a 也不用鏈接其他的數(shù)據(jù)庫實(shí)例了盾碗,這樣一個(gè)單元化的雛形就誕生了媚污。思考一下,應(yīng)用間其實(shí)也存在交互(比如 A 轉(zhuǎn)賬給 B)廷雅,也就意味著耗美,應(yīng)用不需要鏈接其他的數(shù)據(jù)庫了,但是還需要鏈接其他應(yīng)用航缀。如果是常見的 RPC 框架如 Dubbo 等商架,使用的是 TCP/IP 協(xié)議,那么等同于把之前與數(shù)據(jù)庫建立的鏈接芥玉,換成與其他應(yīng)用之間的鏈接了蛇摸。為啥這樣就消除瓶頸了呢?首先由于合理的設(shè)計(jì)灿巧,應(yīng)用間的數(shù)據(jù)交互并不巨量赶袄,其次應(yīng)用間的交互可以共享 TCP 鏈接诬烹,比如 A->B 之間的 Socket 鏈接可以被 A 中的多個(gè)線程復(fù)用。
而一般的數(shù)據(jù)庫如 MySQL 則不行弃鸦,所以 MySQL 才需要數(shù)據(jù)庫鏈接池。
如上圖所示幢痘,但我們把整套系統(tǒng)打包為單元化時(shí)唬格,每一類的數(shù)據(jù)從進(jìn)單元開始就注定在這個(gè)單元被消化,由于這種徹底的隔離性颜说,整個(gè)單元可以輕松的部署到任意機(jī)房而依然能保證邏輯上的統(tǒng)一购岗。
下圖為一個(gè)三地五機(jī)房的部署方式:
螞蟻單元化架構(gòu)實(shí)踐
螞蟻支付寶應(yīng)該是國內(nèi)最大的支付工具,其在雙 11 等活動(dòng)日當(dāng)日的支付 TPS 可達(dá)幾十萬級(jí)门粪,未來這個(gè)數(shù)字可能會(huì)更大喊积,這決定了螞蟻單元化架構(gòu)從容量要求上看必然從單機(jī)房走向多機(jī)房。另一方面玄妈,異地災(zāi)備也決定了這些 IDC 機(jī)房必須是異地部署的乾吻。整體上支付寶也采用了三地五中心(IDC 機(jī)房)來保障系統(tǒng)的可用性。跟上文中描述的有所不同的是拟蜻,支付寶將單元分成了三類(也稱 CRG 架構(gòu)):
RZone(Region Zone):直譯可能有點(diǎn)反而不好理解绎签。實(shí)際上就是所有可以分庫分表的業(yè)務(wù)系統(tǒng)整體部署的最小單元。每個(gè) RZone 連上數(shù)據(jù)庫就可以撐起一片天空酝锅,把業(yè)務(wù)跑的溜溜的诡必。
-
GZone(Global Zone):全局單元,意味著全局只有一份搔扁。部署了不可拆分的數(shù)據(jù)和服務(wù)爸舒,比如系統(tǒng)配置等。
實(shí)際情況下稿蹲,GZone 異地也會(huì)部署扭勉,不過僅是用于災(zāi)備,同一時(shí)刻场绿,只有一地 GZone 進(jìn)行全局服務(wù)剖效。GZone 一般被 RZone 依賴,提供的大部分是讀取服務(wù)焰盗。
-
CZone(City Zone):顧名思義璧尸,這是以城市為單位部署的單元。同樣部署了不可拆分的數(shù)據(jù)和服務(wù)熬拒,比如用戶賬號(hào)服務(wù)爷光,客戶信息服務(wù)等。理論上 CZone 會(huì)被 RZone 以比訪問 GZone 高很多的頻率進(jìn)行訪問澎粟。
CZone 是基于特定的 GZone 場(chǎng)景進(jìn)行優(yōu)化的一種單元蛀序,它把 GZone 中有些有著”寫讀時(shí)間差現(xiàn)象”的數(shù)據(jù)和服務(wù)進(jìn)行了的單獨(dú)部署欢瞪,這樣 RZone 只需要訪問本地的 CZone 即可,而不是訪問異地的 GZone徐裸。
“寫讀時(shí)間差現(xiàn)象”是螞蟻架構(gòu)師們根據(jù)實(shí)踐統(tǒng)計(jì)總結(jié)的遣鼓,他們發(fā)現(xiàn)大部分情況下,一個(gè)數(shù)據(jù)被寫入后重贺,都會(huì)過足夠長的時(shí)間后才會(huì)被訪問骑祟。生活中這種例子很常見,我們辦完銀行卡后可能很久才會(huì)存第一筆錢气笙;我們創(chuàng)建微博賬號(hào)后次企,可能想半天才會(huì)發(fā)微博;我們下載創(chuàng)建淘寶賬號(hào)后潜圃,可能得瀏覽好幾分鐘才會(huì)下單買東西缸棵。當(dāng)然了這些例子中的時(shí)間差遠(yuǎn)遠(yuǎn)超過了系統(tǒng)同步時(shí)間。一般來說異地的延時(shí)在 100ms 以內(nèi)谭期,所以只要滿足某地 CZone 寫入數(shù)據(jù)后 100ms 以后才用這個(gè)數(shù)據(jù)堵第,這樣的數(shù)據(jù)和服務(wù)就適合放到 CZone 中。相信大家看到這都會(huì)問:為啥分這三種單元崇堵?其實(shí)其背后對(duì)應(yīng)的是不同性質(zhì)的數(shù)據(jù)型诚,而服務(wù)不過是對(duì)數(shù)據(jù)的操作集。下面我們來根據(jù)數(shù)據(jù)性質(zhì)的不同來解釋支付寶的 CRG 架構(gòu)鸳劳。當(dāng)下幾乎所有互聯(lián)網(wǎng)公司的分庫分表規(guī)則都是根據(jù)用戶 ID 來制定的狰贯。而圍繞用戶來看整個(gè)系統(tǒng)的數(shù)據(jù)可以分為以下兩類:
用戶流水型數(shù)據(jù):典型的有用戶的訂單、用戶發(fā)的評(píng)論赏廓、用戶的行為記錄等涵紊。
這些數(shù)據(jù)都是用戶行為產(chǎn)生的流水型數(shù)據(jù),具備天然的用戶隔離性幔摸,比如 A 用戶的 App 上絕對(duì)看不到 B 用戶的訂單列表摸柄。所以此類數(shù)據(jù)非常適合分庫分表后獨(dú)立部署服務(wù)。
用戶間共享型數(shù)據(jù):這種類型的數(shù)據(jù)又分兩類既忆。一類共享型數(shù)據(jù)是像賬號(hào)驱负、個(gè)人博客等可能會(huì)被所有用戶請(qǐng)求訪問的用戶數(shù)據(jù)。
比如 A 向 B 轉(zhuǎn)賬患雇,A 給 B 發(fā)消息跃脊,這時(shí)候需要確認(rèn) B 賬號(hào)是否存在;又比如 A 想看 B 的個(gè)人博客之類的苛吱。
另外一類是用戶無關(guān)型數(shù)據(jù)酪术,像商品、系統(tǒng)配置(匯率、優(yōu)惠政策)绘雁、財(cái)務(wù)統(tǒng)計(jì)等這些非用戶緯度的數(shù)據(jù)橡疼,很難說跟具體的某一類用戶掛鉤,可能涉及到所有用戶庐舟。
比如商品欣除,假設(shè)按商品所在地來存放商品數(shù)據(jù)(這需要雙維度分庫分表),那么上海的用戶仍然需要訪問杭州的商品挪略。
這就又構(gòu)成跨地跨 Zone 訪問了耻涛,還是達(dá)不到單元化的理想狀態(tài),而且雙維度分庫分表會(huì)給整個(gè) LDC 運(yùn)維帶來復(fù)雜度提升瘟檩。
注:網(wǎng)上和支付寶內(nèi)部有另外一些分法,比如流水型和狀態(tài)性澈蟆,有時(shí)候還會(huì)分為三類:流水型墨辛、狀態(tài)型和配置型。個(gè)人覺得這些分法雖然嘗試去更高層次的抽象數(shù)據(jù)分類趴俘,但實(shí)際上邊界很模糊睹簇,適得其反。直觀的類比寥闪,我們可以很輕易的將上述兩類數(shù)據(jù)對(duì)應(yīng)的服務(wù)劃分為 RZone 和 GZone太惠,RZone 包含的就是分庫分表后負(fù)責(zé)固定客戶群體的服務(wù),GZone 則包含了用戶間共享的公共數(shù)據(jù)對(duì)應(yīng)的服務(wù)疲憋。到這里為止凿渊,一切都很完美,這也是主流的單元化話題了缚柳。對(duì)比支付寶的 CRG 架構(gòu)埃脏,我們一眼就發(fā)現(xiàn)少了 C(City Zone),CZone 確實(shí)是螞蟻在單元化實(shí)踐領(lǐng)域的一個(gè)創(chuàng)新點(diǎn)秋忙。再來分析下 GZone彩掐,GZone 之所以只能單地部署,是因?yàn)槠鋽?shù)據(jù)要求被所有用戶共享灰追,無法分庫分表堵幽,而多地部署會(huì)帶來由異地延時(shí)引起的不一致。比如實(shí)時(shí)風(fēng)控系統(tǒng)弹澎,如果多地部署朴下,某個(gè) RZone 直接讀取本地的話,很容易讀取到舊的風(fēng)控狀態(tài)裁奇,這是很危險(xiǎn)的桐猬。這時(shí)螞蟻架構(gòu)師們問了自己一個(gè)問題——難道所有數(shù)據(jù)受不了延時(shí)么?這個(gè)問題像是打開了新世界的大門刽肠,通過對(duì) RZone 已有業(yè)務(wù)的分析溃肪,架構(gòu)師們發(fā)現(xiàn) 80% 甚至更高的場(chǎng)景下免胃,數(shù)據(jù)更新后都不要求立馬被讀取到。也就是上文提到的”寫讀時(shí)間差現(xiàn)象”惫撰,那么這就好辦了羔沙,對(duì)于這類數(shù)據(jù),我們?cè)试S每個(gè)地區(qū)的 RZone 服務(wù)直接訪問本地厨钻,為了給這些 RZone 提供這些數(shù)據(jù)的本地訪問能力扼雏,螞蟻架構(gòu)師設(shè)計(jì)出了 CZone。在 CZone 的場(chǎng)景下夯膀,寫請(qǐng)求一般從 GZone 寫入公共數(shù)據(jù)所在庫诗充,然后同步到整個(gè) OB 集群,然后由 CZone 提供讀取服務(wù)诱建。比如支付寶的會(huì)員服務(wù)就是如此蝴蜓。即便架構(gòu)師們?cè)O(shè)計(jì)了完美的 CRG,但即便在螞蟻的實(shí)際應(yīng)用中俺猿,各個(gè)系統(tǒng)仍然存在不合理的 CRG 分類茎匠,尤其是 CG 不分的現(xiàn)象很常見。
支付寶單元化的異地多活和災(zāi)備
流量挑撥技術(shù)探秘簡(jiǎn)介
單元化后押袍,異地多活只是多地部署而已诵冒。比如上海的兩個(gè)單元為 ID 范圍為 [0019],[4059] 的用戶服務(wù)谊惭。而杭州的兩個(gè)單元為 ID 為 [20~39]和[60,79]的用戶服務(wù)汽馋,這樣上海和杭州就是異地雙活的。支付寶對(duì)單元化的基本要求是每個(gè)單元都具備服務(wù)所有用戶的能力圈盔,即——具體的那個(gè)單元服務(wù)哪些用戶是可以動(dòng)態(tài)配置的惭蟋。所以異地雙活的這些單元還充當(dāng)了彼此的備份。發(fā)現(xiàn)工作中冷備熱備已經(jīng)被用的很亂了药磺。最早冷備是指數(shù)據(jù)庫在備份數(shù)據(jù)時(shí)需要關(guān)閉后進(jìn)行備份(也叫離線備份)告组,防止數(shù)據(jù)備份過程中又修改了,不需要關(guān)閉即在運(yùn)行過程中進(jìn)行數(shù)據(jù)備份的方式叫做熱備(也叫在線備份)癌佩。也不知道從哪一天開始木缝,冷備在主備系統(tǒng)里代表了這臺(tái)備用機(jī)器是關(guān)閉狀態(tài)的,只有主服務(wù)器掛了之后围辙,備服務(wù)器才會(huì)被啟動(dòng)我碟。而相同的熱備變成了備服務(wù)器也是啟動(dòng)的瞬内,只是沒有流量而已秕衙,一旦主服務(wù)器掛了之后,流量自動(dòng)打到備服務(wù)器上慷蠕。本文不打算用第二種理解,因?yàn)楦杏X有點(diǎn)野厘托。為了做到每個(gè)單元訪問哪些用戶變成可配置友雳,支付寶要求單元化管理系統(tǒng)具備流量到單元的可配置以及單元到 DB 的可配置能力。
如下圖所示:
其中 Spanner 是螞蟻基于 Nginx 自研的反向代理網(wǎng)關(guān)铅匹,也很好理解押赊,有些請(qǐng)求我們希望在反向代理層就被轉(zhuǎn)發(fā)至其他 IDC 的 Spanner 而無需進(jìn)入后端服務(wù),如圖箭頭 2 所示包斑。那么對(duì)于應(yīng)該在本 IDC 處理的請(qǐng)求流礁,就直接映射到對(duì)應(yīng)的 RZ 即可,如圖箭頭 1罗丰。進(jìn)入后端服務(wù)后神帅,理論上如果請(qǐng)求只是讀取用戶流水型數(shù)據(jù),那么一般不會(huì)再進(jìn)行路由了萌抵。然而枕稀,對(duì)于有些場(chǎng)景來說,A 用戶的一個(gè)請(qǐng)求可能關(guān)聯(lián)了對(duì) B 用戶數(shù)據(jù)的訪問谜嫉,比如 A 轉(zhuǎn)賬給 B,A 扣完錢后要調(diào)用賬務(wù)系統(tǒng)去增加 B 的余額凹联。這時(shí)候就涉及到再次的路由沐兰,同樣有兩個(gè)結(jié)果:跳轉(zhuǎn)到其他 IDC(如圖箭頭 3)或是跳轉(zhuǎn)到本 IDC 的其他 RZone(如圖箭頭 4)。
RZone 到 DB 數(shù)據(jù)分區(qū)的訪問這是事先配置好的蔽挠,上圖中 RZ 和 DB 數(shù)據(jù)分區(qū)的關(guān)系為:
RZ0* --> aRZ1* --> bRZ2* --> cRZ3* --> d
下面我們舉個(gè)例子來說明整個(gè)流量挑撥的過程住闯,假設(shè) C 用戶所屬的數(shù)據(jù)分區(qū)是 c,而 C 用戶在杭州訪問了 cashier.alipay.com(隨便編的)澳淑。
①目前支付寶默認(rèn)會(huì)按照地域來路由流量,具體的實(shí)現(xiàn)承載者是自研的 GLSB(Global Server Load Balancing):
https://developer.alipay.com/article/1889
它會(huì)根據(jù)請(qǐng)求者的 IP量窘,自動(dòng)將 cashier.alipay.com 解析為杭州 IDC 的 IP 地址(或者跳轉(zhuǎn)到 IDC 所在的域名)氢拥。大家自己搞過網(wǎng)站的化應(yīng)該知道大部分 DNS 服務(wù)商的地址都是靠人去配置的,GLSB 屬于動(dòng)態(tài)配置域名的系統(tǒng)冬殃,網(wǎng)上也有比較火的類似產(chǎn)品审葬,比如花生殼之類(建過私站的同學(xué)應(yīng)該很熟悉)的。②好了痴荐,到此為止蹬昌,用戶的請(qǐng)求來到了 IDC-1 的 Spanner 集群服務(wù)器上攀隔,Spanner 從內(nèi)存中讀取到了路由配置皂贩,知道了這個(gè)請(qǐng)求的主體用戶 C 所屬的 RZ3* 不再本 IDC,于是直接轉(zhuǎn)到了 IDC-2 進(jìn)行處理昆汹。③進(jìn)入 IDC-2 之后明刷,根據(jù)流量配比規(guī)則,該請(qǐng)求被分配到了 RZ3B 進(jìn)行處理满粗。④RZ3B 得到請(qǐng)求后對(duì)數(shù)據(jù)分區(qū) c 進(jìn)行訪問辈末。⑤處理完畢后原路返回。大家應(yīng)該發(fā)現(xiàn)問題所在了映皆,如果再來一個(gè)這樣的請(qǐng)求挤聘,豈不是每次都要跨地域進(jìn)行調(diào)用和返回體傳遞?確實(shí)是存在這樣的問題的捅彻,對(duì)于這種問題组去,支付寶架構(gòu)師們決定繼續(xù)把決策邏輯往用戶終端推移。比如步淹,每個(gè) IDC 機(jī)房都會(huì)有自己的域名(真實(shí)情況可能不是這樣命名的):
IDC-1 對(duì)應(yīng) cashieridc-1.alipay.com
IDC-2 對(duì)應(yīng) cashieridc-2.alipay.com
那么請(qǐng)求從 IDC-1 涮過一遍返回時(shí)會(huì)將前端請(qǐng)求跳轉(zhuǎn)到 cashieridc-2.alipay.com 去(如果是 App从隆,只需要替換 rest 調(diào)用的接口域名),后面所有用戶的行為都會(huì)在這個(gè)域名上發(fā)生缭裆,就避免了走一遍 IDC-1 帶來的延時(shí)键闺。
支付寶災(zāi)備機(jī)制
流量挑撥是災(zāi)備切換的基礎(chǔ)和前提條件,發(fā)生災(zāi)難后的通用方法就是把陷入災(zāi)難的單元的流量重新打到正常的單元上去澈驼,這個(gè)流量切換的過程俗稱切流购桑。支付寶 LDC 架構(gòu)下的災(zāi)備有三個(gè)層次:
同機(jī)房單元間災(zāi)備
同城機(jī)房間災(zāi)備
異地機(jī)房間災(zāi)備
同機(jī)房單元間災(zāi)備:災(zāi)難發(fā)生可能性相對(duì)最高(但其實(shí)也很小)缭贡。對(duì) LDC 來說谍失,最小的災(zāi)難就是某個(gè)單元由于一些原因(局部插座斷開、線路老化抹竹、人為操作失誤)宕機(jī)了。從上節(jié)里的圖中可以看到每組 RZ 都有 A袄琳,B 兩個(gè)單元,這就是用來做同機(jī)房災(zāi)備的逗旁,并且 AB 之間也是雙活雙備的介陶。正常情況下 AB 兩個(gè)單元共同分擔(dān)所有的請(qǐng)求,一旦 A 單元掛了某残,B 單元將自動(dòng)承擔(dān) A 單元的流量份額。這個(gè)災(zāi)備方案是默認(rèn)的澳厢。同城機(jī)房間災(zāi)備:災(zāi)難發(fā)生可能性相對(duì)更小线得。這種災(zāi)難發(fā)生的原因一般是機(jī)房電線網(wǎng)線被挖斷,或者機(jī)房維護(hù)人員操作失誤導(dǎo)致的角雷。
在這種情況下,就需要人工的制定流量挑撥(切流)方案了檩咱。下面我們舉例說明這個(gè)過程,如下圖所示為上海的兩個(gè) IDC 機(jī)房炊汹。
整個(gè)切流配置過程分兩步,首先需要將陷入災(zāi)難的機(jī)房中 RZone 對(duì)應(yīng)的數(shù)據(jù)分區(qū)的訪問權(quán)配置進(jìn)行修改霸褒。假設(shè)我們的方案是由 IDC-2 機(jī)房的 RZ2 和 RZ3 分別接管 IDC-1 中的 RZ0 和 RZ1。那么首先要做的是把數(shù)據(jù)分區(qū) a殊轴,b 對(duì)應(yīng)的訪問權(quán)從 RZ0 和 RZ1 收回,分配給 RZ2 和 RZ3淹接。
即將(如上圖所示為初始映射):
RZ0* --> aRZ1* --> bRZ2* --> cRZ3* --> d
變?yōu)椋?/p>
RZ0* --> /RZ1* --> /RZ2* --> aRZ2* --> cRZ3* --> bRZ3* --> d
然后再修改用戶 ID 和 RZ 之間的映射配置塑悼。假設(shè)之前為:
[00-24] --> RZ0A(50%),RZOB(50%)[25-49] --> RZ1A(50%),RZ1B(50%)[50-74] --> RZ2A(50%),RZ2B(50%)[75-99] --> RZ3A(50%),RZ3B(50%)
那么按照災(zāi)備方案的要求,這個(gè)映射配置將變?yōu)椋?/p>
[00-24] --> RZ2A(50%),RZ2B(50%)[25-49] --> RZ3A(50%),RZ3B(50%)[50-74] --> RZ2A(50%),RZ2B(50%)[75-99] --> RZ3A(50%),RZ3B(50%)
這樣之后斑鸦,所有流量將會(huì)被打到 IDC-2 中,期間部分已經(jīng)向 IDC-1 發(fā)起請(qǐng)求的用戶會(huì)收到失敗并重試的提示嘱巾。實(shí)際情況中,整個(gè)過程并不是災(zāi)難發(fā)生后再去做的问拘,整個(gè)切換的流程會(huì)以預(yù)案配置的形式事先準(zhǔn)備好骤坐,推送給每個(gè)流量挑撥客戶端(集成到了所有的服務(wù)和 Spanner 中)。這里可以思考下顶岸,為何先切數(shù)據(jù)庫映射霹抛,再切流量呢霞篡?這是因?yàn)槿绻惹辛髁坷时馕吨罅孔⒍ㄊ〉恼?qǐng)求會(huì)被打到新的正常單元上去寸爆,從而影響系統(tǒng)的穩(wěn)定性(數(shù)據(jù)庫還沒準(zhǔn)備好)。異地機(jī)房間災(zāi)備:這個(gè)基本上跟同城機(jī)房間災(zāi)備一致(這也是單元化的優(yōu)點(diǎn))魔种,不再贅述。
支付寶單元化的異地多活和災(zāi)備
回顧 CAP
①CAP 的定義
CAP 原則是指任意一個(gè)分布式系統(tǒng)心铃,同時(shí)最多只能滿足其中的兩項(xiàng),而無法同時(shí)滿足三項(xiàng)愉棱。
所謂的分布式系統(tǒng),說白了就是一件事一個(gè)人做的朋其,現(xiàn)在分給好幾個(gè)人一起干。我們先簡(jiǎn)單回顧下 CAP 各個(gè)維度的含義:
Consistency(一致性)袱蚓,這個(gè)理解起來很簡(jiǎn)單体斩,就是每時(shí)每刻每個(gè)節(jié)點(diǎn)上的同一份數(shù)據(jù)都是一致的。
這就要求任何更新都是原子的源武,即要么全部成功,要么全部失敗闹究。想象一下使用分布式事務(wù)來保證所有系統(tǒng)的原子性是多么低效的一個(gè)操作。
Availability(可用性),這個(gè)可用性看起來很容易理解用踩,但真正說清楚的不多姊扔。我更愿意把可用性解釋為:任意時(shí)刻系統(tǒng)都可以提供讀寫服務(wù)佛南。
舉個(gè)例子,當(dāng)我們用事務(wù)將所有節(jié)點(diǎn)鎖住來進(jìn)行某種寫操作時(shí)妈拌,如果某個(gè)節(jié)點(diǎn)發(fā)生不可用的情況尘分,會(huì)讓整個(gè)系統(tǒng)不可用。
對(duì)于分片式的 NoSQL 中間件集群(Redis,Memcached)來說私股,一旦一個(gè)分片歇菜了黄娘,整個(gè)系統(tǒng)的數(shù)據(jù)也就不完整了优床,讀取宕機(jī)分片的數(shù)據(jù)就會(huì)沒響應(yīng)杂伟,也就是不可用了幽钢。
需要說明一點(diǎn),哪些選擇 CP 的分布式系統(tǒng)喧笔,并不是代表可用性就完全沒有了帽驯,只是可用性沒有保障了。
為了增加可用性保障书闸,這類中間件往往都提供了”分片集群+復(fù)制集”的方案尼变。
Partition tolerance(分區(qū)容忍性),這個(gè)可能也是很多文章都沒說清楚的。P 并不是像 CA 一樣是一個(gè)獨(dú)立的性質(zhì)嫌术,它依托于 CA 來進(jìn)行討論。
參考文獻(xiàn)中的解釋:”除非整個(gè)網(wǎng)絡(luò)癱瘓比然,否則任何時(shí)刻系統(tǒng)都能正常工作”,言下之意是小范圍的網(wǎng)絡(luò)癱瘓于樟,節(jié)點(diǎn)宕機(jī)传黄,都不會(huì)影響整個(gè)系統(tǒng)的 CA窗声。
我感覺這個(gè)解釋聽著還是有點(diǎn)懵逼扫俺,所以個(gè)人更愿意解釋為當(dāng)節(jié)點(diǎn)之間網(wǎng)絡(luò)不通時(shí)(出現(xiàn)網(wǎng)絡(luò)分區(qū)),可用性和一致性仍然能得到保障香浩。
從個(gè)人角度理解速缆,分區(qū)容忍性又分為“可用性分區(qū)容忍性”和“一致性分區(qū)容忍性”毅臊。
出現(xiàn)分區(qū)時(shí)會(huì)不會(huì)影響可用性的關(guān)鍵在于需不需要所有節(jié)點(diǎn)互相溝通協(xié)作來完成一次事務(wù),不需要的話是鐵定不影響可用性的项栏。
慶幸的是應(yīng)該不太會(huì)有分布式系統(tǒng)會(huì)被設(shè)計(jì)成完成一次事務(wù)需要所有節(jié)點(diǎn)聯(lián)動(dòng)店乐,一定要舉個(gè)例子的話,全同步復(fù)制技術(shù)下的 MySQL 是一個(gè)典型案例。
出現(xiàn)分區(qū)時(shí)會(huì)不會(huì)影響一致性的關(guān)鍵則在于出現(xiàn)腦裂時(shí)有沒有保證一致性的方案,這對(duì)主從同步型數(shù)據(jù)庫(MySQL弹沽、SQL Server)是致命的。
一旦網(wǎng)絡(luò)出現(xiàn)分區(qū)滩褥,產(chǎn)生腦裂,系統(tǒng)會(huì)出現(xiàn)一份數(shù)據(jù)兩個(gè)值的狀態(tài)哩牍,誰都不覺得自己是錯(cuò)的。
需要說明的是摊阀,正常來說同一局域網(wǎng)內(nèi)夺蛇,網(wǎng)絡(luò)分區(qū)的概率非常低,這也是為啥我們最熟悉的數(shù)據(jù)庫(MySQL、SQL Server 等)也是不考慮 P 的原因烙如。
下圖為 CAP 之間的經(jīng)典關(guān)系圖:
還有個(gè)需要說明的地方,其實(shí)分布式系統(tǒng)很難滿足 CAP 的前提條件是這個(gè)系統(tǒng)一定是有讀有寫的毅否,如果只考慮讀亚铁,那么 CAP 很容易都滿足。比如一個(gè)計(jì)算器服務(wù)螟加,接受表達(dá)式請(qǐng)求刀闷,返回計(jì)算結(jié)果,搞成水平擴(kuò)展的分布式仰迁,顯然這樣的系統(tǒng)沒有一致性問題甸昏,網(wǎng)絡(luò)分區(qū)也不怕,可用性也是很穩(wěn)的徐许,所以可以滿足 CAP施蜜。
②CAP 分析方法
先說下 CA 和 P 的關(guān)系,如果不考慮 P 的話雌隅,系統(tǒng)是可以輕松實(shí)現(xiàn) CA 的翻默。
而 P 并不是一個(gè)單獨(dú)的性質(zhì),它代表的是目標(biāo)分布式系統(tǒng)有沒有對(duì)網(wǎng)絡(luò)分區(qū)的情況做容錯(cuò)處理恰起。
如果做了處理修械,就一定是帶有 P 的,接下來再考慮分區(qū)情況下到底選擇了 A 還是 C检盼。所以分析 CAP肯污,建議先確定有沒有對(duì)分區(qū)情況做容錯(cuò)處理。
以下是個(gè)人總結(jié)的分析一個(gè)分布式系統(tǒng) CAP 滿足情況的一般方法:
if( 不存在分區(qū)的可能性 || 分區(qū)后不影響可用性或一致性 || 有影響但考慮了分區(qū)情況-P){ if(可用性分區(qū)容忍性-A under P)) return "AP"; else if(一致性分區(qū)容忍性-C under P) return "CP";}else{ //分區(qū)有影響但沒考慮分區(qū)情況下的容錯(cuò) if(具備可用性-A && 具備一致性-C){ return AC; }}
這里說明下吨枉,如果考慮了分區(qū)容忍性蹦渣,就不需要考慮不分區(qū)情況下的可用性和一致性了(大多是滿足的)。
水平擴(kuò)展應(yīng)用+單數(shù)據(jù)庫實(shí)例的 CAP 分析
讓我們?cè)賮砘仡櫹路植际綉?yīng)用系統(tǒng)的來由貌亭,早年每個(gè)應(yīng)用都是單體的柬唯,跑在一個(gè)服務(wù)器上,服務(wù)器一掛圃庭,服務(wù)就不可用了锄奢。另外一方面,單體應(yīng)用由于業(yè)務(wù)功能復(fù)雜剧腻,對(duì)機(jī)器的要求也逐漸變高拘央,普通的微機(jī)無法滿足這種性能和容量的要求。所以要拆恕酸!還在 IBM 大賣小型商用機(jī)的年代堪滨,阿里巴巴就提出要以分布式微機(jī)替代小型機(jī)。所以我們發(fā)現(xiàn)蕊温,分布式系統(tǒng)解決的最大的痛點(diǎn)袱箱,就是單體單機(jī)系統(tǒng)的可用性問題遏乔。要想高可用,必須分布式发笔。一家互聯(lián)網(wǎng)公司的發(fā)展之路上盟萨,第一次與分布式相遇應(yīng)該都是在單體應(yīng)用的水平擴(kuò)展上。
也就是同一個(gè)應(yīng)用啟動(dòng)了多個(gè)實(shí)例了讨,連接著相同的數(shù)據(jù)庫(為了簡(jiǎn)化問題捻激,先不考慮數(shù)據(jù)庫是否單點(diǎn)),如下圖所示:
這樣的系統(tǒng)天然具有的就是 AP(可用性和分區(qū)容忍性):
一方面解決了單點(diǎn)導(dǎo)致的低可用性問題前计。
另一方面無論這些水平擴(kuò)展的機(jī)器間網(wǎng)絡(luò)是否出現(xiàn)分區(qū)胞谭,這些服務(wù)器都可以各自提供服務(wù),因?yàn)樗麄冎g不需要進(jìn)行溝通男杈。
然而丈屹,這樣的系統(tǒng)是沒有一致性可言的,想象一下每個(gè)實(shí)例都可以往數(shù)據(jù)庫 insert 和 update(注意這里還沒討論到事務(wù))伶棒,那還不亂了套旺垒。于是我們轉(zhuǎn)向了讓 DB 去做這個(gè)事,這時(shí)候”數(shù)據(jù)庫事務(wù)”就被用上了肤无。用大部分公司會(huì)選擇的 MySQL 來舉例先蒋,用了事務(wù)之后會(huì)發(fā)現(xiàn)數(shù)據(jù)庫又變成了單點(diǎn)和瓶頸。單點(diǎn)就像單機(jī)一樣(本例子中不考慮從庫模式)宛渐,理論上就不叫分布式了竞漾,如果一定要分析其 CAP 的話,根據(jù)上面的步驟分析過程應(yīng)該是這樣的:
分區(qū)容忍性:先看有沒有考慮分區(qū)容忍性皇忿,或者分區(qū)后是否會(huì)有影響畴蹭。單臺(tái) MySQL 無法構(gòu)成分區(qū)坦仍,要么整個(gè)系統(tǒng)掛了鳍烁,要么就活著。
可用性分區(qū)容忍性:分區(qū)情況下繁扎,假設(shè)恰好是該節(jié)點(diǎn)掛了幔荒,系統(tǒng)也就不可用了,所以可用性分區(qū)容忍性不滿足梳玫。
一致性分區(qū)容忍性:分區(qū)情況下爹梁,只要可用,單點(diǎn)單機(jī)的最大好處就是一致性可以得到保障提澎。
因此這樣的一個(gè)系統(tǒng)姚垃,個(gè)人認(rèn)為只是滿足了 CP。A 有但不出色盼忌,從這點(diǎn)可以看出积糯,CAP 并不是非黑即白的掂墓。包括常說的 BASE (最終一致性)方案,其實(shí)只是 C 不出色看成,但最終也是達(dá)到一致性的君编,BASE 在一致性上選擇了退讓。關(guān)于分布式應(yīng)用+單點(diǎn)數(shù)據(jù)庫的模式算不算純正的分布式系統(tǒng)川慌,這個(gè)可能每個(gè)人看法有點(diǎn)差異吃嘿,上述只是我個(gè)人的一種理解,是不是分布式系統(tǒng)不重要梦重,重要的是分析過程兑燥。其實(shí)我們討論分布式,就是希望系統(tǒng)的可用性是多個(gè)系統(tǒng)多活的琴拧,一個(gè)掛了另外的也能頂上贪嫂,顯然單機(jī)單點(diǎn)的系統(tǒng)不具備這樣的高可用特性。所以在我看來艾蓝,廣義的說 CAP 也適用于單點(diǎn)單機(jī)系統(tǒng)力崇,單機(jī)系統(tǒng)是 CP 的。說到這里赢织,大家似乎也發(fā)現(xiàn)了亮靴,水平擴(kuò)展的服務(wù)應(yīng)用+數(shù)據(jù)庫這樣的系統(tǒng)的 CAP 魔咒主要發(fā)生在數(shù)據(jù)庫層。因?yàn)榇蟛糠诌@樣的服務(wù)應(yīng)用都只是承擔(dān)了計(jì)算的任務(wù)(像計(jì)算器那樣)于置,本身不需要互相協(xié)作茧吊,所有寫請(qǐng)求帶來的數(shù)據(jù)的一致性問題下沉到了數(shù)據(jù)庫層去解決。想象一下八毯,如果沒有數(shù)據(jù)庫層搓侄,而是應(yīng)用自己來保障數(shù)據(jù)一致性,那么這樣的應(yīng)用之間就涉及到狀態(tài)的同步和交互了话速,ZooKeeper 就是這么一個(gè)典型的例子讶踪。
水平擴(kuò)展應(yīng)用+主從數(shù)據(jù)庫集群的CAP分析
上一節(jié)我們討論了多應(yīng)用實(shí)例+單數(shù)據(jù)庫實(shí)例的模式,這種模式是分布式系統(tǒng)也好泊交,不是分布式系統(tǒng)也罷乳讥,整體是偏 CP 的。現(xiàn)實(shí)中廓俭,技術(shù)人員們也會(huì)很快發(fā)現(xiàn)這種架構(gòu)的不合理性——可用性太低了云石。
于是如下圖所示的模式成為了當(dāng)下大部分中小公司所使用的架構(gòu):
從上圖我可以看到三個(gè)數(shù)據(jù)庫實(shí)例中只有一個(gè)是主庫,其他是從庫研乒。一定程度上汹忠,這種架構(gòu)極大的緩解了”讀可用性”問題,而這樣的架構(gòu)一般會(huì)做讀寫分離來達(dá)到更高的”讀可用性”,幸運(yùn)的是大部分互聯(lián)網(wǎng)場(chǎng)景中讀都占了 80% 以上宽菜,所以這樣的架構(gòu)能得到較長時(shí)間的廣泛應(yīng)用奖地。寫可用性可以通過 Keepalived 這種 HA(高可用)框架來保證主庫是活著的,但仔細(xì)一想就可以明白赋焕,這種方式并沒有帶來性能上的可用性提升参歹。還好,至少系統(tǒng)不會(huì)因?yàn)槟硞€(gè)實(shí)例掛了就都不可用了隆判∪樱可用性勉強(qiáng)達(dá)標(biāo)了,這時(shí)候的 CAP 分析如下:
-
分區(qū)容忍性:依舊先看分區(qū)容忍性侨嘀,主從結(jié)構(gòu)的數(shù)據(jù)庫存在節(jié)點(diǎn)之間的通信臭挽,他們之間需要通過心跳來保證只有一個(gè) Master。
然而一旦發(fā)生分區(qū)咬腕,每個(gè)分區(qū)會(huì)自己選取一個(gè)新的 Master欢峰,這樣就出現(xiàn)了腦裂,常見的主從數(shù)據(jù)庫(MySQL涨共,Oracle 等)并沒有自帶解決腦裂的方案纽帖。所以分區(qū)容忍性是沒考慮的。
一致性:不考慮分區(qū)举反,由于任意時(shí)刻只有一個(gè)主庫懊直,所以一致性是滿足的。
可用性:不考慮分區(qū)火鼻,HA 機(jī)制的存在可以保證可用性室囊,所以可用性顯然也是滿足的。
所以這樣的一個(gè)系統(tǒng)魁索,我們認(rèn)為它是 AC 的融撞。我們?cè)偕钊胙芯肯拢绻l(fā)生腦裂產(chǎn)生數(shù)據(jù)不一致后有一種方式可以仲裁一致性問題粗蔚,是不是就可以滿足 P 了呢尝偎。還真有嘗試通過預(yù)先設(shè)置規(guī)則來解決這種多主庫帶來的一致性問題的系統(tǒng),比如 CouchDB支鸡,它通過版本管理來支持多庫寫入冬念,在其仲裁階段會(huì)通過 DBA 配置的仲裁規(guī)則(也就是合并規(guī)則,比如誰的時(shí)間戳最晚誰的生效)進(jìn)行自動(dòng)仲裁(自動(dòng)合并)牧挣,從而保障最終一致性(BASE),自動(dòng)規(guī)則無法合并的情況則只能依賴人工決策了醒陆。
螞蟻單元化 LDC 架構(gòu) CAP 分析
①戰(zhàn)勝分區(qū)容忍性
在討論螞蟻 LDC 架構(gòu)的 CAP 之前瀑构,我們?cè)賮硐胂敕謪^(qū)容忍性有啥值得一提的,為啥很多大名鼎鼎的 BASE(最終一致性)體系系統(tǒng)都選擇損失實(shí)時(shí)一致性,而不是丟棄分區(qū)容忍性呢寺晌?
分區(qū)的產(chǎn)生一般有兩種情況:
某臺(tái)機(jī)器宕機(jī)了世吨,過一會(huì)兒又重啟了,看起來就像失聯(lián)了一段時(shí)間呻征,像是網(wǎng)絡(luò)不可達(dá)一樣耘婚。
異地部署情況下,異地多活意味著每一地都可能會(huì)產(chǎn)生數(shù)據(jù)寫入陆赋,而異地之間偶爾的網(wǎng)絡(luò)延時(shí)尖刺(網(wǎng)絡(luò)延時(shí)曲線圖陡增)沐祷、網(wǎng)絡(luò)故障都會(huì)導(dǎo)致小范圍的網(wǎng)絡(luò)分區(qū)產(chǎn)生。
前文也提到過攒岛,如果一個(gè)分布式系統(tǒng)是部署在一個(gè)局域網(wǎng)內(nèi)的(一個(gè)物理機(jī)房?jī)?nèi))赖临,那么個(gè)人認(rèn)為分區(qū)的概率極低,即便有復(fù)雜的拓?fù)湓志猓埠苌贂?huì)有在同一個(gè)機(jī)房里出現(xiàn)網(wǎng)絡(luò)分區(qū)的情況兢榨。
而異地這個(gè)概率會(huì)大大增高,所以螞蟻的三地五中心必須需要思考這樣的問題顺饮,分區(qū)容忍不能丟吵聪!
同樣的情況還會(huì)發(fā)生在不同 ISP 的機(jī)房之間(想象一下你和朋友組隊(duì)玩 DOTA,他在電信兼雄,你在聯(lián)通)暖璧。
為了應(yīng)對(duì)某一時(shí)刻某個(gè)機(jī)房突發(fā)的網(wǎng)絡(luò)延時(shí)尖刺活著間歇性失聯(lián),一個(gè)好的分布式系統(tǒng)一定能處理好這種情況下的一致性問題君旦。
那么螞蟻是怎么解決這個(gè)問題的呢澎办?我們?cè)谏衔挠懻撨^,其實(shí) LDC 機(jī)房的各個(gè)單元都由兩部分組成:負(fù)責(zé)業(yè)務(wù)邏輯計(jì)算的應(yīng)用服務(wù)器和負(fù)責(zé)數(shù)據(jù)持久化的數(shù)據(jù)庫金砍。大部分應(yīng)用服務(wù)器就像一個(gè)個(gè)計(jì)算器局蚀,自身是不對(duì)寫一致性負(fù)責(zé)的,這個(gè)任務(wù)被下沉到了數(shù)據(jù)庫恕稠。所以螞蟻解決分布式一致性問題的關(guān)鍵就在于數(shù)據(jù)庫琅绅!想必螞蟻的讀者大概猜到下面的討論重點(diǎn)了——OceanBase(下文簡(jiǎn)稱OB),中國第一款自主研發(fā)的分布式數(shù)據(jù)庫鹅巍,一時(shí)間也確實(shí)獲得了很多光環(huán)千扶。在討論 OB 前,我們先來想想 Why not MySQL骆捧?首先澎羞,就像 CAP 三角圖中指出的,MySQL 是一款滿足 AC 但不滿足 P 的分布式系統(tǒng)敛苇。試想一下妆绞,一個(gè) MySQL 主從結(jié)構(gòu)的數(shù)據(jù)庫集群,當(dāng)出現(xiàn)分區(qū)時(shí),問題分區(qū)內(nèi)的 Slave 會(huì)認(rèn)為主已經(jīng)掛了括饶,所以自己成為本分區(qū)的 Master(腦裂)株茶。等分區(qū)問題恢復(fù)后,會(huì)產(chǎn)生 2 個(gè)主庫的數(shù)據(jù)图焰,而無法確定誰是正確的启盛,也就是分區(qū)導(dǎo)致了一致性被破壞。這樣的結(jié)果是嚴(yán)重的技羔,這也是螞蟻寧愿自研 OceanBase 的原動(dòng)力之一僵闯。那么如何才能讓分布式系統(tǒng)具備分區(qū)容忍性呢?按照老慣例堕阔,我們從”可用性分區(qū)容忍”和”一致性分區(qū)容忍”兩個(gè)方面來討論:可用性分區(qū)容忍性保障機(jī)制:可用性分區(qū)容忍的關(guān)鍵在于別讓一個(gè)事務(wù)一來所有節(jié)點(diǎn)來完成棍厂,這個(gè)很簡(jiǎn)單,別要求所有節(jié)點(diǎn)共同同時(shí)參與某個(gè)事務(wù)即可超陆。一致性分區(qū)容忍性保障機(jī)制:老實(shí)說牺弹,都產(chǎn)生分區(qū)了,哪還可能獲得實(shí)時(shí)一致性时呀。但要保證最終一致性也不簡(jiǎn)單张漂,一旦產(chǎn)生分區(qū),如何保證同一時(shí)刻只會(huì)產(chǎn)生一份提議呢谨娜?換句話說航攒,如何保障仍然只有一個(gè)腦呢?下面我們來看下 PAXOS 算法是如何解決腦裂問題的趴梢。這里可以發(fā)散下漠畜,所謂的“腦”其實(shí)就是具備寫能力的系統(tǒng),“非腦”就是只具備讀能力的系統(tǒng)坞靶,對(duì)應(yīng)了 MySQL 集群中的從庫憔狞。
下面是一段摘自維基百科的 PAXOS 定義:
Paxos is a family of protocols for solving consensus in a network of unreliable processors (that is, processors that may fail).
大致意思就是說,PAXOS 是在一群不是特別可靠的節(jié)點(diǎn)組成的集群中的一種共識(shí)機(jī)制彰阴。Paxos 要求任何一個(gè)提議瘾敢,至少有 (N/2)+1 的系統(tǒng)節(jié)點(diǎn)認(rèn)可,才被認(rèn)為是可信的尿这,這背后的一個(gè)基礎(chǔ)理論是少數(shù)服從多數(shù)簇抵。想象一下,如果多數(shù)節(jié)點(diǎn)認(rèn)可后射众,整個(gè)系統(tǒng)宕機(jī)了碟摆,重啟后,仍然可以通過一次投票知道哪個(gè)值是合法的(多數(shù)節(jié)點(diǎn)保留的那個(gè)值)责球。這樣的設(shè)定也巧妙的解決了分區(qū)情況下的共識(shí)問題焦履,因?yàn)橐坏┊a(chǎn)生分區(qū)拓劝,勢(shì)必最多只有一個(gè)分區(qū)內(nèi)的節(jié)點(diǎn)數(shù)量會(huì)大于等于 (N/2)+1雏逾。通過這樣的設(shè)計(jì)就可以巧妙的避開腦裂嘉裤,當(dāng)然 MySQL 集群的腦裂問題也是可以通過其他方法來解決的,比如同時(shí) Ping 一個(gè)公共的 IP栖博,成功者繼續(xù)為腦屑宠,顯然這就又制造了另外一個(gè)單點(diǎn)。如果你了解過比特幣或者區(qū)塊鏈仇让,你就知道區(qū)塊鏈的基礎(chǔ)理論也是 PAXOS典奉。區(qū)塊鏈借助 PAXOS 對(duì)最終一致性的貢獻(xiàn)來抵御惡意篡改。而本文涉及的分布式應(yīng)用系統(tǒng)則是通過 PAXOS 來解決分區(qū)容忍性丧叽。再說本質(zhì)一點(diǎn)卫玖,一個(gè)是抵御部分節(jié)點(diǎn)變壞,一個(gè)是防范部分節(jié)點(diǎn)失聯(lián)踊淳。大家一定聽說過這樣的描述:PAXOS 是唯一能解決分布式一致性問題的解法假瞬。這句話越是理解越發(fā)覺得詭異,這會(huì)讓人以為 PAXOS 逃離于 CAP 約束了迂尝,所以個(gè)人更愿意理解為:PAXOS 是唯一一種保障分布式系統(tǒng)最終一致性的共識(shí)算法(所謂共識(shí)算法脱茉,就是大家都按照這個(gè)算法來操作,大家最后的結(jié)果一定相同)垄开。PAXOS 并沒有逃離 CAP 魔咒琴许,畢竟達(dá)成共識(shí)是 (N/2)+1 的節(jié)點(diǎn)之間的事,剩下的 (N/2)-1 的節(jié)點(diǎn)上的數(shù)據(jù)還是舊的溉躲,這時(shí)候仍然是不一致的榜田。所以 PAXOS 對(duì)一致性的貢獻(xiàn)在于經(jīng)過一次事務(wù)后,這個(gè)集群里已經(jīng)有部分節(jié)點(diǎn)保有了本次事務(wù)正確的結(jié)果(共識(shí)的結(jié)果)锻梳,這個(gè)結(jié)果隨后會(huì)被異步的同步到其他節(jié)點(diǎn)上箭券,從而保證最終一致性。
以下摘自維基百科:
Paxos is a family of protocols for solving consensus in a network of unreliable processors (that is, processors that may fail).Quorums express the safety (or consistency) properties of Paxos by ensuring at least some surviving processor retains knowledge of the results.
另外 PAXOS 不要求對(duì)所有節(jié)點(diǎn)做實(shí)時(shí)同步唱蒸,實(shí)質(zhì)上是考慮到了分區(qū)情況下的可用性邦鲫,通過減少完成一次事務(wù)需要的參與者個(gè)數(shù),來保障系統(tǒng)的可用性神汹。
②OceanBase 的 CAP 分析
上文提到過庆捺,單元化架構(gòu)中的成千山萬的應(yīng)用就像是計(jì)算器,本身無 CAP 限制屁魏,其 CAP 限制下沉到了其數(shù)據(jù)庫層滔以,也就是螞蟻?zhàn)匝械姆植际綌?shù)據(jù)庫 OceanBase(本節(jié)簡(jiǎn)稱 OB)。
在 OB 體系中氓拼,每個(gè)數(shù)據(jù)庫實(shí)例都具備讀寫能力你画,具體是讀是寫可以動(dòng)態(tài)配置(參考第二部分)抵碟。實(shí)際情況下大部分時(shí)候,對(duì)于某一類數(shù)據(jù)(固定用戶號(hào)段的數(shù)據(jù))任意時(shí)刻只有一個(gè)單元會(huì)負(fù)責(zé)寫入某個(gè)節(jié)點(diǎn)坏匪,其他節(jié)點(diǎn)要么是實(shí)時(shí)庫間同步拟逮,要么是異步數(shù)據(jù)同步。OB 也采用了 PAXOS 共識(shí)協(xié)議适滓。實(shí)時(shí)庫間同步的節(jié)點(diǎn)(包含自己)個(gè)數(shù)至少需要 (N/2)+1 個(gè)敦迄,這樣就可以解決分區(qū)容忍性問題。
下面我們舉個(gè)馬老師改英文名的例子來說明 OB 設(shè)計(jì)的精妙之處:
假設(shè)數(shù)據(jù)庫按照用戶 ID 分庫分表凭迹,馬老師的用戶 ID 對(duì)應(yīng)的數(shù)據(jù)段在 [0-9]罚屋,開始由單元 A 負(fù)責(zé)數(shù)據(jù)寫入。
假如馬老師(用戶 ID 假設(shè)為 000)正在用支付寶 App 修改自己的英文名嗅绸,馬老師一開始打錯(cuò)了脾猛,打成了 Jason Ma,A 單元收到了這個(gè)請(qǐng)求鱼鸠。
這時(shí)候發(fā)生了分區(qū)(比如 A 網(wǎng)絡(luò)斷開了)猛拴,我們將單元 A 對(duì)數(shù)據(jù)段 [0,9] 的寫入權(quán)限轉(zhuǎn)交給單元 B(更改映射),馬老師這次寫對(duì)了瞧柔,為 Jack Ma漆弄。
而在網(wǎng)絡(luò)斷開前請(qǐng)求已經(jīng)進(jìn)入了 A,寫權(quán)限轉(zhuǎn)交給單元 B 生效后造锅,A 和 B 同時(shí)對(duì) [0,9] 數(shù)據(jù)段進(jìn)行寫入馬老師的英文名撼唾。
假如這時(shí)候都允許寫入的話就會(huì)出現(xiàn)不一致,A 單元說我看到馬老師設(shè)置了 Jason Ma哥蔚,B 單元說我看到馬老師設(shè)置了 Jack Ma倒谷。
然而這種情況不會(huì)發(fā)生的,A 提議說我建議把馬老師的英文名設(shè)置為 Jason Ma 時(shí)糙箍,發(fā)現(xiàn)沒人回應(yīng)它渤愁。
因?yàn)槌霈F(xiàn)了分區(qū),其他節(jié)點(diǎn)對(duì)它來說都是不可達(dá)的深夯,所以這個(gè)提議被自動(dòng)丟棄抖格,A 心里也明白是自己分區(qū)了,會(huì)有主分區(qū)替自己完成寫入任務(wù)的咕晋。
同樣的雹拄,B 提出了將馬老師的英文名改成 Jack Ma 后,大部分節(jié)點(diǎn)都響應(yīng)了掌呜,所以 B 成功將 Jack Ma 寫入了馬老師的賬號(hào)記錄滓玖。
假如在寫權(quán)限轉(zhuǎn)交給單元 B 后 A 突然恢復(fù)了,也沒關(guān)系,兩筆寫請(qǐng)求同時(shí)要求獲得 (N/2)+1 個(gè)節(jié)點(diǎn)的事務(wù)鎖跛十,通過 no-wait 設(shè)計(jì)求橄,在 B 獲得了鎖之后传透,其他爭(zhēng)搶該鎖的事務(wù)都會(huì)因?yàn)槭《貪L。
下面我們分析下 OB 的 CAP:
分區(qū)容忍性:OB 節(jié)點(diǎn)之間是有互相通信的(需要相互同步數(shù)據(jù))刮便,所以存在分區(qū)問題脯爪,OB 通過僅同步到部分節(jié)點(diǎn)來保證可用性委煤。這一點(diǎn)就說明 OB 做了分區(qū)容錯(cuò)绷蹲。
-
可用性分區(qū)容忍性:OB 事務(wù)只需要同步到 (N/2)+1 個(gè)節(jié)點(diǎn)棒卷,允許其余的一小半節(jié)點(diǎn)分區(qū)(宕機(jī)顾孽、斷網(wǎng)等)祝钢,只要 (N/2)+1 個(gè)節(jié)點(diǎn)活著就是可用的。
極端情況下若厚,比如 5 個(gè)節(jié)點(diǎn)分成 3 份(2:2:1)拦英,那就確實(shí)不可用了,只是這種情況概率比較低测秸。
一致性分區(qū)容忍性:分區(qū)情況下意味著部分節(jié)點(diǎn)失聯(lián)了疤估,一致性顯然是不滿足的。但通過共識(shí)算法可以保證當(dāng)下只有一個(gè)值是合法的霎冯,并且最終會(huì)通過節(jié)點(diǎn)間的同步達(dá)到最終一致性铃拇。
所以 OB 仍然沒有逃脫 CAP 魔咒,產(chǎn)生分區(qū)的時(shí)候它變成 AP+最終一致性(C)沈撞。整體來說慷荔,它是 AP 的,即高可用和分區(qū)容忍缠俺。
結(jié)語
個(gè)人感覺本文涉及到的知識(shí)面確實(shí)不少显晶,每個(gè)點(diǎn)單獨(dú)展開都可以討論半天∫际浚回到我們緊扣的主旨來看磷雇,雙十一海量支付背后技術(shù)上大快人心的設(shè)計(jì)到底是啥?我想無非是以下幾點(diǎn):
基于用戶分庫分表的 RZone 設(shè)計(jì)躏救。每個(gè)用戶群獨(dú)占一個(gè)單元給整個(gè)系統(tǒng)的容量帶來了爆發(fā)式增長唯笙。
RZone 在網(wǎng)絡(luò)分區(qū)或?yàn)?zāi)備切換時(shí) OB 的防腦裂設(shè)計(jì)(PAXOS)。我們知道 RZone 是單腦的(讀寫都在一個(gè)單元對(duì)應(yīng)的庫)盒使,而網(wǎng)絡(luò)分區(qū)或者災(zāi)備時(shí)熱切換過程中可能會(huì)產(chǎn)生多個(gè)腦崩掘,OB 解決了腦裂情況下的共識(shí)問題(PAXOS 算法)。
基于 CZone 的本地讀設(shè)計(jì)忠怖。這一點(diǎn)保證了很大一部分有著“寫讀時(shí)間差”現(xiàn)象的公共數(shù)據(jù)能被高速本地訪問呢堰。
-
剩下的那一丟丟不能本地訪問只能實(shí)時(shí)訪問 GZone 的公共配置數(shù)據(jù),也興不起什么風(fēng)凡泣,作不了什么浪枉疼。
比如用戶創(chuàng)建這種 TPS皮假,不會(huì)高到哪里去。再比如對(duì)于實(shí)時(shí)庫存數(shù)據(jù)骂维,可以通過“頁面展示查詢走應(yīng)用層緩存”+“實(shí)際下單時(shí)再校驗(yàn)”的方式減少其 GZone 調(diào)用量惹资。
而這就是螞蟻 LDC 的 CRG 架構(gòu),相信 54.4 萬筆/秒還遠(yuǎn)沒到 LDC 的上限航闺,這個(gè)數(shù)字可以做到更高褪测。當(dāng)然雙 11 海量支付的成功不單單是這么一套設(shè)計(jì)所決定的,還有預(yù)熱削峰等運(yùn)營+技術(shù)的手段潦刃,以及成百上千的兄弟姐妹共同奮戰(zhàn)侮措,特此在這向各位雙 11 留守同學(xué)致敬。感謝大家的閱讀乖杠,文中可能存在不足或遺漏之處分扎,歡迎批評(píng)指正。
參考文獻(xiàn):
Practice of Cloud System Administration, The: DevOps and SRE Practices for Web Services, Volume 2. Thomas A. Limoncelli, Strata R. Chalup, Christina J. Hogan.
-
MySQL 5.7 半同步復(fù)制技術(shù)
-
BASE 理論分析
-
Keepalived
-
PAXOS
-
OceanBase 支撐 2135 億成交額背后的技術(shù)原理
-
Backup
</article>
作者:湯波**
簡(jiǎn)介:阿里巴巴架構(gòu)師胧洒,熱愛技術(shù)畏吓,深信技術(shù)讓世界更美好。對(duì)前沿技術(shù)一直保持饑餓感卫漫,熱衷于創(chuàng)新和革新菲饼,讓系統(tǒng)體制更為高效和人性化,也深知一個(gè)人強(qiáng)走的快列赎,一個(gè)團(tuán)體強(qiáng)才能走的遠(yuǎn)宏悦。在技術(shù)團(tuán)隊(duì)建設(shè)(團(tuán)隊(duì)招聘和組建、梯隊(duì)梯度建設(shè))粥谬、技術(shù)棧管理(包含技術(shù)選型肛根、技術(shù)規(guī)范建設(shè)、軟件體系規(guī)劃)和項(xiàng)目研發(fā)管理(軟件工程管理漏策、開發(fā)效能和質(zhì)量管理)方面有著較為豐富的實(shí)踐經(jīng)驗(yàn)派哲。關(guān)注領(lǐng)域:SaaS,PaaS掺喻,Serverless芭届,Service mesh,新零售感耙,區(qū)塊鏈褂乍,人工智能,互聯(lián)網(wǎng)全棧即硼,分布式企業(yè)級(jí)開發(fā)逃片,網(wǎng)絡(luò)應(yīng)用/協(xié)議開發(fā),計(jì)算機(jī)算法應(yīng)用只酥。