參考
前言
本文全部轉(zhuǎn)載自搞懂異地多活,看這篇就夠了。這是我當(dāng)前找到的豁延,對(duì)異地多活講得最透徹的文章,先轉(zhuǎn)載一下腊状。以防丟失诱咏。
00 背景
你好,我是 Kaito缴挖。
在軟件開(kāi)發(fā)領(lǐng)域袋狞,「異地多活」是分布式系統(tǒng)架構(gòu)設(shè)計(jì)的一座高峰,很多人經(jīng)常聽(tīng)過(guò)它映屋,但很少人理解其中的原理苟鸯。
異地多活到底是什么?為什么需要異地多活棚点?它到底解決了什么問(wèn)題早处?究竟是怎么解決的?
這些疑問(wèn)瘫析,想必是每個(gè)程序看到異地多活這個(gè)名詞時(shí)砌梆,都想要搞明白的問(wèn)題默责。
有幸,我曾經(jīng)深度參與過(guò)一個(gè)中等互聯(lián)網(wǎng)公司咸包,建設(shè)異地多活系統(tǒng)的設(shè)計(jì)與實(shí)施過(guò)程桃序。所以今天,我就來(lái)和你聊一聊異地多活背后的的實(shí)現(xiàn)原理烂瘫。
認(rèn)真讀完這篇文章媒熊,我相信你會(huì)對(duì)異地多活架構(gòu),有更加深刻的理解忱反。
這篇文章干貨很多泛释,希望你可以耐心讀完。
01 系統(tǒng)可用性
要想理解異地多活温算,我們需要從架構(gòu)設(shè)計(jì)的原則說(shuō)起怜校。
現(xiàn)如今,我們開(kāi)發(fā)一個(gè)軟件系統(tǒng)注竿,對(duì)其要求越來(lái)越高茄茁,如果你了解一些「架構(gòu)設(shè)計(jì)」的要求,就知道一個(gè)好的軟件架構(gòu)應(yīng)該遵循以下 3 個(gè)原則:
- 高性能
- 高可用
- 易擴(kuò)展
其中巩割,高性能意味著系統(tǒng)擁有更大流量的處理能力裙顽,更低的響應(yīng)延遲。例如 1 秒可處理 10W 并發(fā)請(qǐng)求宣谈,接口響應(yīng)時(shí)間 5 ms 等等愈犹。
易擴(kuò)展表示系統(tǒng)在迭代新功能時(shí),能以最小的代價(jià)去擴(kuò)展闻丑,系統(tǒng)遇到流量壓力時(shí)漩怎,可以在不改動(dòng)代碼的前提下,去擴(kuò)容系統(tǒng)嗦嗡。
而「高可用」這個(gè)概念勋锤,看起來(lái)很抽象,怎么理解它呢侥祭?通常用 2 個(gè)指標(biāo)來(lái)衡量:
- 平均故障間隔 MTBF(Mean Time Between Failure):表示兩次故障的間隔時(shí)間叁执,也就是系統(tǒng)「正常運(yùn)行」的平均時(shí)間,這個(gè)時(shí)間越長(zhǎng)矮冬,說(shuō)明系統(tǒng)穩(wěn)定性越高
- 故障恢復(fù)時(shí)間 MTTR(Mean Time To Repair):表示系統(tǒng)發(fā)生故障后「恢復(fù)的時(shí)間」谈宛,這個(gè)值越小,故障對(duì)用戶的影響越小
可用性與這兩者的關(guān)系:
可用性(Availability)= MTBF / (MTBF + MTTR) * 100%
這個(gè)公式得出的結(jié)果是一個(gè)「比例」胎署,通常我們會(huì)用「N 個(gè) 9」來(lái)描述一個(gè)系統(tǒng)的可用性入挣。
從這張圖你可以看到,要想達(dá)到 4 個(gè) 9 以上的可用性硝拧,平均每天故障時(shí)間必須控制在 10 秒以內(nèi)径筏。
也就是說(shuō)葛假,只有故障的時(shí)間「越短」,整個(gè)系統(tǒng)的可用性才會(huì)越高滋恬,每提升 1 個(gè) 9聊训,都會(huì)對(duì)系統(tǒng)提出更高的要求。
我們都知道恢氯,系統(tǒng)發(fā)生故障其實(shí)是不可避免的带斑,尤其是規(guī)模越大的系統(tǒng),發(fā)生問(wèn)題的概率也越大勋拟。這些故障一般體現(xiàn)在 3 個(gè)方面:
- 硬件故障:CPU勋磕、內(nèi)存、磁盤(pán)敢靡、網(wǎng)卡挂滓、交換機(jī)、路由器
- 軟件問(wèn)題:代碼 Bug啸胧、版本迭代
- 不可抗力:地震赶站、水災(zāi)、火災(zāi)纺念、戰(zhàn)爭(zhēng)
這些風(fēng)險(xiǎn)隨時(shí)都有可能發(fā)生贝椿。所以,在面對(duì)故障時(shí)陷谱,我們的系統(tǒng)能否以「最快」的速度恢復(fù)烙博,就成為了可用性的關(guān)鍵。
可如何做到快速恢復(fù)呢烟逊?
這篇文章要講的「異地多活」架構(gòu)渣窜,就是為了解決這個(gè)問(wèn)題,而提出的高效解決方案焙格。
下面,我會(huì)從一個(gè)最簡(jiǎn)單的系統(tǒng)出發(fā)夷都,帶你一步步演化出一個(gè)支持「異地多活」的系統(tǒng)架構(gòu)眷唉。
在這個(gè)過(guò)程中,你會(huì)看到一個(gè)系統(tǒng)會(huì)遇到哪些可用性問(wèn)題囤官,以及為什么架構(gòu)要這樣演進(jìn)冬阳,從而理解異地多活架構(gòu)的意義。
02 單機(jī)架構(gòu)
我們從最簡(jiǎn)單的開(kāi)始講起党饮。
假設(shè)你的業(yè)務(wù)處于起步階段肝陪,體量非常小,那你的架構(gòu)是這樣的:
這個(gè)架構(gòu)模型非常簡(jiǎn)單刑顺,客戶端請(qǐng)求進(jìn)來(lái)氯窍,業(yè)務(wù)應(yīng)用讀寫(xiě)數(shù)據(jù)庫(kù)饲常,返回結(jié)果,非常好理解狼讨。
但需要注意的是贝淤,這里的數(shù)據(jù)庫(kù)是「單機(jī)」部署的,所以它有一個(gè)致命的缺點(diǎn):一旦遭遇意外政供,例如磁盤(pán)損壞播聪、操作系統(tǒng)異常、誤刪數(shù)據(jù)布隔,那這意味著所有數(shù)據(jù)就全部「丟失」了离陶,這個(gè)損失是巨大的。
如何避免這個(gè)問(wèn)題呢衅檀?我們很容易想到一個(gè)方案:備份招刨。
你可以對(duì)數(shù)據(jù)做備份,把數(shù)據(jù)庫(kù)文件「定期」cp 到另一臺(tái)機(jī)器上术吝,這樣计济,即使原機(jī)器丟失數(shù)據(jù),你依舊可以通過(guò)備份把數(shù)據(jù)「恢復(fù)」回來(lái)排苍,以此保證數(shù)據(jù)安全沦寂。
這個(gè)方案實(shí)施起來(lái)雖然比較簡(jiǎn)單,但存在 2 個(gè)問(wèn)題:
- 恢復(fù)需要時(shí)間:業(yè)務(wù)需先停機(jī)淘衙,再恢復(fù)數(shù)據(jù)传藏,停機(jī)時(shí)間取決于恢復(fù)的速度,恢復(fù)期間服務(wù)「不可用」
- 數(shù)據(jù)不完整:因?yàn)槭嵌ㄆ趥浞萃兀瑪?shù)據(jù)肯定不是「最新」的毯侦,數(shù)據(jù)完整程度取決于備份的周期
很明顯,你的數(shù)據(jù)庫(kù)越大具垫,意味故障恢復(fù)時(shí)間越久侈离。那按照前面我們提到的「高可用」標(biāo)準(zhǔn),這個(gè)方案可能連 1 個(gè) 9 都達(dá)不到筝蚕,遠(yuǎn)遠(yuǎn)無(wú)法滿足我們對(duì)可用性的要求卦碾。
那有什么更好的方案,既可以快速恢復(fù)業(yè)務(wù)起宽?還能盡可能保證數(shù)據(jù)完整性呢洲胖?
這時(shí)你可以采用這個(gè)方案:主從副本。
03 主從副本
你可以在另一臺(tái)機(jī)器上坯沪,再部署一個(gè)數(shù)據(jù)庫(kù)實(shí)例绿映,讓這個(gè)新實(shí)例成為原實(shí)例的「副本」,讓兩者保持「實(shí)時(shí)同步」,就像這樣:
我們一般把原實(shí)例叫作主庫(kù)(master)叉弦,新實(shí)例叫作從庫(kù)(slave)丐一。這個(gè)方案的優(yōu)點(diǎn)在于:
- 數(shù)據(jù)完整性高:主從副本實(shí)時(shí)同步,數(shù)據(jù)「差異」很小
- 抗故障能力提升:主庫(kù)有任何異常卸奉,從庫(kù)可隨時(shí)「切換」為主庫(kù)钝诚,繼續(xù)提供服務(wù)
- 讀性能提升:業(yè)務(wù)應(yīng)用可直接讀從庫(kù),分擔(dān)主庫(kù)「壓力」讀壓力
這個(gè)方案不錯(cuò)榄棵,不僅大大提高了數(shù)據(jù)庫(kù)的可用性凝颇,還提升了系統(tǒng)的讀性能。
同樣的思路疹鳄,你的「業(yè)務(wù)應(yīng)用」也可以在其它機(jī)器部署一份拧略,避免單點(diǎn)。因?yàn)闃I(yè)務(wù)應(yīng)用通常是「無(wú)狀態(tài)」的(不像數(shù)據(jù)庫(kù)那樣存儲(chǔ)數(shù)據(jù))瘪弓,所以直接部署即可垫蛆,非常簡(jiǎn)單。
因?yàn)闃I(yè)務(wù)應(yīng)用部署了多個(gè)腺怯,所以你現(xiàn)在還需要部署一個(gè)「接入層」袱饭,來(lái)做請(qǐng)求的「負(fù)載均衡」(一般會(huì)使用 nginx 或 LVS)绷杜,這樣當(dāng)一臺(tái)機(jī)器宕機(jī)后庙睡,另一臺(tái)機(jī)器也可以「接管」所有流量创橄,持續(xù)提供服務(wù)耙饰。
從這個(gè)方案你可以看出,提升可用性的關(guān)鍵思路就是:冗余玉组。
沒(méi)錯(cuò)耍目,擔(dān)心一個(gè)實(shí)例故障房交,那就部署多個(gè)實(shí)例帜篇,擔(dān)心一個(gè)機(jī)器宕機(jī)糙捺,那就部署多臺(tái)機(jī)器。
到這里笙隙,你的架構(gòu)基本已演變成主流方案了洪灯,之后開(kāi)發(fā)新的業(yè)務(wù)應(yīng)用,都可以按照這種模式去部署竟痰。
但這種方案還有什么風(fēng)險(xiǎn)嗎签钩?
04 風(fēng)險(xiǎn)不可控
現(xiàn)在讓我們把視角下放,把焦點(diǎn)放到具體的「部署細(xì)節(jié)」上來(lái)凯亮。
按照前面的分析哄尔,為了避免單點(diǎn)故障假消,你的應(yīng)用雖然部署了多臺(tái)機(jī)器,但這些機(jī)器的分布情況岭接,我們并沒(méi)有去深究富拗。
而一個(gè)機(jī)房有很多服務(wù)器臼予,這些服務(wù)器通常會(huì)分布在一個(gè)個(gè)「機(jī)柜」上,如果你使用的這些機(jī)器啃沪,剛好在一個(gè)機(jī)柜粘拾,還是存在風(fēng)險(xiǎn)。
如果恰好連接這個(gè)機(jī)柜的交換機(jī) / 路由器發(fā)生故障创千,那么你的應(yīng)用依舊有「不可用」的風(fēng)險(xiǎn)缰雇。
雖然交換機(jī) / 路由器也做了路線冗余,但不能保證一定不出問(wèn)題追驴。
部署在一個(gè)機(jī)柜有風(fēng)險(xiǎn)械哟,那把這些機(jī)器打散,分散到不同機(jī)柜上殿雪,是不是就沒(méi)問(wèn)題了暇咆?
這樣確實(shí)會(huì)大大降低出問(wèn)題的概率。但我們依舊不能掉以輕心丙曙,因?yàn)闊o(wú)論怎么分散爸业,它們總歸還是在一個(gè)相同的環(huán)境下:機(jī)房。
那繼續(xù)追問(wèn)亏镰,機(jī)房會(huì)不會(huì)發(fā)生故障呢扯旷?
一般來(lái)講,建設(shè)一個(gè)機(jī)房的要求其實(shí)是很高的拆挥,地理位置薄霜、溫濕度控制、備用電源等等纸兔,機(jī)房廠商會(huì)在各方面做好防護(hù)惰瓜。但即使這樣,我們每隔一段時(shí)間還會(huì)看到這樣的新聞:
- 2015 年 5 月 27 日汉矿,杭州市某地光纖被挖斷崎坊,近 3 億用戶長(zhǎng)達(dá) 5 小時(shí)無(wú)法訪問(wèn)支付寶
- 2021 年 7 月 13 日,B 站部分服務(wù)器機(jī)房發(fā)生故障洲拇,造成整站持續(xù) 3 個(gè)小時(shí)無(wú)法訪問(wèn)
- 2021 年 10 月 9 日奈揍,富途證券服務(wù)器機(jī)房發(fā)生電力閃斷故障,造成用戶 2 個(gè)小時(shí)無(wú)法登陸赋续、交易
- …
可見(jiàn)男翰,即使機(jī)房級(jí)別的防護(hù)已經(jīng)做得足夠好,但只要有「概率」出問(wèn)題纽乱,那現(xiàn)實(shí)情況就有可能發(fā)生蛾绎。雖然概率很小,但一旦真的發(fā)生,影響之大可見(jiàn)一斑租冠。
看到這里你可能會(huì)想鹏倘,機(jī)房出現(xiàn)問(wèn)題的概率也太小了吧,工作了這么多年顽爹,也沒(méi)讓我碰上一次纤泵,有必要考慮得這么復(fù)雜嗎?
但你有沒(méi)有思考這樣一個(gè)問(wèn)題:不同體量的系統(tǒng)镜粤,它們各自關(guān)注的重點(diǎn)是什么捏题?
體量很小的系統(tǒng),它會(huì)重點(diǎn)關(guān)注「用戶」規(guī)模肉渴、增長(zhǎng)涉馅,這個(gè)階段獲取用戶是一切。等用戶體量上來(lái)了黄虱,這個(gè)階段會(huì)重點(diǎn)關(guān)注「性能」稚矿,優(yōu)化接口響應(yīng)時(shí)間、頁(yè)面打開(kāi)速度等等捻浦,這個(gè)階段更多是關(guān)注用戶體驗(yàn)晤揣。
等體量再大到一定規(guī)模后你會(huì)發(fā)現(xiàn),「可用性」就變得尤為重要朱灿。像微信昧识、支付寶這種全民級(jí)的應(yīng)用,如果機(jī)房發(fā)生一次故障盗扒,那整個(gè)影響范圍可以說(shuō)是非常巨大的跪楞。
所以,再小概率的風(fēng)險(xiǎn)侣灶,我們?cè)谔岣呦到y(tǒng)可用性時(shí)甸祭,也不能忽視。
分析了風(fēng)險(xiǎn)褥影,再說(shuō)回我們的架構(gòu)池户。那到底該怎么應(yīng)對(duì)機(jī)房級(jí)別的故障呢?
沒(méi)錯(cuò)凡怎,還是冗余校焦。
05 同城災(zāi)備
想要抵御「機(jī)房」級(jí)別的風(fēng)險(xiǎn),那應(yīng)對(duì)方案就不能局限在一個(gè)機(jī)房?jī)?nèi)了统倒。
現(xiàn)在寨典,你需要做機(jī)房級(jí)別的冗余方案,也就是說(shuō)房匆,你需要再搭建一個(gè)機(jī)房耸成,來(lái)部署你的服務(wù)注暗。
簡(jiǎn)單起見(jiàn),你可以在「同一個(gè)城市」再搭建一個(gè)機(jī)房墓猎,原機(jī)房我們叫作 A 機(jī)房,新機(jī)房叫 B 機(jī)房赚楚,這兩個(gè)機(jī)房的網(wǎng)絡(luò)用一條「專線」連通毙沾。
有了新機(jī)房,怎么把它用起來(lái)呢宠页?這里還是要優(yōu)先考慮「數(shù)據(jù)」風(fēng)險(xiǎn)左胞。
為了避免 A 機(jī)房故障導(dǎo)致數(shù)據(jù)丟失,所以我們需要把數(shù)據(jù)在 B 機(jī)房也存一份举户。最簡(jiǎn)單的方案還是和前面提到的一樣:備份烤宙。
A 機(jī)房的數(shù)據(jù),定時(shí)在 B 機(jī)房做備份(拷貝數(shù)據(jù)文件)俭嘁,這樣即使整個(gè) A 機(jī)房遭到嚴(yán)重的損壞躺枕,B 機(jī)房的數(shù)據(jù)不會(huì)丟,通過(guò)備份可以把數(shù)據(jù)「恢復(fù)」回來(lái)供填,重啟服務(wù)拐云。
這種方案,我們稱之為「冷備」近她。為什么叫冷備呢叉瘩?因?yàn)?B 機(jī)房只做備份,不提供實(shí)時(shí)服務(wù)粘捎,它是冷的薇缅,只會(huì)在 A 機(jī)房故障時(shí)才會(huì)啟用。
但備份的問(wèn)題依舊和之前描述的一樣:數(shù)據(jù)不完整攒磨、恢復(fù)數(shù)據(jù)期間業(yè)務(wù)不可用泳桦,整個(gè)系統(tǒng)的可用性還是無(wú)法得到保證。
所以娩缰,我們還是需要用「主從副本」的方式蓬痒,在 B 機(jī)房部署 A 機(jī)房的數(shù)據(jù)副本,架構(gòu)就變成了這樣:
這樣漆羔,就算整個(gè) A 機(jī)房掛掉梧奢,我們?cè)?B 機(jī)房也有比較「完整」的數(shù)據(jù)。
數(shù)據(jù)是保住了演痒,但這時(shí)你需要考慮另外一個(gè)問(wèn)題:如果 A 機(jī)房真掛掉了亲轨,要想保證服務(wù)不中斷,你還需要在 B 機(jī)房「緊急」做這些事情:
- B 機(jī)房所有從庫(kù)提升為主庫(kù)
- 在 B 機(jī)房部署應(yīng)用鸟顺,啟動(dòng)服務(wù)
- 部署接入層惦蚊,配置轉(zhuǎn)發(fā)規(guī)則
- DNS 指向 B 機(jī)房接入層器虾,接入流量,業(yè)務(wù)恢復(fù)
看到了么蹦锋?A 機(jī)房故障后兆沙,B 機(jī)房需要做這么多工作,你的業(yè)務(wù)才能完全「恢復(fù)」過(guò)來(lái)莉掂。
你看葛圃,整個(gè)過(guò)程需要人為介入,且需花費(fèi)大量時(shí)間來(lái)操作憎妙,恢復(fù)之前整個(gè)服務(wù)還是不可用的库正,這個(gè)方案還是不太爽,如果能做到故障后立即「切換」厘唾,那就好了褥符。
因此,要想縮短業(yè)務(wù)恢復(fù)的時(shí)間抚垃,你必須把這些工作在 B 機(jī)房「提前」做好喷楣,也就是說(shuō),你需要在 B 機(jī)房提前部署好接入層鹤树、業(yè)務(wù)應(yīng)用抡蛙,等待隨時(shí)切換。架構(gòu)就變成了這樣:
這樣的話魂迄,A 機(jī)房整個(gè)掛掉粗截,我們只需要做 2 件事即可:
- B 機(jī)房所有從庫(kù)提升為主庫(kù)
- DNS 指向 B 機(jī)房接入層,接入流量捣炬,業(yè)務(wù)恢復(fù)
這樣一來(lái)熊昌,恢復(fù)速度快了很多。
到這里你會(huì)發(fā)現(xiàn)湿酸,B 機(jī)房從最開(kāi)始的「空空如也」婿屹,演變到現(xiàn)在,幾乎是「鏡像」了一份 A 機(jī)房的所有東西推溃,從最上層的接入層昂利,到中間的業(yè)務(wù)應(yīng)用,到最下層的存儲(chǔ)铁坎。兩個(gè)機(jī)房唯一的區(qū)別是蜂奸,A 機(jī)房的存儲(chǔ)都是主庫(kù),而 B 機(jī)房都是從庫(kù)硬萍。
這種方案扩所,我們把它叫做「熱備」。
熱的意思是指朴乖,B 機(jī)房處于「待命」?fàn)顟B(tài)祖屏,A 故障后 B 可以隨時(shí)「接管」流量助赞,繼續(xù)提供服務(wù)。熱備相比于冷備最大的優(yōu)點(diǎn)是:隨時(shí)可切換袁勺。
無(wú)論是冷備還是熱備雹食,因?yàn)樗鼈兌继幱凇競(jìng)溆谩範(fàn)顟B(tài),所以我們把這兩個(gè)方案統(tǒng)稱為:同城災(zāi)備期丰。
同城災(zāi)備的最大優(yōu)勢(shì)在于群叶,我們?cè)僖膊挥脫?dān)心「機(jī)房」級(jí)別的故障了,一個(gè)機(jī)房發(fā)生風(fēng)險(xiǎn)咐汞,我們只需把流量切換到另一個(gè)機(jī)房即可,可用性再次提高儒鹿,是不是很爽化撕?(后面還有更爽的)
06 同城雙活
我們繼續(xù)來(lái)看這個(gè)架構(gòu)。
雖然我們有了應(yīng)對(duì)機(jī)房故障的解決方案约炎,但這里有個(gè)問(wèn)題是我們不能忽視的:A 機(jī)房掛掉植阴,全部流量切到 B 機(jī)房,B 機(jī)房能否真的如我們所愿圾浅,正常提供服務(wù)掠手?
這是個(gè)值得思考的問(wèn)題。
這就好比有兩支軍隊(duì) A 和 B狸捕,A 軍隊(duì)歷經(jīng)沙場(chǎng)喷鸽,作戰(zhàn)經(jīng)驗(yàn)豐富,而 B 軍隊(duì)只是后備軍灸拍,除了有軍人的基本素養(yǎng)之外做祝,并沒(méi)有實(shí)戰(zhàn)經(jīng)驗(yàn),戰(zhàn)斗經(jīng)驗(yàn)基本為 0鸡岗。
如果 A 軍隊(duì)喪失戰(zhàn)斗能力混槐,需要 B 軍隊(duì)立即頂上時(shí),作為指揮官的你轩性,肯定也會(huì)擔(dān)心 B 軍隊(duì)能否真的擔(dān)此重任吧声登?
我們的架構(gòu)也是如此,此時(shí)的 B 機(jī)房雖然是隨時(shí)「待命」?fàn)顟B(tài)揣苏,但 A 機(jī)房真的發(fā)生故障悯嗓,我們要把全部流量切到 B 機(jī)房,其實(shí)是不敢百分百保證它可以「如期」工作的卸察。
你想绅作,我們?cè)谝粋€(gè)機(jī)房?jī)?nèi)部署服務(wù),還總是發(fā)生各種各樣的問(wèn)題蛾派,例如:發(fā)布應(yīng)用的版本不一致俄认、系統(tǒng)資源不足个少、操作系統(tǒng)參數(shù)不一樣等等。現(xiàn)在多部署一個(gè)機(jī)房眯杏,這些問(wèn)題只會(huì)增多夜焦,不會(huì)減少。
另外岂贩,從「成本」的角度來(lái)看茫经,我們新部署一個(gè)機(jī)房,需要購(gòu)買服務(wù)器萎津、內(nèi)存卸伞、硬盤(pán)、帶寬資源锉屈,花費(fèi)成本也是非常高昂的荤傲,只讓它當(dāng)一個(gè)后備軍,未免也太「大材小用」了颈渊!
因此遂黍,我們需要讓 B 機(jī)房也接入流量,實(shí)時(shí)提供服務(wù)俊嗽,這樣做的好處雾家,一是可以實(shí)時(shí)訓(xùn)練這支后備軍,讓它達(dá)到與 A 機(jī)房相同的作戰(zhàn)水平绍豁,隨時(shí)可切換芯咧,二是 B 機(jī)房接入流量后,可以分擔(dān) A 機(jī)房的流量壓力竹揍。這才是把 B 機(jī)房資源優(yōu)勢(shì)唬党,發(fā)揮最大化的最好方案!
那怎么讓 B 機(jī)房也接入流量呢鬼佣?很簡(jiǎn)單驶拱,就是把 B 機(jī)房的接入層 IP 地址,加入到 DNS 中晶衷,這樣蓝纲,B 機(jī)房從上層就可以有流量進(jìn)來(lái)了。
但這里有一個(gè)問(wèn)題:別忘了晌纫,B 機(jī)房的存儲(chǔ)税迷,現(xiàn)在可都是 A 機(jī)房的「從庫(kù)」,從庫(kù)默認(rèn)可都是「不可寫(xiě)」的锹漱,B 機(jī)房的寫(xiě)請(qǐng)求打到本機(jī)房存儲(chǔ)上箭养,肯定會(huì)報(bào)錯(cuò),這還是不符合我們預(yù)期哥牍。怎么辦毕泌?
這時(shí)喝检,你就需要在「業(yè)務(wù)應(yīng)用」層做改造了。
你的業(yè)務(wù)應(yīng)用在操作數(shù)據(jù)庫(kù)時(shí)撼泛,需要區(qū)分「讀寫(xiě)分離」(一般用中間件實(shí)現(xiàn))挠说,即兩個(gè)機(jī)房的「讀」流量,可以讀任意機(jī)房的存儲(chǔ)愿题,但「寫(xiě)」流量损俭,只允許寫(xiě) A 機(jī)房,因?yàn)橹鲙?kù)在 A 機(jī)房潘酗。
這會(huì)涉及到你用的所有存儲(chǔ)杆兵,例如項(xiàng)目中用到了 MySQL、Redis仔夺、MongoDB 等等琐脏,操作這些數(shù)據(jù)庫(kù),都需要區(qū)分讀寫(xiě)請(qǐng)求囚灼,所以這塊需要一定的業(yè)務(wù)「改造」成本骆膝。
因?yàn)?A 機(jī)房的存儲(chǔ)都是主庫(kù)祭衩,所以我們把 A 機(jī)房叫做「主機(jī)房」灶体,B 機(jī)房叫「從機(jī)房」。
兩個(gè)機(jī)房部署在「同城」掐暮,物理距離比較近蝎抽,而且兩個(gè)機(jī)房用「專線」網(wǎng)絡(luò)連接,雖然跨機(jī)房訪問(wèn)的延遲路克,比單個(gè)機(jī)房?jī)?nèi)要大一些樟结,但整體的延遲還是可以接受的。
業(yè)務(wù)改造完成后精算,B 機(jī)房可以慢慢接入流量瓢宦,從 10%、30%灰羽、50% 逐漸覆蓋到 100%驮履,你可以持續(xù)觀察 B 機(jī)房的業(yè)務(wù)是否存在問(wèn)題,有問(wèn)題及時(shí)修復(fù)廉嚼,逐漸讓 B 機(jī)房的工作能力玫镐,達(dá)到和 A 機(jī)房相同水平。
現(xiàn)在怠噪,因?yàn)?B 機(jī)房實(shí)時(shí)接入了流量恐似,此時(shí)如果 A 機(jī)房掛了锣夹,那我們就可以「大膽」地把 A 的流量擦剑,全部切換到 B 機(jī)房吉捶,完成快速切換霹陡!
到這里你可以看到,我們部署的 B 機(jī)房口四,在物理上雖然與 A 有一定距離孵运,但整個(gè)系統(tǒng)從「邏輯」上來(lái)看,我們是把這兩個(gè)機(jī)房看做一個(gè)「整體」來(lái)規(guī)劃的蔓彩,也就是說(shuō)治笨,相當(dāng)于把 2 個(gè)機(jī)房當(dāng)作 1 個(gè)機(jī)房來(lái)用。
這種架構(gòu)方案赤嚼,比前面的同城災(zāi)備更「進(jìn)了一步」旷赖,B 機(jī)房實(shí)時(shí)接入了流量,還能應(yīng)對(duì)隨時(shí)的故障切換更卒,這種方案我們把它叫做「同城雙活」等孵。
因?yàn)閮蓚€(gè)機(jī)房都能處理業(yè)務(wù)請(qǐng)求,這對(duì)我們系統(tǒng)的內(nèi)部維護(hù)蹂空、改造俯萌、升級(jí)提供了更多的可實(shí)施空間(流量隨時(shí)切換),現(xiàn)在上枕,整個(gè)系統(tǒng)的彈性也變大了咐熙,是不是更爽了?
那這種架構(gòu)有什么問(wèn)題呢辨萍?
07 兩地三中心
還是回到風(fēng)險(xiǎn)上來(lái)說(shuō)棋恼。
雖然我們把 2 個(gè)機(jī)房當(dāng)做一個(gè)整體來(lái)規(guī)劃,但這 2 個(gè)機(jī)房在物理層面上锈玉,還是處于「一個(gè)城市」內(nèi)爪飘,如果是整個(gè)城市發(fā)生自然災(zāi)害,例如地震拉背、水災(zāi)(河南水災(zāi)剛過(guò)去不久)师崎,那 2 個(gè)機(jī)房依舊存在「全局覆沒(méi)」的風(fēng)險(xiǎn)。
真是防不勝防耙喂住犁罩?怎么辦?沒(méi)辦法土陪,繼續(xù)冗余昼汗。
但這次冗余機(jī)房,就不能部署在同一個(gè)城市了鬼雀,你需要把它放到距離更遠(yuǎn)的地方顷窒,部署在「異地」。
通常建議兩個(gè)機(jī)房的距離要在 1000 公里以上,這樣才能應(yīng)對(duì)城市級(jí)別的災(zāi)難鞋吉。
假設(shè)之前的 A鸦做、B 機(jī)房在北京,那這次新部署的 C 機(jī)房可以放在上海谓着。
按照前面的思路泼诱,把 C 機(jī)房用起來(lái),最簡(jiǎn)單粗暴的方案還就是做「冷備」赊锚,即定時(shí)把 A治筒、B 機(jī)房的數(shù)據(jù),在 C 機(jī)房做備份舷蒲,防止數(shù)據(jù)丟失耸袜。
這種方案,就是我們經(jīng)常聽(tīng)到的「兩地三中心」牲平。
兩地是指 2 個(gè)城市堤框,三中心是指有 3 個(gè)機(jī)房,其中 2 個(gè)機(jī)房在同一個(gè)城市纵柿,并且同時(shí)提供服務(wù)蜈抓,第 3 個(gè)機(jī)房部署在異地,只做數(shù)據(jù)災(zāi)備昂儒。
這種架構(gòu)方案沟使,通常用在銀行、金融荆忍、政企相關(guān)的項(xiàng)目中格带。它的問(wèn)題還是前面所說(shuō)的撤缴,啟用災(zāi)備機(jī)房需要時(shí)間刹枉,而且啟用后的服務(wù),不確定能否如期工作屈呕。
所以微宝,要想真正的抵御城市級(jí)別的故障,越來(lái)越多的互聯(lián)網(wǎng)公司虎眨,開(kāi)始實(shí)施「異地雙活」蟋软。
08 偽異地雙活
這里,我們還是分析 2 個(gè)機(jī)房的架構(gòu)情況嗽桩。我們不再把 A岳守、B 機(jī)房部署在同一個(gè)城市,而是分開(kāi)部署碌冶,例如 A 機(jī)房放在北京湿痢,B 機(jī)房放在上海。
前面我們講了同城雙活,那異地雙活是不是直接「照搬」同城雙活的模式去部署就可以了呢譬重?
事情沒(méi)你想的那么簡(jiǎn)單拒逮。
如果還是按照同城雙活的架構(gòu)來(lái)部署,那異地雙活的架構(gòu)就是這樣的:
[圖片上傳中...(image-6215ff-1640589611145-7)]
注意看臀规,兩個(gè)機(jī)房的網(wǎng)絡(luò)是通過(guò)「跨城專線」連通的滩援。
此時(shí)兩個(gè)機(jī)房都接入流量,那上海機(jī)房的請(qǐng)求塔嬉,可能要去讀寫(xiě)北京機(jī)房的存儲(chǔ)玩徊,這里存在一個(gè)很大的問(wèn)題:網(wǎng)絡(luò)延遲。
因?yàn)閮蓚€(gè)機(jī)房距離較遠(yuǎn)谨究,受到物理距離的限制佣赖,現(xiàn)在,兩地之間的網(wǎng)絡(luò)延遲就變成了「不可忽視」的因素了记盒。
北京到上海的距離大約 1300 公里憎蛤,即使架設(shè)一條高速的「網(wǎng)絡(luò)專線」,光纖以光速傳輸纪吮,一個(gè)來(lái)回也需要近 10ms 的延遲俩檬。
況且,網(wǎng)絡(luò)線路之間還會(huì)經(jīng)歷各種路由器碾盟、交換機(jī)等網(wǎng)絡(luò)設(shè)備棚辽,實(shí)際延遲可能會(huì)達(dá)到 30ms ~ 100ms,如果網(wǎng)絡(luò)發(fā)生抖動(dòng)冰肴,延遲甚至?xí)_(dá)到 1 秒屈藐。
不止是延遲,遠(yuǎn)距離的網(wǎng)絡(luò)專線質(zhì)量熙尉,是遠(yuǎn)遠(yuǎn)達(dá)不到機(jī)房?jī)?nèi)網(wǎng)絡(luò)質(zhì)量的联逻,專線網(wǎng)絡(luò)經(jīng)常會(huì)發(fā)生延遲、丟包检痰、甚至中斷的情況包归。總之铅歼,不能過(guò)度信任和依賴「跨城專線」公壤。
你可能會(huì)問(wèn),這點(diǎn)延遲對(duì)業(yè)務(wù)影響很大嗎椎椰?影響非常大厦幅!
試想,一個(gè)客戶端請(qǐng)求打到上海機(jī)房慨飘,上海機(jī)房要去讀寫(xiě)北京機(jī)房的存儲(chǔ)确憨,一次跨機(jī)房訪問(wèn)延遲就達(dá)到了 30ms,這大致是機(jī)房?jī)?nèi)網(wǎng)網(wǎng)絡(luò)(0.5 ms)訪問(wèn)速度的 60 倍(30ms / 0.5ms),一次請(qǐng)求慢 60 倍缚态,來(lái)回往返就要慢 100 倍以上磁椒。
而我們?cè)?App 打開(kāi)一個(gè)頁(yè)面,可能會(huì)訪問(wèn)后端幾十個(gè) API玫芦,每次都跨機(jī)房訪問(wèn)浆熔,整個(gè)頁(yè)面的響應(yīng)延遲有可能就達(dá)到了秒級(jí),這個(gè)性能簡(jiǎn)直慘不忍睹桥帆,難以接受医增。
看到了么,雖然我們只是簡(jiǎn)單的把機(jī)房部署在了「異地」老虫,但「同城雙活」的架構(gòu)模型叶骨,在這里就不適用了,還是按照這種方式部署祈匙,這是「?jìng)萎惖仉p活」忽刽!
那如何做到真正的異地雙活呢?
09 真正的異地雙活
既然「跨機(jī)房」調(diào)用延遲是不容忽視的因素夺欲,那我們只能盡量避免跨機(jī)房「調(diào)用」跪帝,規(guī)避這個(gè)延遲問(wèn)題。
也就是說(shuō)些阅,上海機(jī)房的應(yīng)用伞剑,不能再「跨機(jī)房」去讀寫(xiě)北京機(jī)房的存儲(chǔ),只允許讀寫(xiě)上海本地的存儲(chǔ)市埋,實(shí)現(xiàn)「就近訪問(wèn)」黎泣,這樣才能避免延遲問(wèn)題。
還是之前提到的問(wèn)題:上海機(jī)房存儲(chǔ)都是從庫(kù)缤谎,不允許寫(xiě)入啊抒倚,除非我們只允許上海機(jī)房接入「讀流量」,不接收「寫(xiě)流量」弓千,否則無(wú)法滿足不再跨機(jī)房的要求衡便。
很顯然献起,只讓上海機(jī)房接收讀流量的方案不現(xiàn)實(shí)洋访,因?yàn)楹苌儆许?xiàng)目是只有讀流量,沒(méi)有寫(xiě)流量的谴餐。所以這種方案還是不行姻政,這怎么辦?
此時(shí)岂嗓,你就必須在「存儲(chǔ)層」做改造了汁展。
要想上海機(jī)房讀寫(xiě)本機(jī)房的存儲(chǔ),那上海機(jī)房的存儲(chǔ)不能再是北京機(jī)房的從庫(kù),而是也要變?yōu)椤钢鲙?kù)」食绿。
你沒(méi)看錯(cuò)侈咕,兩個(gè)機(jī)房的存儲(chǔ)必須都是「主庫(kù)」,而且兩個(gè)機(jī)房的數(shù)據(jù)還要「互相同步」數(shù)據(jù)器紧,即客戶端無(wú)論寫(xiě)哪一個(gè)機(jī)房耀销,都能把這條數(shù)據(jù)同步到另一個(gè)機(jī)房。
因?yàn)橹挥袃蓚€(gè)機(jī)房都擁有「全量數(shù)據(jù)」铲汪,才能支持任意切換機(jī)房熊尉,持續(xù)提供服務(wù)。
怎么實(shí)現(xiàn)這種「雙主」架構(gòu)呢掌腰?它們之間如何互相同步數(shù)據(jù)狰住?
如果你對(duì) MySQL 有所了解,MySQL 本身就提供了雙主架構(gòu)齿梁,它支持雙向復(fù)制數(shù)據(jù)催植,但平時(shí)用的并不多。而且 Redis勺择、MongoDB 等數(shù)據(jù)庫(kù)并沒(méi)有提供這個(gè)功能查邢,所以,你必須開(kāi)發(fā)對(duì)應(yīng)的「數(shù)據(jù)同步中間件」來(lái)實(shí)現(xiàn)雙向同步的功能酵幕。
此外扰藕,除了數(shù)據(jù)庫(kù)這種有狀態(tài)的軟件之外,你的項(xiàng)目通常還會(huì)使用到消息隊(duì)列芳撒,例如 RabbitMQ邓深、Kafka,這些也是有狀態(tài)的服務(wù)笔刹,所以它們也需要開(kāi)發(fā)雙向同步的中間件芥备,支持任意機(jī)房寫(xiě)入數(shù)據(jù),同步至另一個(gè)機(jī)房舌菜。
看到了么萌壳,這一下子復(fù)雜度就上來(lái)了,單單針對(duì)每個(gè)數(shù)據(jù)庫(kù)日月、隊(duì)列開(kāi)發(fā)同步中間件袱瓮,就需要投入很大精力了。
業(yè)界也開(kāi)源出了很多數(shù)據(jù)同步中間件爱咬,例如阿里的 Canal尺借、RedisShake、MongoShake精拟,可分別在兩個(gè)機(jī)房同步 MySQL燎斩、Redis虱歪、MongoDB 數(shù)據(jù)。
很多有能力的公司栅表,也會(huì)采用自研同步中間件的方式來(lái)做笋鄙,例如餓了么、攜程怪瓶、美團(tuán)都開(kāi)發(fā)了自己的同步中間件局装。
我也有幸參與設(shè)計(jì)開(kāi)發(fā)了 MySQL、Redis/Codis劳殖、MongoDB 的同步中間件铐尚,有時(shí)間寫(xiě)一篇文章詳細(xì)聊聊實(shí)現(xiàn)細(xì)節(jié),歡迎持續(xù)關(guān)注哆姻。:)
現(xiàn)在宣增,整個(gè)架構(gòu)就變成了這樣:
注意看,兩個(gè)機(jī)房的存儲(chǔ)層都互相同步數(shù)據(jù)的矛缨。有了數(shù)據(jù)同步中間件爹脾,就可以達(dá)到這樣的效果:
- 北京機(jī)房寫(xiě)入 X = 1
- 上海機(jī)房寫(xiě)入 Y = 2
- 數(shù)據(jù)通過(guò)中間件雙向同步
- 北京、上海機(jī)房都有 X = 1箕昭、Y = 2 的數(shù)據(jù)
這里我們用中間件雙向同步數(shù)據(jù)灵妨,就不用再擔(dān)心專線問(wèn)題,專線出問(wèn)題落竹,我們的中間件可以自動(dòng)重試泌霍,直到成功,達(dá)到數(shù)據(jù)最終一致述召。
但這里還會(huì)遇到一個(gè)問(wèn)題朱转,兩個(gè)機(jī)房都可以寫(xiě),操作的不是同一條數(shù)據(jù)那還好积暖,如果修改的是同一條的數(shù)據(jù)藤为,發(fā)生沖突怎么辦?
- 用戶短時(shí)間內(nèi)發(fā)了 2 個(gè)修改請(qǐng)求夺刑,都是修改同一條數(shù)據(jù)
- 一個(gè)請(qǐng)求落在北京機(jī)房缅疟,修改 X = 1(還未同步到上海機(jī)房)
- 另一個(gè)請(qǐng)求落在上海機(jī)房,修改 X = 2(還未同步到北京機(jī)房)
- 兩個(gè)機(jī)房以哪個(gè)為準(zhǔn)遍愿?
也就是說(shuō)存淫,在很短的時(shí)間內(nèi),同一個(gè)用戶修改同一條數(shù)據(jù)错览,兩個(gè)機(jī)房無(wú)法確認(rèn)誰(shuí)先誰(shuí)后纫雁,數(shù)據(jù)發(fā)生「沖突」。
這是一個(gè)很嚴(yán)重的問(wèn)題倾哺,系統(tǒng)發(fā)生故障并不可怕轧邪,可怕的是數(shù)據(jù)發(fā)生「錯(cuò)誤」,因?yàn)樾拚龜?shù)據(jù)的成本太高了羞海。我們一定要避免這種情況的發(fā)生忌愚。解決這個(gè)問(wèn)題,有 2 個(gè)方案却邓。
第一個(gè)方案硕糊,數(shù)據(jù)同步中間件要有自動(dòng)「合并」數(shù)據(jù)、解決「沖突」的能力腊徙。
這個(gè)方案實(shí)現(xiàn)起來(lái)比較復(fù)雜简十,要想合并數(shù)據(jù),就必須要區(qū)分出「先后」順序撬腾。我們很容易想到的方案螟蝙,就是以「時(shí)間」為標(biāo)尺,以「后到達(dá)」的請(qǐng)求為準(zhǔn)民傻。
但這種方案需要兩個(gè)機(jī)房的「時(shí)鐘」嚴(yán)格保持一致才行胰默,否則很容易出現(xiàn)問(wèn)題。例如:
- 第 1 個(gè)請(qǐng)求落到北京機(jī)房漓踢,北京機(jī)房時(shí)鐘是 10:01牵署,修改 X = 1
- 第 2 個(gè)請(qǐng)求落到上海機(jī)房,上海機(jī)房時(shí)鐘是 10:00喧半,修改 X = 2
因?yàn)楸本C(jī)房的時(shí)間「更晚」奴迅,那最終結(jié)果就會(huì)是 X = 1。但這里其實(shí)應(yīng)該以第 2 個(gè)請(qǐng)求為準(zhǔn)挺据,X = 2 才對(duì)半沽。
可見(jiàn),完全「依賴」時(shí)鐘的沖突解決方案吴菠,不太嚴(yán)謹(jǐn)者填。
所以,通常會(huì)采用第二種方案做葵,從「源頭」就避免數(shù)據(jù)沖突的發(fā)生占哟。
10 如何實(shí)施異地雙活
既然自動(dòng)合并數(shù)據(jù)的方案實(shí)現(xiàn)成本高,那我們就要想酿矢,能否從源頭就「避免」數(shù)據(jù)沖突呢榨乎?
這個(gè)思路非常棒!
從源頭避免數(shù)據(jù)沖突的思路是:在最上層接入流量時(shí)瘫筐,就不要讓沖突的情況發(fā)生蜜暑。
具體來(lái)講就是,要在最上層就把用戶「區(qū)分」開(kāi)策肝,部分用戶請(qǐng)求固定打到北京機(jī)房肛捍,其它用戶請(qǐng)求固定打到上海 機(jī)房隐绵,進(jìn)入某個(gè)機(jī)房的用戶請(qǐng)求,之后的所有業(yè)務(wù)操作拙毫,都在這一個(gè)機(jī)房?jī)?nèi)完成依许,從根源上避免「跨機(jī)房」。
所以這時(shí)缀蹄,你需要在接入層之上峭跳,再部署一個(gè)「路由層」(通常部署在云服務(wù)器上),自己可以配置路由規(guī)則缺前,把用戶「分流」到不同的機(jī)房?jī)?nèi)蛀醉。
但這個(gè)路由規(guī)則,具體怎么定呢衅码?有很多種實(shí)現(xiàn)方式拯刁,最常見(jiàn)的我總結(jié)了 3 類:
- 按業(yè)務(wù)類型分片
- 直接哈希分片
- 按地理位置分片
1、按業(yè)務(wù)類型分片
這種方案是指肆良,按應(yīng)用的「業(yè)務(wù)類型」來(lái)劃分筛璧。
舉例:假設(shè)我們一共有 4 個(gè)應(yīng)用,北京和上海機(jī)房都部署這些應(yīng)用惹恃。但應(yīng)用 1夭谤、2 只在北京機(jī)房接入流量,在上海機(jī)房只是熱備巫糙。應(yīng)用 3朗儒、4 只在上海機(jī)房接入流量,在北京機(jī)房是熱備参淹。
這樣一來(lái)醉锄,應(yīng)用 1、2 的所有業(yè)務(wù)請(qǐng)求浙值,只讀寫(xiě)北京機(jī)房存儲(chǔ)恳不,應(yīng)用 3、4 的所有請(qǐng)求开呐,只會(huì)讀寫(xiě)上海機(jī)房存儲(chǔ)烟勋。
這樣按業(yè)務(wù)類型分片,也可以避免同一個(gè)用戶修改同一條數(shù)據(jù)筐付。
這里按業(yè)務(wù)類型在不同機(jī)房接入流量卵惦,還需要考慮多個(gè)應(yīng)用之間的依賴關(guān)系,要盡可能的把完成「相關(guān)」業(yè)務(wù)的應(yīng)用部署在同一個(gè)機(jī)房瓦戚,避免跨機(jī)房調(diào)用沮尿。
例如,訂單较解、支付服務(wù)有依賴關(guān)系,會(huì)產(chǎn)生互相調(diào)用,那這 2 個(gè)服務(wù)在 A 機(jī)房接入流量谷异。社區(qū)、發(fā)帖服務(wù)有依賴關(guān)系乍楚,那這 2 個(gè)服務(wù)在 B 機(jī)房接入流量当编。
2届慈、直接哈希分片
這種方案就是,最上層的路由層忿偷,會(huì)根據(jù)用戶 ID 計(jì)算「哈辖鸲伲」取模,然后從路由表中找到對(duì)應(yīng)的機(jī)房鲤桥,之后把請(qǐng)求轉(zhuǎn)發(fā)到指定機(jī)房?jī)?nèi)揍拆。
舉例:一共 200 個(gè)用戶,根據(jù)用戶 ID 計(jì)算哈希值茶凳,然后根據(jù)路由規(guī)則嫂拴,把用戶 1 - 100 路由到北京機(jī)房,101 - 200 用戶路由到上海機(jī)房贮喧,這樣筒狠,就避免了同一個(gè)用戶修改同一條數(shù)據(jù)的情況發(fā)生。
3箱沦、按地理位置分片
這種方案辩恼,非常適合與地理位置密切相關(guān)的業(yè)務(wù),例如打車谓形、外賣服務(wù)就非常適合這種方案灶伊。
拿外賣服務(wù)舉例,你要點(diǎn)外賣肯定是「就近」點(diǎn)餐寒跳,整個(gè)業(yè)務(wù)范圍相關(guān)的有商家聘萨、用戶、騎手童太,它們都是在相同的地理位置內(nèi)的米辐。
針對(duì)這種特征,就可以在最上層康愤,按用戶的「地理位置」來(lái)做分片儡循,分散到不同的機(jī)房。
舉例:北京征冷、河北地區(qū)的用戶點(diǎn)餐择膝,請(qǐng)求只會(huì)打到北京機(jī)房,而上海检激、浙江地區(qū)的用戶肴捉,請(qǐng)求則只會(huì)打到上海機(jī)房腹侣。這樣的分片規(guī)則,也能避免數(shù)據(jù)沖突齿穗。
提醒:這 3 種常見(jiàn)的分片規(guī)則傲隶,第一次看不太好理解,建議配合圖多理解幾遍窃页。搞懂這 3 個(gè)分片規(guī)則跺株,你才能真正明白怎么做異地多活。
總之脖卖,分片的核心思路在于乒省,讓同一個(gè)用戶的相關(guān)請(qǐng)求,只在一個(gè)機(jī)房?jī)?nèi)完成所有業(yè)務(wù)「閉環(huán)」畦木,不再出現(xiàn)「跨機(jī)房」訪問(wèn)袖扛。
阿里在實(shí)施這種方案時(shí),給它起了個(gè)名字十籍,叫做「單元化」蛆封。
當(dāng)然,最上層的路由層把用戶分片后勾栗,理論來(lái)說(shuō)同一個(gè)用戶只會(huì)落在同一個(gè)機(jī)房?jī)?nèi)惨篱,但不排除程序 Bug 導(dǎo)致用戶會(huì)在兩個(gè)機(jī)房「漂移」。
安全起見(jiàn)械姻,每個(gè)機(jī)房在寫(xiě)存儲(chǔ)時(shí)妒蛇,還需要有一套機(jī)制,能夠檢測(cè)「數(shù)據(jù)歸屬」楷拳,應(yīng)用層操作存儲(chǔ)時(shí)绣夺,需要通過(guò)中間件來(lái)做「兜底」,避免不該寫(xiě)本機(jī)房的情況發(fā)生欢揖。(篇幅限制陶耍,這里不展開(kāi)講,理解思路即可)
現(xiàn)在她混,兩個(gè)機(jī)房就可以都接收「讀寫(xiě)」流量(做好分片的請(qǐng)求)烈钞,底層存儲(chǔ)保持「雙向」同步,兩個(gè)機(jī)房都擁有全量數(shù)據(jù)坤按,當(dāng)任意機(jī)房故障時(shí)毯欣,另一個(gè)機(jī)房就可以「接管」全部流量,實(shí)現(xiàn)快速切換臭脓,簡(jiǎn)直不要太爽酗钞。
不僅如此,因?yàn)闄C(jī)房部署在異地,我們還可以更細(xì)化地「優(yōu)化」路由規(guī)則砚作,讓用戶訪問(wèn)就近的機(jī)房窘奏,這樣整個(gè)系統(tǒng)的性能也會(huì)大大提升。
這里還有一種情況葫录,是無(wú)法做數(shù)據(jù)分片的:全局?jǐn)?shù)據(jù)着裹。例如系統(tǒng)配置、商品庫(kù)存這類需要強(qiáng)一致的數(shù)據(jù)米同,這類服務(wù)依舊只能采用寫(xiě)主機(jī)房骇扇,讀從機(jī)房的方案,不做雙活窍霞。
雙活的重點(diǎn)匠题,是要優(yōu)先保證「核心」業(yè)務(wù)先實(shí)現(xiàn)雙活拯坟,并不是「全部」業(yè)務(wù)實(shí)現(xiàn)雙活但金。
至此,我們才算實(shí)現(xiàn)了真正的「異地雙活」郁季!
到這里你可以看出冷溃,完成這樣一套架構(gòu),需要投入的成本是巨大的梦裂。
路由規(guī)則似枕、路由轉(zhuǎn)發(fā)、數(shù)據(jù)同步中間件年柠、數(shù)據(jù)校驗(yàn)兜底策略凿歼,不僅需要開(kāi)發(fā)強(qiáng)大的中間件,同時(shí)還要業(yè)務(wù)配合改造(業(yè)務(wù)邊界劃分冗恨、依賴拆分)等一些列工作答憔,沒(méi)有足夠的人力物力,這套架構(gòu)很難實(shí)施掀抹。
11 異地多活
理解了異地雙活虐拓,那「異地多活」顧名思義,就是在異地雙活的基礎(chǔ)上傲武,部署多個(gè)機(jī)房即可蓉驹。架構(gòu)變成了這樣:
這些服務(wù)按照「單元化」的部署方式,可以讓每個(gè)機(jī)房部署在任意地區(qū)揪利,隨時(shí)擴(kuò)展新機(jī)房态兴,你只需要在最上層定義好分片規(guī)則就好了。
但這里還有一個(gè)小問(wèn)題疟位,隨著擴(kuò)展的機(jī)房越來(lái)越多瞻润,當(dāng)一個(gè)機(jī)房寫(xiě)入數(shù)據(jù)后,需要同步的機(jī)房也越來(lái)越多,這個(gè)實(shí)現(xiàn)復(fù)雜度會(huì)比較高敢订。
所以業(yè)界又把這一架構(gòu)又做了進(jìn)一步優(yōu)化王污,把「網(wǎng)狀」架構(gòu)升級(jí)為「星狀」:
[圖片上傳中...(image-876669-1640589611145-0)]
這種方案必須設(shè)立一個(gè)「中心機(jī)房」,任意機(jī)房寫(xiě)入數(shù)據(jù)后楚午,都只同步到中心機(jī)房昭齐,再由中心機(jī)房同步至其它機(jī)房。
這樣做的好處是矾柜,一個(gè)機(jī)房寫(xiě)入數(shù)據(jù)阱驾,只需要同步數(shù)據(jù)到中心機(jī)房即可,不需要再關(guān)心一共部署了多少個(gè)機(jī)房怪蔑,實(shí)現(xiàn)復(fù)雜度大大「簡(jiǎn)化」里覆。
但與此同時(shí),這個(gè)中心機(jī)房的「穩(wěn)定性」要求會(huì)比較高缆瓣。不過(guò)也還好喧枷,即使中心機(jī)房發(fā)生故障,我們也可以把任意一個(gè)機(jī)房弓坞,提升為中心機(jī)房隧甚,繼續(xù)按照之前的架構(gòu)提供服務(wù)。
至此渡冻,我們的系統(tǒng)徹底實(shí)現(xiàn)了「異地多活」戚扳!
多活的優(yōu)勢(shì)在于,可以任意擴(kuò)展機(jī)房「就近」部署族吻。任意機(jī)房發(fā)生故障帽借,可以完成快速「切換」,大大提高了系統(tǒng)的可用性超歌。
同時(shí)砍艾,我們也再也不用擔(dān)心系統(tǒng)規(guī)模的增長(zhǎng),因?yàn)檫@套架構(gòu)具有極強(qiáng)的「擴(kuò)展能力」握础。
怎么樣辐董?我們從一個(gè)最簡(jiǎn)單的應(yīng)用,一路優(yōu)化下來(lái)禀综,到最終的架構(gòu)方案简烘,有沒(méi)有幫你徹底理解異地多活呢?
總結(jié)
好了定枷,總結(jié)一下這篇文章的重點(diǎn)孤澎。
1、一個(gè)好的軟件架構(gòu)欠窒,應(yīng)該遵循高性能覆旭、高可用退子、易擴(kuò)展 3 大原則,其中「高可用」在系統(tǒng)規(guī)模變得越來(lái)越大時(shí)型将,變得尤為重要
2寂祥、系統(tǒng)發(fā)生故障并不可怕,能以「最快」的速度恢復(fù)七兜,才是高可用追求的目標(biāo)丸凭,異地多活是實(shí)現(xiàn)高可用的有效手段
3、提升高可用的核心是「冗余」腕铸,備份惜犀、主從副本、同城災(zāi)備狠裹、同城雙活虽界、兩地三中心、異地雙活涛菠,異地多活都是在做冗余
4莉御、同城災(zāi)備分為「冷備」和「熱備」,冷備只備份數(shù)據(jù)碗暗,不提供服務(wù)颈将,熱備實(shí)時(shí)同步數(shù)據(jù),并做好隨時(shí)切換的準(zhǔn)備
5言疗、同城雙活比災(zāi)備的優(yōu)勢(shì)在于,兩個(gè)機(jī)房都可以接入「讀寫(xiě)」流量颂砸,提高可用性的同時(shí)噪奄,還提升了系統(tǒng)性能。雖然物理上是兩個(gè)機(jī)房人乓,但「邏輯」上還是當(dāng)做一個(gè)機(jī)房來(lái)用
6勤篮、兩地三中心是在同城雙活的基礎(chǔ)上,額外部署一個(gè)異地機(jī)房做「災(zāi)備」色罚,用來(lái)抵御「城市」級(jí)別的災(zāi)害碰缔,但啟用災(zāi)備機(jī)房需要時(shí)間
7、異地雙活才是抵御「城市」級(jí)別災(zāi)害的更好方案戳护,兩個(gè)機(jī)房同時(shí)提供服務(wù)金抡,故障隨時(shí)可切換,可用性高腌且。但實(shí)現(xiàn)也最復(fù)雜梗肝,理解了異地雙活,才能徹底理解異地多活
8铺董、異地多活是在異地雙活的基礎(chǔ)上巫击,任意擴(kuò)展多個(gè)機(jī)房,不僅又提高了可用性,還能應(yīng)對(duì)更大規(guī)模的流量的壓力坝锰,擴(kuò)展性最強(qiáng)粹懒,是實(shí)現(xiàn)高可用的最終方案
后記
這篇文章我從「宏觀」層面,向你介紹了異地多活架構(gòu)的「核心」思路顷级,整篇文章的信息量還是很大的崎淳,如果不太好理解,我建議你多讀幾遍愕把。
因?yàn)槠拗萍鸢迹芏嗉?xì)節(jié)我并沒(méi)有展開(kāi)來(lái)講。這篇文章更像是講異地多活的架構(gòu)之「道」恨豁,而真正實(shí)施的「術(shù)」嚣镜,要考慮的點(diǎn)其實(shí)也非常繁多,因?yàn)樗枰_(kāi)發(fā)強(qiáng)大的「基礎(chǔ)設(shè)施」才可以完成實(shí)施橘蜜。
不僅如此菊匿,要想真正實(shí)現(xiàn)異地多活,還需要遵循一些原則计福,例如業(yè)務(wù)梳理跌捆、業(yè)務(wù)分級(jí)、數(shù)據(jù)分類象颖、數(shù)據(jù)最終一致性保障佩厚、機(jī)房切換一致性保障、異常處理等等说订。同時(shí)抄瓦,相關(guān)的運(yùn)維設(shè)施、監(jiān)控體系也要能跟得上才行陶冷。
宏觀上需要考慮業(yè)務(wù)(微服務(wù)部署钙姊、依賴、拆分埂伦、SDK煞额、Web 框架)、基礎(chǔ)設(shè)施(服務(wù)發(fā)現(xiàn)沾谜、流量調(diào)度膊毁、持續(xù)集成、同步中間件类早、自研存儲(chǔ))媚媒,微觀上要開(kāi)發(fā)各種中間件,還要關(guān)注中間件的高性能涩僻、高可用缭召、容錯(cuò)能力栈顷,其復(fù)雜度之高,只有親身參與過(guò)之后才知道嵌巷。
我曾經(jīng)有幸參與過(guò)萄凤,存儲(chǔ)層同步中間件的設(shè)計(jì)與開(kāi)發(fā),實(shí)現(xiàn)過(guò)「跨機(jī)房」同步 MySQL搪哪、Redis靡努、MongoDB 的中間件,踩過(guò)的坑也非常多晓折。當(dāng)然惑朦,這些中間件的設(shè)計(jì)思路也非常有意思,有時(shí)間單獨(dú)分享一下這些中間件的設(shè)計(jì)思路漓概。
值得提醒你的是漾月,只有真正理解了「異地雙活」,才能徹底理解「異地多活」胃珍。在我看來(lái)梁肿,從同城雙活演變?yōu)楫惖仉p活的過(guò)程,是最為復(fù)雜的觅彰,最核心的東西包括吩蔑,業(yè)務(wù)單元化劃分、存儲(chǔ)層數(shù)據(jù)雙向同步填抬、最上層的分片邏輯烛芬,這些是實(shí)現(xiàn)異地多活的重中之重。