Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 499, comments - 13, trackbacks - 0, articles - 1

          本文由公眾號(hào)“水滴與銀彈”號(hào)主Kaito原創(chuàng)分享,原題“搞懂異地多活,看這篇就夠了”,為使文章更好理解,即時(shí)通訊網(wǎng)收錄時(shí)有修訂。

          1、引言

          前幾天技術(shù)群里有群友問我52im社區(qū)里有沒有IM分布式系統(tǒng)異地多活方面的文章,我仔細(xì)想了想,除了微信分享的幾篇文章里有提到容災(zāi)和異地多活(只是大致提過,沒有詳細(xì)展開),確實(shí)目前還沒有系統(tǒng)性的異地多活技術(shù)資料可供參考。正好借此機(jī)會(huì),整理了Kaito分享的這篇供大家學(xué)習(xí)。

          本文從一個(gè)簡單的系統(tǒng)例子開始,從單機(jī)架構(gòu)、主從副本、同城災(zāi)備、同城雙活,再到異地雙活、異地多活,由淺入深、循序漸進(jìn)地講解了大型分布式系統(tǒng)異地多活容災(zāi)架構(gòu)的技術(shù)原理和基本的實(shí)現(xiàn)思路,非常適合入門者學(xué)習(xí)。

          學(xué)習(xí)交流:

          - 即時(shí)通訊/推送技術(shù)開發(fā)交流5群:215477170 [推薦]

          - 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM

          - 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK 

          本文同步發(fā)布于:http://www.52im.net/thread-3742-1-1.html)

          2、系列文章

          本文是IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課系列文章中的第10篇:

          1. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(一):正確理解前置HTTP SSO單點(diǎn)登陸接口的原理
          2. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(二):如何設(shè)計(jì)大量圖片文件的服務(wù)端存儲(chǔ)架構(gòu)?
          3. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(三):快速理解服務(wù)端數(shù)據(jù)庫讀寫分離原理及實(shí)踐建議
          4. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(四):正確理解HTTP短連接中的Cookie、Session和Token
          5. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(五):通俗易懂,正確理解并用好MQ消息隊(duì)列
          6. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(六):數(shù)據(jù)庫用NoSQL還是SQL?讀這篇就夠了!
          7. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(七):主流移動(dòng)端賬號(hào)登錄方式的原理及設(shè)計(jì)思路
          8. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(八):史上最通俗,徹底搞懂字符亂碼問題的本質(zhì)
          9. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(九):想開發(fā)IM集群?先搞懂什么是RPC!
          10. IM開發(fā)基礎(chǔ)知識(shí)補(bǔ)課(十):大型IM系統(tǒng)有多難?萬字長文,搞懂異地多活!》(* 本文

          以下是文章中也有關(guān)于容災(zāi)和異地多活的內(nèi)容:

          1. 快速裂變:見證微信強(qiáng)大后臺(tái)架構(gòu)從0到1的演進(jìn)歷程(二)
          2. IM消息ID技術(shù)專題(二):微信的海量IM聊天消息序列號(hào)生成實(shí)踐(容災(zāi)方案篇)
          3. 淘寶技術(shù)分享:手淘億級(jí)移動(dòng)端接入層網(wǎng)關(guān)的技術(shù)演進(jìn)之路

          3、內(nèi)容概述

          在軟件開發(fā)領(lǐng)域,「異地多活」是分布式系統(tǒng)架構(gòu)設(shè)計(jì)的一座高峰,很多人經(jīng)常聽過它,但很少人理解其中的原理。

          異地多活到底是什么?為什么需要異地多活?它到底解決了什么問題?究竟是怎么解決的?

          這些疑問,想必是每個(gè)程序看到異地多活這個(gè)名詞時(shí),都想要搞明白的問題。

          我曾經(jīng)有幸深度參與過一個(gè)中等互聯(lián)網(wǎng)公司異地多活系統(tǒng)的設(shè)計(jì)與實(shí)施過程。所以今天,我就來和你聊一聊異地多活背后的的實(shí)現(xiàn)原理。

          認(rèn)真讀完這篇文章,我相信你會(huì)對異地多活架構(gòu),有更加深刻的理解。

          4、什么是系統(tǒng)可用性

          要想理解異地多活,我們需要從架構(gòu)設(shè)計(jì)的原則說起。

          現(xiàn)如今,我們開發(fā)一個(gè)軟件系統(tǒng),對其要求越來越高,如果你了解一些「架構(gòu)設(shè)計(jì)」的要求,就知道一個(gè)好的軟件架構(gòu)應(yīng)該遵循以下 3 個(gè)原則。

          它們是:

          • 1)高性能;
          • 2)高可用;
          • 3)易擴(kuò)展。

          其中:

          • 1)高性能:意味著系統(tǒng)擁有更大流量的處理能力,更低的響應(yīng)延遲(例如 1 秒可處理 10W 并發(fā)請求,接口響應(yīng)時(shí)間 5 ms 等等);
          • 2)易擴(kuò)展:表示系統(tǒng)在迭代新功能時(shí),能以最小的代價(jià)去擴(kuò)展,系統(tǒng)遇到流量壓力時(shí),可以在不改動(dòng)代碼的前提下,去擴(kuò)容系統(tǒng)。

          而「高可用」這個(gè)概念,看起來很抽象,怎么理解它呢?

          通常用 2 個(gè)指標(biāo)來衡量:

          • 1)平均故障間隔 MTBF(Mean Time Between Failure):表示兩次故障的間隔時(shí)間,也就是系統(tǒng)「正常運(yùn)行」的平均時(shí)間,這個(gè)時(shí)間越長,說明系統(tǒng)穩(wěn)定性越高;
          • 2)故障恢復(fù)時(shí)間 MTTR(Mean Time To Repair):表示系統(tǒng)發(fā)生故障后「恢復(fù)的時(shí)間」,這個(gè)值越小,故障對用戶的影響越小。

          可用性與這兩者的關(guān)系:

          可用性(Availability)= MTBF / (MTBF + MTTR) * 100%

          這個(gè)公式得出的結(jié)果是一個(gè)「比例」,通常我們會(huì)用「N 個(gè) 9」來描述一個(gè)系統(tǒng)的可用性。

          從這張圖你可以看到,要想達(dá)到 4 個(gè) 9 以上的可用性,平均每天故障時(shí)間必須控制在 10 秒以內(nèi)。

          也就是說,只有故障的時(shí)間「越短」,整個(gè)系統(tǒng)的可用性才會(huì)越高,每提升 1 個(gè) 9,都會(huì)對系統(tǒng)提出更高的要求。

          我們都知道,系統(tǒng)發(fā)生故障其實(shí)是不可避免的,尤其是規(guī)模越大的系統(tǒng),發(fā)生問題的概率也越大。

          這些故障一般體現(xiàn)在 3 個(gè)方面:

          • 1)硬件故障:CPU、內(nèi)存、磁盤、網(wǎng)卡、交換機(jī)、路由器;
          • 2)軟件問題:代碼 Bug、版本迭代;
          • 3)不可抗力:地震、水災(zāi)、火災(zāi)、戰(zhàn)爭。

          這些風(fēng)險(xiǎn)隨時(shí)都有可能發(fā)生。所以在面對故障時(shí),我們的系統(tǒng)能否以「最快」的速度恢復(fù),就成為了可用性的關(guān)鍵。

          可如何做到快速恢復(fù)呢?

          這篇文章要講的「異地多活」架構(gòu),就是為了解決這個(gè)問題,而提出的高效解決方案。

          本文余下的內(nèi)容,我將會(huì)從一個(gè)最簡單的系統(tǒng)出發(fā),帶你一步步演化出一個(gè)支持「異地多活」的系統(tǒng)架構(gòu)。

          在這個(gè)過程中,你會(huì)看到一個(gè)系統(tǒng)會(huì)遇到哪些可用性問題,以及為什么架構(gòu)要這樣演進(jìn),從而理解異地多活架構(gòu)的意義。

          5、單機(jī)架構(gòu)

          我們從最簡單的開始講起。

          假設(shè)你的業(yè)務(wù)處于起步階段,體量非常小,那你的架構(gòu)是這樣的:

          這個(gè)架構(gòu)模型非常簡單,客戶端請求進(jìn)來,業(yè)務(wù)應(yīng)用讀寫數(shù)據(jù)庫,返回結(jié)果,非常好理解。

          但需要注意的是,這里的數(shù)據(jù)庫是「單機(jī)」部署的,所以它有一個(gè)致命的缺點(diǎn):即一旦遭遇意外(例如磁盤損壞、操作系統(tǒng)異常、誤刪數(shù)據(jù)),那這意味著所有數(shù)據(jù)就全部「丟失」了,這個(gè)損失是巨大的。

          如何避免這個(gè)問題呢?我們很容易想到一個(gè)方案:備份

           你可以對數(shù)據(jù)做備份,把數(shù)據(jù)庫文件「定期」cp 到另一臺(tái)機(jī)器上。這樣,即使原機(jī)器丟失數(shù)據(jù),你依舊可以通過備份把數(shù)據(jù)「恢復(fù)」回來,以此保證數(shù)據(jù)安全。

          這個(gè)方案實(shí)施起來雖然比較簡單,但存在 2 個(gè)問題:

          • 1)恢復(fù)需時(shí)間:業(yè)務(wù)需先停機(jī),再恢復(fù)數(shù)據(jù),停機(jī)時(shí)間取決于恢復(fù)的速度,恢復(fù)期間服務(wù)「不可用」;
          • 2)數(shù)據(jù)不完整:因?yàn)槭嵌ㄆ趥浞荩瑪?shù)據(jù)肯定不是「最新」的,數(shù)據(jù)完整程度取決于備份的周期。

          很明顯:你的數(shù)據(jù)庫越大,意味故障恢復(fù)時(shí)間越久。按照前面我們提到的「高可用」標(biāo)準(zhǔn),這個(gè)方案可能連 1 個(gè) 9 都達(dá)不到,遠(yuǎn)遠(yuǎn)無法滿足我們對可用性的要求。

          那有什么更好的方案,既可以快速恢復(fù)業(yè)務(wù)?還能盡可能保證數(shù)據(jù)完整性呢?

          這時(shí)你可以采用這個(gè)方案:主從副本。

          6、主從副本架構(gòu)

          針對上節(jié)中單機(jī)架構(gòu)的問題,你可以在另一臺(tái)機(jī)器上,再部署一個(gè)數(shù)據(jù)庫實(shí)例,讓這個(gè)新實(shí)例成為原實(shí)例的「副本」,讓兩者保持「實(shí)時(shí)同步」。

          就像這樣:

           我們一般把原實(shí)例叫作主庫(master),新實(shí)例叫作從庫(slave)。

          這個(gè)方案的優(yōu)點(diǎn)在于:

          • 1)數(shù)據(jù)完整性高:主從副本實(shí)時(shí)同步,數(shù)據(jù)「差異」很小;
          • 2)抗故障能力提升:主庫有任何異常,從庫可隨時(shí)「切換」為主庫,繼續(xù)提供服務(wù);
          • 3)讀性能提升:業(yè)務(wù)應(yīng)用可直接讀從庫,分擔(dān)主庫「壓力」讀壓力。

          這個(gè)方案不錯(cuò):不僅大大提高了數(shù)據(jù)庫的可用性,還提升了系統(tǒng)的讀性能。

          同樣的思路,你的「業(yè)務(wù)應(yīng)用」也可以在其它機(jī)器部署一份,避免單點(diǎn)。因?yàn)闃I(yè)務(wù)應(yīng)用通常是「無狀態(tài)」的(不像數(shù)據(jù)庫那樣存儲(chǔ)數(shù)據(jù)),所以直接部署即可,非常簡單。

           因?yàn)闃I(yè)務(wù)應(yīng)用部署了多個(gè),所以你現(xiàn)在還需要部署一個(gè)「接入層」,來做請求的「負(fù)載均衡」(一般會(huì)使用 nginx 或 LVS),這樣當(dāng)一臺(tái)機(jī)器宕機(jī)后,另一臺(tái)機(jī)器也可以「接管」所有流量,持續(xù)提供服務(wù)。

           從這個(gè)方案你可以看出,提升可用性的關(guān)鍵思路就是:冗余

          沒錯(cuò):擔(dān)心一個(gè)實(shí)例故障,那就部署多個(gè)實(shí)例,擔(dān)心一個(gè)機(jī)器宕機(jī),那就部署多臺(tái)機(jī)器。

          到這里:你的架構(gòu)基本已演變成主流方案了,之后開發(fā)新的業(yè)務(wù)應(yīng)用,都可以按照這種模式去部署。

          但這種方案還有什么風(fēng)險(xiǎn)嗎?

          7、一個(gè)容易被可忽視的風(fēng)險(xiǎn)

          現(xiàn)在讓我們把視角下放,把焦點(diǎn)放到具體的「部署細(xì)節(jié)」上來。

          按照前面的分析,為了避免單點(diǎn)故障,你的應(yīng)用雖然部署了多臺(tái)機(jī)器,但這些機(jī)器的分布情況,我們并沒有去深究。

          而一個(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ī) / 路由器也做了路線冗余,但不能保證一定不出問題。

          部署在一個(gè)機(jī)柜有風(fēng)險(xiǎn),那把這些機(jī)器打散,分散到不同機(jī)柜上,是不是就沒問題了?

          這樣確實(shí)會(huì)大大降低出問題的概率。但我們依舊不能掉以輕心,因?yàn)闊o論怎么分散,它們總歸還是在一個(gè)相同的環(huán)境下:機(jī)房。

          那繼續(xù)追問,機(jī)房會(huì)不會(huì)發(fā)生故障呢?

          一般來講,建設(shè)一個(gè)機(jī)房的要求其實(shí)是很高的,地理位置、溫濕度控制、備用電源等等,機(jī)房廠商會(huì)在各方面做好防護(hù)。

          但即使這樣,我們每隔一段時(shí)間還會(huì)看到這樣的新聞:

          2015 年 5 月 27 日,杭州市某地光纖被挖斷,近 3 億用戶長達(dá) 5 小時(shí)無法訪問支付寶;

          2021 年 7 月 13 日,B 站部分服務(wù)器機(jī)房發(fā)生故障,造成整站持續(xù) 3 個(gè)小時(shí)無法訪問;

          2021 年 10 月 9 日,富途證券服務(wù)器機(jī)房發(fā)生電力閃斷故障,造成用戶 2 個(gè)小時(shí)無法登陸、交易;

          ...

          可見:即使機(jī)房級(jí)別的防護(hù)已經(jīng)做得足夠好,但只要有「概率」出問題,那現(xiàn)實(shí)情況就有可能發(fā)生(墨菲定律)。雖然概率很小,但一旦真的發(fā)生,影響之大可見一斑。

          看到這里你可能會(huì)想,機(jī)房出現(xiàn)問題的概率也太小了吧,工作了這么多年,也沒讓我碰上一次,有必要考慮得這么復(fù)雜嗎?

          但你有沒有思考這樣一個(gè)問題:不同體量的系統(tǒng),它們各自關(guān)注的重點(diǎn)是什么?

          • 1)體量很小的系統(tǒng),它會(huì)重點(diǎn)關(guān)注「用戶」規(guī)模、增長,這個(gè)階段獲取用戶是一切;
          • 2)等用戶體量上來了,這個(gè)階段會(huì)重點(diǎn)關(guān)注「性能」,優(yōu)化接口響應(yīng)時(shí)間、頁面打開速度等等,這個(gè)階段更多是關(guān)注用戶體驗(yàn);
          • 3)等體量再大到一定規(guī)模后你會(huì)發(fā)現(xiàn),「可用性」就變得尤為重要。像微信、支付寶這種全民級(jí)的應(yīng)用,如果機(jī)房發(fā)生一次故障,那整個(gè)影響范圍可以說是非常巨大的。

          所以,再小概率的風(fēng)險(xiǎn),我們在提高系統(tǒng)可用性時(shí),也不能忽視。

          分析了風(fēng)險(xiǎn),再說回我們的架構(gòu)。那到底該怎么應(yīng)對機(jī)房級(jí)別的故障呢?

          沒錯(cuò),還是冗余。

          8、同城災(zāi)備架構(gòu)

          想要抵御「機(jī)房」級(jí)別的風(fēng)險(xiǎn),那應(yīng)對方案就不能局限在一個(gè)機(jī)房內(nèi)了。

          現(xiàn)在,你需要做機(jī)房級(jí)別的冗余方案,也就是說,你需要再搭建一個(gè)機(jī)房,來部署你的服務(wù)。

          簡單起見,你可以在「同一個(gè)城市」再搭建一個(gè)機(jī)房,原機(jī)房我們叫作 A 機(jī)房,新機(jī)房叫 B 機(jī)房,這兩個(gè)機(jī)房的網(wǎng)絡(luò)用一條「專線」連通。

          有了新機(jī)房,怎么把它用起來呢?這里還是要優(yōu)先考慮「數(shù)據(jù)」風(fēng)險(xiǎn)。

          為了避免 A 機(jī)房故障導(dǎo)致數(shù)據(jù)丟失,所以我們需要把數(shù)據(jù)在 B 機(jī)房也存一份。最簡單的方案還是和前面提到的一樣:備份。

          A 機(jī)房的數(shù)據(jù),定時(shí)在 B 機(jī)房做備份(拷貝數(shù)據(jù)文件),這樣即使整個(gè) A 機(jī)房遭到嚴(yán)重的損壞,B 機(jī)房的數(shù)據(jù)不會(huì)丟,通過備份可以把數(shù)據(jù)「恢復(fù)」回來,重啟服務(wù)。

           這種方案,我們稱之為「冷備」。

          為什么叫冷備呢?因?yàn)?B 機(jī)房只做備份,不提供實(shí)時(shí)服務(wù),它是冷的,只會(huì)在 A 機(jī)房故障時(shí)才會(huì)啟用。

          但備份的問題依舊和之前描述的一樣:數(shù)據(jù)不完整、恢復(fù)數(shù)據(jù)期間業(yè)務(wù)不可用,整個(gè)系統(tǒng)的可用性還是無法得到保證。

          所以,我們還是需要用「主從副本」的方式,在 B 機(jī)房部署 A 機(jī)房的數(shù)據(jù)副本。

          架構(gòu)就變成了這樣:

           這樣:就算整個(gè) A 機(jī)房掛掉,我們在 B 機(jī)房也有比較「完整」的數(shù)據(jù)。

          數(shù)據(jù)是保住了,但這時(shí)你需要考慮另外一個(gè)問題——如果 A 機(jī)房真掛掉了,要想保證服務(wù)不中斷,你還需要在 B 機(jī)房「緊急」做這些事情。

          比如:

          • 1)B 機(jī)房所有從庫提升為主庫;
          • 2)在 B 機(jī)房部署應(yīng)用,啟動(dòng)服務(wù);
          • 3)部署接入層,配置轉(zhuǎn)發(fā)規(guī)則;
          • 4)DNS 指向 B 機(jī)房,接入流量,業(yè)務(wù)恢復(fù)。

          看到了么?A 機(jī)房故障后,B 機(jī)房需要做這么多工作,你的業(yè)務(wù)才能完全「恢復(fù)」過來。

          你看:整個(gè)過程需要人為介入,且需花費(fèi)大量時(shí)間來操作,恢復(fù)之前整個(gè)服務(wù)還是不可用的,這個(gè)方案還是不太爽,如果能做到故障后立即「切換」,那就好了。

          因此:要想縮短業(yè)務(wù)恢復(fù)的時(shí)間,你必須把這些工作在 B 機(jī)房「提前」做好,也就是說,你需要在 B 機(jī)房提前部署好接入層、業(yè)務(wù)應(yīng)用,等待隨時(shí)切換。

          架構(gòu)就變成了這樣:

          這樣的話,A 機(jī)房整個(gè)掛掉,我們只需要做 2 件事即可:

          • 1)B 機(jī)房所有從庫提升為主庫;
          • 2)DNS 指向 B 機(jī)房,接入流量,業(yè)務(wù)恢復(fù)。

          這樣一來,恢復(fù)速度快了很多。

          到這里你會(huì)發(fā)現(xiàn),B 機(jī)房從最開始的「空空如也」,演變到現(xiàn)在,幾乎是「鏡像」了一份 A 機(jī)房的所有東西,從最上層的接入層,到中間的業(yè)務(wù)應(yīng)用,到最下層的存儲(chǔ)。

          兩個(gè)機(jī)房唯一的區(qū)別是,A 機(jī)房的存儲(chǔ)都是主庫,而 B 機(jī)房都是從庫。

          這種方案,我們把它叫做「熱備」。

          “熱”的意思是指:B 機(jī)房處于「待命」?fàn)顟B(tài),A 故障后 B 可以隨時(shí)「接管」流量,繼續(xù)提供服務(wù)。

          熱備相比于冷備最大的優(yōu)點(diǎn)是:隨時(shí)可切換。

          無論是冷備還是熱備,因?yàn)樗鼈兌继幱凇競溆谩範(fàn)顟B(tài),所以我們把這兩個(gè)方案統(tǒng)稱為:同城災(zāi)備。

          同城災(zāi)備的最大優(yōu)勢在于:我們再也不用擔(dān)心「機(jī)房」級(jí)別的故障了,一個(gè)機(jī)房發(fā)生風(fēng)險(xiǎn),我們只需把流量切換到另一個(gè)機(jī)房即可,可用性再次提高,是不是很爽?(后面還有更爽的 ...)

          9、同城雙活架構(gòu)

          我們繼續(xù)來看上節(jié)的這個(gè)架構(gòu)。

          雖然我們有了應(yīng)對機(jī)房故障的解決方案,但這里有個(gè)問題是我們不能忽視的:A 機(jī)房掛掉,全部流量切到 B 機(jī)房,B 機(jī)房能否真的如我們所愿,正常提供服務(wù)?

          這是個(gè)值得思考的問題。

          這就好比有兩支軍隊(duì) A 和 B,A 軍隊(duì)歷經(jīng)沙場,作戰(zhàn)經(jīng)驗(yàn)豐富,而 B 軍隊(duì)只是后備軍,除了有軍人的基本素養(yǎng)之外,并沒有實(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í)是不敢百分百保證它可以「如期」工作的。

          你想:我們在一個(gè)機(jī)房內(nèi)部署服務(wù),還總是發(fā)生各種各樣的問題,例如:發(fā)布應(yīng)用的版本不一致、系統(tǒng)資源不足、操作系統(tǒng)參數(shù)不一樣等等。現(xiàn)在多部署一個(gè)機(jī)房,這些問題只會(huì)增多,不會(huì)減少。

          另外:從「成本」的角度來看,我們新部署一個(gè)機(jī)房,需要購買服務(wù)器、內(nèi)存、硬盤、帶寬資源,花費(fèi)成本也是非常高昂的,只讓它當(dāng)一個(gè)后備軍,未免也太「大材小用」了!

          因此:我們需要讓 B 機(jī)房也接入流量,實(shí)時(shí)提供服務(wù),這樣做的好處有兩個(gè)。

          • 一是可以實(shí)時(shí)訓(xùn)練這支后備軍,讓它達(dá)到與 A 機(jī)房相同的作戰(zhàn)水平,隨時(shí)可切換;
          • 二是 B 機(jī)房接入流量后,可以分擔(dān) A 機(jī)房的流量壓力。

          這才是把 B 機(jī)房資源優(yōu)勢,發(fā)揮最大化的最好方案!

          那怎么讓 B 機(jī)房也接入流量呢?很簡單,就是把 B 機(jī)房的接入層 IP 地址,加入到 DNS 中,這樣,B 機(jī)房從上層就可以有流量進(jìn)來了。

           但這里有一個(gè)問題:別忘了,B 機(jī)房的存儲(chǔ),現(xiàn)在可都是 A 機(jī)房的「從庫」,從庫默認(rèn)可都是「不可寫」的,B 機(jī)房的寫請求打到本機(jī)房存儲(chǔ)上,肯定會(huì)報(bào)錯(cuò),這還是不符合我們預(yù)期。怎么辦?

          這時(shí),你就需要在「業(yè)務(wù)應(yīng)用」層做改造了。

          你的業(yè)務(wù)應(yīng)用在操作數(shù)據(jù)庫時(shí),需要區(qū)分「讀寫分離」(一般用中間件實(shí)現(xiàn)),即兩個(gè)機(jī)房的「讀」流量,可以讀任意機(jī)房的存儲(chǔ),但「寫」流量,只允許寫 A 機(jī)房,因?yàn)橹鲙煸?A 機(jī)房。

           這會(huì)涉及到你用的所有存儲(chǔ),例如項(xiàng)目中用到了 MySQL、Redis、MongoDB 等等,操作這些數(shù)據(jù)庫,都需要區(qū)分讀寫請求,所以這塊需要一定的業(yè)務(wù)「改造」成本。

          因?yàn)?A 機(jī)房的存儲(chǔ)都是主庫,所以我們把 A 機(jī)房叫做「主機(jī)房」,B 機(jī)房叫「從機(jī)房」。

          兩個(gè)機(jī)房部署在「同城」,物理距離比較近,而且兩個(gè)機(jī)房用「專線」網(wǎng)絡(luò)連接,雖然跨機(jī)房訪問的延遲,比單個(gè)機(jī)房內(nèi)要大一些,但整體的延遲還是可以接受的。

          業(yè)務(wù)改造完成后,B 機(jī)房可以慢慢接入流量(從 10%、30%、50% 逐漸覆蓋到 100%)你可以持續(xù)觀察 B 機(jī)房的業(yè)務(wù)是否存在問題,有問題及時(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)從「邏輯」上來看,我們是把這兩個(gè)機(jī)房看做一個(gè)「整體」來規(guī)劃的,也就是說,相當(dāng)于把 2 個(gè)機(jī)房當(dāng)作 1 個(gè)機(jī)房來用。

          這種架構(gòu)方案:比前面的同城災(zāi)備更「進(jìn)了一步」,B 機(jī)房實(shí)時(shí)接入了流量,還能應(yīng)對隨時(shí)的故障切換,這種方案我們把它叫做「同城雙活」。

          因?yàn)閮蓚€(gè)機(jī)房都能處理業(yè)務(wù)請求,這對我們系統(tǒng)的內(nèi)部維護(hù)、改造、升級(jí)提供了更多的可實(shí)施空間(流量隨時(shí)切換),現(xiàn)在,整個(gè)系統(tǒng)的彈性也變大了,是不是更爽了?

          那這種架構(gòu)有什么問題呢?

          10、兩地三中心架構(gòu)

          還是回到風(fēng)險(xiǎn)上來說。

          如上節(jié)所述,雖然我們把 2 個(gè)機(jī)房當(dāng)做一個(gè)整體來規(guī)劃,但這 2 個(gè)機(jī)房在物理層面上,還是處于「一個(gè)城市」內(nèi),如果是整個(gè)城市發(fā)生自然災(zāi)害,例如地震、水災(zāi)(河南水災(zāi)剛過去不久),那 2 個(gè)機(jī)房依舊存在「全局覆沒」的風(fēng)險(xiǎn)。

          真是防不勝防啊。怎么辦?沒辦法,繼續(xù)冗余。

          但這次冗余機(jī)房,就不能部署在同一個(gè)城市了,你需要把它放到距離更遠(yuǎn)的地方,部署在「異地」。

          通常建議兩個(gè)機(jī)房的距離要在 1000 公里以上,這樣才能應(yīng)對城市級(jí)別的災(zāi)難。

          假設(shè)之前的 A、B 機(jī)房在北京,那這次新部署的 C 機(jī)房可以放在上海。

          按照前面的思路,把 C 機(jī)房用起來,最簡單粗暴的方案還就是做「冷備」,即定時(shí)把 A、B 機(jī)房的數(shù)據(jù),在 C 機(jī)房做備份,防止數(shù)據(jù)丟失。

          這種方案,就是我們經(jī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)目中。它的問題還是前面所說的,啟用災(zāi)備機(jī)房需要時(shí)間,而且啟用后的服務(wù),不確定能否如期工作。

          所以:要想真正的抵御城市級(jí)別的故障,越來越多的互聯(lián)網(wǎng)公司,開始實(shí)施「異地雙活」。

          11、偽異地雙活架構(gòu)

          這里,我們還是分析 2 個(gè)機(jī)房的架構(gòu)情況。

          我們不再把 A、B 機(jī)房部署在同一個(gè)城市,而是分開部署(例如 A 機(jī)房放在北京,B 機(jī)房放在上海)。

          前面我們講了同城雙活,那異地雙活是不是直接「照搬」同城雙活的模式去部署就可以了呢?

          事情沒你想的那么簡單。

          如果還是按照同城雙活的架構(gòu)來部署,那異地雙活的架構(gòu)就是這樣的:

           注意看:兩個(gè)機(jī)房的網(wǎng)絡(luò)是通過「跨城專線」連通的。

          此時(shí)兩個(gè)機(jī)房都接入流量,那上海機(jī)房的請求,可能要去讀寫北京機(jī)房的存儲(chǔ),這里存在一個(gè)很大的問題:網(wǎng)絡(luò)延遲。

          因?yàn)閮蓚€(gè)機(jī)房距離較遠(yuǎn),受到物理距離的限制。現(xiàn)在,兩地之間的網(wǎng)絡(luò)延遲就變成了「不可忽視」的因素了。

          北京到上海的距離大約 1300 公里,即使架設(shè)一條高速的「網(wǎng)絡(luò)專線」,光纖以光速傳輸,一個(gè)來回也需要近 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ī)房內(nèi)網(wǎng)絡(luò)質(zhì)量的,專線網(wǎng)絡(luò)經(jīng)常會(huì)發(fā)生延遲、丟包、甚至中斷的情況。總之,不能過度信任和依賴「跨城專線」。

          你可能會(huì)問,這點(diǎn)延遲對業(yè)務(wù)影響很大嗎?影響非常大!

          試想:一個(gè)客戶端請求打到上海機(jī)房,上海機(jī)房要去讀寫北京機(jī)房的存儲(chǔ),一次跨機(jī)房訪問延遲就達(dá)到了 30ms,這大致是機(jī)房內(nèi)網(wǎng)網(wǎng)絡(luò)(0.5 ms)訪問速度的 60 倍(30ms / 0.5ms),一次請求慢 60 倍,來回往返就要慢 100 倍以上。

          而我們在 App 打開一個(gè)頁面,可能會(huì)訪問后端幾十個(gè) API,每次都跨機(jī)房訪問,整個(gè)頁面的響應(yīng)延遲有可能就達(dá)到了秒級(jí),這個(gè)性能簡直慘不忍睹,難以接受。

          看到了么:雖然我們只是簡單的把機(jī)房部署在了「異地」,但「同城雙活」的架構(gòu)模型,在這里就不適用了,還是按照這種方式部署,這是「偽異地雙活」!

          那如何做到真正的異地雙活呢?

          12、真正的異地雙活架構(gòu)

          既然「跨機(jī)房」調(diào)用延遲是不容忽視的因素,那我們只能盡量避免跨機(jī)房「調(diào)用」,規(guī)避這個(gè)延遲問題。

          也就是說:上海機(jī)房的應(yīng)用,不能再「跨機(jī)房」去讀寫北京機(jī)房的存儲(chǔ),只允許讀寫上海本地的存儲(chǔ),實(shí)現(xiàn)「就近訪問」,這樣才能避免延遲問題。

          還是之前提到的問題:上海機(jī)房存儲(chǔ)都是從庫,不允許寫入啊,除非我們只允許上海機(jī)房接入「讀流量」,不接收「寫流量」,否則無法滿足不再跨機(jī)房的要求。

          很顯然:只讓上海機(jī)房接收讀流量的方案不現(xiàn)實(shí),因?yàn)楹苌儆许?xiàng)目是只有讀流量,沒有寫流量的。所以這種方案還是不行,這怎么辦?

          此時(shí),你就必須在「存儲(chǔ)層」做改造了。

          要想上海機(jī)房讀寫本機(jī)房的存儲(chǔ),那上海機(jī)房的存儲(chǔ)不能再是北京機(jī)房的從庫,而是也要變?yōu)椤钢鲙臁埂?/p>

          你沒看錯(cuò):兩個(gè)機(jī)房的存儲(chǔ)必須都是「主庫」,而且兩個(gè)機(jī)房的數(shù)據(jù)還要「互相同步」數(shù)據(jù),即客戶端無論寫哪一個(gè)機(jī)房,都能把這條數(shù)據(jù)同步到另一個(gè)機(jī)房。

          因?yàn)橹挥袃蓚€(gè)機(jī)房都擁有「全量數(shù)據(jù)」,才能支持任意切換機(jī)房,持續(xù)提供服務(wù)。

          怎么實(shí)現(xiàn)這種「雙主」架構(gòu)呢?它們之間如何互相同步數(shù)據(jù)?

          如果對 MySQL 有所了解,你應(yīng)該知道,MySQL 本身就提供了雙主架構(gòu),它支持雙向復(fù)制數(shù)據(jù),但平時(shí)用的并不多。而且 Redis、MongoDB 等數(shù)據(jù)庫并沒有提供這個(gè)功能。所以,你必須開發(fā)對應(yīng)的「數(shù)據(jù)同步中間件」來實(shí)現(xiàn)雙向同步的功能。

          此外:除了數(shù)據(jù)庫這種有狀態(tài)的軟件之外,你的項(xiàng)目通常還會(huì)使用到消息隊(duì)列(例如 RabbitMQ、Kafka),這些也是有狀態(tài)的服務(wù),所以它們也需要開發(fā)雙向同步的中間件,支持任意機(jī)房寫入數(shù)據(jù),同步至另一個(gè)機(jī)房。

          看到了么:這一下子復(fù)雜度就上來了,單單針對每個(gè)數(shù)據(jù)庫、隊(duì)列開發(fā)同步中間件,就需要投入很大精力了。

          業(yè)界也開源出了很多數(shù)據(jù)同步中間件,例如:阿里的 CanalRedisShakeMongoShake,可分別在兩個(gè)機(jī)房同步 MySQL、Redis、MongoDB 數(shù)據(jù)。

          很多有能力的公司,也會(huì)采用自研同步中間件的方式來做(例如餓了么、攜程、美團(tuán)都開發(fā)了自己的同步中間件)。

          現(xiàn)在,整個(gè)架構(gòu)就變成了這樣:

          注意看:兩個(gè)機(jī)房的存儲(chǔ)層都互相同步數(shù)據(jù)的。

          有了數(shù)據(jù)同步中間件,就可以達(dá)到這樣的效果:

          • 1)北京機(jī)房寫入 X = 1;
          • 2)上海機(jī)房寫入 Y = 2;
          • 3)數(shù)據(jù)通過中間件雙向同步;
          • 4)北京、上海機(jī)房都有 X = 1、Y = 2 的數(shù)據(jù)。

          這里:我們用中間件雙向同步數(shù)據(jù),就不用再擔(dān)心專線問題(一旦專線出問題,我們的中間件可以自動(dòng)重試,直到成功,達(dá)到數(shù)據(jù)最終一致)。

          但這里還會(huì)遇到一個(gè)問題:兩個(gè)機(jī)房都可以寫,操作的不是同一條數(shù)據(jù)那還好,如果修改的是同一條的數(shù)據(jù),發(fā)生沖突怎么辦?

          • 1)用戶短時(shí)間內(nèi)發(fā)了 2 個(gè)修改請求,都是修改同一條數(shù)據(jù);
          • 2)一個(gè)請求落在北京機(jī)房,修改 X = 1(還未同步到上海機(jī)房);
          • 3)另一個(gè)請求落在上海機(jī)房,修改 X = 2(還未同步到北京機(jī)房);
          • 4)兩個(gè)機(jī)房以哪個(gè)為準(zhǔn)?

          也就是說:在很短的時(shí)間內(nèi),同一個(gè)用戶修改同一條數(shù)據(jù),兩個(gè)機(jī)房無法確認(rèn)誰先誰后,數(shù)據(jù)發(fā)生「沖突」。

          這是一個(gè)很嚴(yán)重的問題:系統(tǒng)發(fā)生故障并不可怕,可怕的是數(shù)據(jù)發(fā)生「錯(cuò)誤」,因?yàn)樾拚龜?shù)據(jù)的成本太高了。我們一定要避免這種情況的發(fā)生。

          解決這個(gè)問題,有 2 個(gè)方案。

          第一個(gè)方案:數(shù)據(jù)同步中間件要有自動(dòng)「合并」數(shù)據(jù)、解決「沖突」的能力。

          這個(gè)方案實(shí)現(xiàn)起來比較復(fù)雜,要想合并數(shù)據(jù),就必須要區(qū)分出「先后」順序。我們很容易想到的方案,就是以「時(shí)間」為標(biāo)尺,以「后到達(dá)」的請求為準(zhǔn)。

          但這種方案需要兩個(gè)機(jī)房的「時(shí)鐘」嚴(yán)格保持一致才行,否則很容易出現(xiàn)問題。

          例如:

          • 1)第 1 個(gè)請求落到北京機(jī)房,北京機(jī)房時(shí)鐘是 10:01,修改 X = 1;
          • 2)第 2 個(gè)請求落到上海機(jī)房,上海機(jī)房時(shí)鐘是 10:00,修改 X = 2。

          因?yàn)楸本C(jī)房的時(shí)間「更晚」,那最終結(jié)果就會(huì)是 X = 1。但這里其實(shí)應(yīng)該以第 2 個(gè)請求為準(zhǔn),X = 2 才對。

          可見,完全「依賴」時(shí)鐘的沖突解決方案,不太嚴(yán)謹(jǐn)。

          所以,通常會(huì)采用第二種方案,從「源頭」就避免數(shù)據(jù)沖突的發(fā)生。

          我們繼續(xù)往下學(xué)習(xí)。。。

          13、更好的異地雙活架構(gòu)及實(shí)施思路

          接上節(jié):既然自動(dòng)合并數(shù)據(jù)的方案實(shí)現(xiàn)成本高,那我們就要想,能否從源頭就「避免」數(shù)據(jù)沖突呢?

          這個(gè)思路非常棒!

          13.1 基本思路

          從源頭避免數(shù)據(jù)沖突的思路是:在最上層接入流量時(shí),就不要讓沖突的情況發(fā)生。

          具體來講就是:要在最上層就把用戶「區(qū)分」開,部分用戶請求固定打到北京機(jī)房,其它用戶請求固定打到上海 機(jī)房,進(jìn)入某個(gè)機(jī)房的用戶請求,之后的所有業(yè)務(wù)操作,都在這一個(gè)機(jī)房內(nèi)完成,從根源上避免「跨機(jī)房」。

          所以這時(shí):你需要在接入層之上,再部署一個(gè)「路由層」(通常部署在云服務(wù)器上),自己可以配置路由規(guī)則,把用戶「分流」到不同的機(jī)房內(nèi)。

          但這個(gè)路由規(guī)則,具體怎么定呢?

          有很多種實(shí)現(xiàn)方式,最常見的我總結(jié)了 3 類:

          • 1)按業(yè)務(wù)類型分片;
          • 2)直接哈希分片;
          • 3)按地理位置分片。

          13.2 按業(yè)務(wù)類型分片

          這種方案是指,按應(yīng)用的「業(yè)務(wù)類型」來劃分。

          舉例:假設(shè)我們一共有 4 個(gè)應(yīng)用,北京和上海機(jī)房都部署這些應(yīng)用。但應(yīng)用 1、2 只在北京機(jī)房接入流量,在上海機(jī)房只是熱備。應(yīng)用 3、4 只在上海機(jī)房接入流量,在北京機(jī)房是熱備。

          這樣一來:應(yīng)用 1、2 的所有業(yè)務(wù)請求,只讀寫北京機(jī)房存儲(chǔ),應(yīng)用 3、4 的所有請求,只會(huì)讀寫上海機(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ī)房接入流量。

          13.3 直接哈希分片

          這種方案就是:最上層的路由層,會(huì)根據(jù)用戶 ID 計(jì)算「哈希」取模,然后從路由表中找到對應(yīng)的機(jī)房,之后把請求轉(zhuǎn)發(fā)到指定機(jī)房內(nèi)。

          舉例:一共 200 個(gè)用戶,根據(jù)用戶 ID 計(jì)算哈希值,然后根據(jù)路由規(guī)則,把用戶 1 - 100 路由到北京機(jī)房,101 - 200 用戶路由到上海機(jī)房,這樣,就避免了同一個(gè)用戶修改同一條數(shù)據(jù)的情況發(fā)生。

          13.4 按地理位置分片

          這種方案,非常適合與地理位置密切相關(guān)的業(yè)務(wù),例如打車、外賣服務(wù)就非常適合這種方案。

          拿外賣服務(wù)舉例:你要點(diǎn)外賣肯定是「就近」點(diǎn)餐,整個(gè)業(yè)務(wù)范圍相關(guān)的有商家、用戶、騎手,它們都是在相同的地理位置內(nèi)的。

          針對這種特征:就可以在最上層,按用戶的「地理位置」來做分片,分散到不同的機(jī)房。

          舉例:北京、河北地區(qū)的用戶點(diǎn)餐,請求只會(huì)打到北京機(jī)房,而上海、浙江地區(qū)的用戶,請求則只會(huì)打到上海機(jī)房。這樣的分片規(guī)則,也能避免數(shù)據(jù)沖突。

          提醒:這 3 種常見的分片規(guī)則,第一次看不太好理解,建議配合圖多理解幾遍。搞懂這 3 個(gè)分片規(guī)則,你才能真正明白怎么做異地多活。

          總之:分片的核心思路在于,讓同一個(gè)用戶的相關(guān)請求,只在一個(gè)機(jī)房內(nèi)完成所有業(yè)務(wù)「閉環(huán)」,不再出現(xiàn)「跨機(jī)房」訪問。

          阿里在實(shí)施這種方案時(shí),給它起了個(gè)名字,叫做「單元化」。

          當(dāng)然,最上層的路由層把用戶分片后,理論來說同一個(gè)用戶只會(huì)落在同一個(gè)機(jī)房內(nèi),但不排除程序 Bug 導(dǎo)致用戶會(huì)在兩個(gè)機(jī)房「漂移」。

          安全起見,每個(gè)機(jī)房在寫存儲(chǔ)時(shí),還需要有一套機(jī)制,能夠檢測「數(shù)據(jù)歸屬」,應(yīng)用層操作存儲(chǔ)時(shí),需要通過中間件來做「兜底」,避免不該寫本機(jī)房的情況發(fā)生。(篇幅限制,這里不展開講,理解思路即可)

          現(xiàn)在:兩個(gè)機(jī)房就可以都接收「讀寫」流量(做好分片的請求),底層存儲(chǔ)保持「雙向」同步,兩個(gè)機(jī)房都擁有全量數(shù)據(jù)。當(dāng)任意機(jī)房故障時(shí),另一個(gè)機(jī)房就可以「接管」全部流量,實(shí)現(xiàn)快速切換,簡直不要太爽。

          不僅如此:因?yàn)闄C(jī)房部署在異地,我們還可以更細(xì)化地「優(yōu)化」路由規(guī)則,讓用戶訪問就近的機(jī)房,這樣整個(gè)系統(tǒng)的性能也會(huì)大大提升。

          這里還有一種情況,是無法做數(shù)據(jù)分片的:全局?jǐn)?shù)據(jù),例如系統(tǒng)配置、商品庫存這類需要強(qiáng)一致的數(shù)據(jù),這類服務(wù)依舊只能采用寫主機(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)兜底策略,不僅需要開發(fā)強(qiáng)大的中間件,同時(shí)還要業(yè)務(wù)配合改造(業(yè)務(wù)邊界劃分、依賴拆分)等一些列工作,沒有足夠的人力物力,這套架構(gòu)很難實(shí)施。

          14、異地多活架構(gòu)

          理解了異地雙活,那「異地多活」顧名思義,就是在異地雙活的基礎(chǔ)上,部署多個(gè)機(jī)房即可。

          架構(gòu)變成了這樣:

          這些服務(wù)按照「單元化」的部署方式,可以讓每個(gè)機(jī)房部署在任意地區(qū),隨時(shí)擴(kuò)展新機(jī)房,你只需要在最上層定義好分片規(guī)則就好了。

          但這里還有一個(gè)小問題:隨著擴(kuò)展的機(jī)房越來越多,當(dāng)一個(gè)機(jī)房寫入數(shù)據(jù)后,需要同步的機(jī)房也越來越多,這個(gè)實(shí)現(xiàn)復(fù)雜度會(huì)比較高。

          所以業(yè)界又把這一架構(gòu)又做了進(jìn)一步優(yōu)化,把「網(wǎng)狀」架構(gòu)升級(jí)為「星狀」:

          這種方案必須設(shè)立一個(gè)「中心機(jī)房」,任意機(jī)房寫入數(shù)據(jù)后,都只同步到中心機(jī)房,再由中心機(jī)房同步至其它機(jī)房。

          這樣做的好處是:一個(gè)機(jī)房寫入數(shù)據(jù),只需要同步數(shù)據(jù)到中心機(jī)房即可,不需要再關(guān)心一共部署了多少個(gè)機(jī)房,實(shí)現(xiàn)復(fù)雜度大大「簡化」。

          但與此同時(shí):這個(gè)中心機(jī)房的「穩(wěn)定性」要求會(huì)比較高。不過也還好,即使中心機(jī)房發(fā)生故障,我們也可以把任意一個(gè)機(jī)房,提升為中心機(jī)房,繼續(xù)按照之前的架構(gòu)提供服務(wù)。

          至此,我們的系統(tǒng)徹底實(shí)現(xiàn)了「異地多活」!

          多活的優(yōu)勢在于:可以任意擴(kuò)展機(jī)房「就近」部署。任意機(jī)房發(fā)生故障,可以完成快速「切換」,大大提高了系統(tǒng)的可用性。

          同時(shí):我們也再也不用擔(dān)心系統(tǒng)規(guī)模的增長,因?yàn)檫@套架構(gòu)具有極強(qiáng)的「擴(kuò)展能力」。

          怎么樣?我們從一個(gè)最簡單的應(yīng)用,一路優(yōu)化下來,到最終的架構(gòu)方案,有沒有幫你徹底理解異地多活呢?

          15、本文小結(jié)

          好了,總結(jié)一下這篇文章的重點(diǎn)。

          1)一個(gè)好的軟件架構(gòu),應(yīng)該遵循高性能、高可用、易擴(kuò)展 3 大原則,其中「高可用」在系統(tǒng)規(guī)模變得越來越大時(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)勢在于,兩個(gè)機(jī)房都可以接入「讀寫」流量,提高可用性的同時(shí),還提升了系統(tǒng)性能。雖然物理上是兩個(gè)機(jī)房,但「邏輯」上還是當(dāng)做一個(gè)機(jī)房來用。

          6)兩地三中心是在同城雙活的基礎(chǔ)上,額外部署一個(gè)異地機(jī)房做「災(zā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)對更大規(guī)模的流量的壓力,擴(kuò)展性最強(qiáng),是實(shí)現(xiàn)高可用的最終方案。

          16、寫在最后

          這篇文章我從「宏觀」層面,向你介紹了異地多活架構(gòu)的「核心」思路,整篇文章的信息量還是很大的,如果不太好理解,我建議你多讀幾遍。

          因?yàn)槠拗疲芏嗉?xì)節(jié)我并沒有展開來講。這篇文章更像是講異地多活的架構(gòu)之「道」,而真正實(shí)施的「術(shù)」,要考慮的點(diǎn)其實(shí)也非常繁多,因?yàn)樗枰_發(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ǔ)),微觀上要開發(fā)各種中間件,還要關(guān)注中間件的高性能、高可用、容錯(cuò)能力,其復(fù)雜度之高,只有親身參與過之后才知道。

          我曾經(jīng)有幸參與過存儲(chǔ)層同步中間件的設(shè)計(jì)與開發(fā),實(shí)現(xiàn)過「跨機(jī)房」同步 MySQL、Redis、MongoDB 的中間件,踩過的坑也非常多。當(dāng)然,這些中間件的設(shè)計(jì)思路也非常有意思,有時(shí)間單獨(dú)分享一下這些中間件的設(shè)計(jì)思路。

          值得提醒你的是:只有真正理解了「異地雙活」,才能徹底理解「異地多活」。

          在我看來:從同城雙活演變?yōu)楫惖仉p活的過程,是最為復(fù)雜的。最核心的東西包括:業(yè)務(wù)單元化劃分、存儲(chǔ)層數(shù)據(jù)雙向同步、最上層的分片邏輯,這些是實(shí)現(xiàn)異地多活的重中之重。

          希望我分享的架構(gòu)經(jīng)驗(yàn),對你有所啟發(fā)。

          附錄:更多IM技術(shù)干貨

          [1] IM架構(gòu)設(shè)計(jì)的文章:

          淺談IM系統(tǒng)的架構(gòu)設(shè)計(jì)

          簡述移動(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)方案

          一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計(jì)實(shí)踐

          從游擊隊(duì)到正規(guī)軍(一):馬蜂窩旅游網(wǎng)的IM系統(tǒng)架構(gòu)演進(jìn)之路

          瓜子IM智能客服系統(tǒng)的數(shù)據(jù)架構(gòu)設(shè)計(jì)(整理自現(xiàn)場演講,有配套PPT)

          阿里釘釘技術(shù)分享:企業(yè)級(jí)IM王者——釘釘在后端架構(gòu)上的過人之處

          一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(上篇):整體架構(gòu)、服務(wù)拆分等

          一套億級(jí)用戶的IM架構(gòu)技術(shù)干貨(下篇):可靠性、有序性、弱網(wǎng)優(yōu)化等

          從新手到專家:如何設(shè)計(jì)一套億級(jí)消息量的分布式IM系統(tǒng)

          企業(yè)微信的IM架構(gòu)設(shè)計(jì)揭秘:消息模型、萬人群、已讀回執(zhí)、消息撤回等

          融云技術(shù)分享:全面揭秘億級(jí)IM消息的可靠投遞機(jī)制

          IM開發(fā)技術(shù)學(xué)習(xí):揭秘微信朋友圈這種信息推流背后的系統(tǒng)設(shè)計(jì)

          阿里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í)踐

          [2] 其它IM技術(shù)綜合性文章:

          新手入門一篇就夠:從零開發(fā)移動(dòng)端IM

          移動(dòng)端IM開發(fā)者必讀(一):通俗易懂,理解移動(dòng)網(wǎng)絡(luò)的“弱”和“慢”

          移動(dòng)端IM開發(fā)者必讀(二):史上最全移動(dòng)弱網(wǎng)絡(luò)優(yōu)化方法總結(jié)

          從客戶端的角度來談?wù)勔苿?dòng)端IM的消息可靠性和送達(dá)機(jī)制

          現(xiàn)代移動(dòng)端網(wǎng)絡(luò)短連接的優(yōu)化手段總結(jié):請求速度、弱網(wǎng)適應(yīng)、安全保障

          移動(dòng)端IM中大規(guī)模群消息的推送如何保證效率、實(shí)時(shí)性?

          移動(dòng)端IM開發(fā)需要面對的技術(shù)問題

          IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(一):保證在線實(shí)時(shí)消息的可靠投遞

          IM消息送達(dá)保證機(jī)制實(shí)現(xiàn)(二):保證離線消息的可靠投遞

          如何保證IM實(shí)時(shí)消息的“時(shí)序性”與“一致性”?

          一個(gè)低成本確保IM消息時(shí)序的方法探討

          IM單聊和群聊中的在線狀態(tài)同步應(yīng)該用“推”還是“拉”?

          IM群聊消息如此復(fù)雜,如何保證不丟不重?

          談?wù)勔苿?dòng)端 IM 開發(fā)中登錄請求的優(yōu)化

          移動(dòng)端IM登錄時(shí)拉取數(shù)據(jù)如何作到省流量?

          淺談移動(dòng)端IM的多點(diǎn)登錄和消息漫游原理

          完全自已開發(fā)的IM該如何設(shè)計(jì)“失敗重試”機(jī)制?

          自已開發(fā)IM有那么難嗎?手把手教你自擼一個(gè)Andriod版簡易IM (有源碼)

          適合新手:從零開發(fā)一個(gè)IM服務(wù)端(基于Netty,有完整源碼)

          拿起鍵盤就是干:跟我一起徒手開發(fā)一套分布式IM系統(tǒng)

          IM消息ID技術(shù)專題(一):微信的海量IM聊天消息序列號(hào)生成實(shí)踐(算法原理篇)

          IM開發(fā)寶典:史上最全,微信各種功能參數(shù)和邏輯規(guī)則資料匯總

          IM開發(fā)干貨分享:我是如何解決大量離線消息導(dǎo)致客戶端卡頓的

          零基礎(chǔ)IM開發(fā)入門(一):什么是IM系統(tǒng)?

          零基礎(chǔ)IM開發(fā)入門(二):什么是IM系統(tǒng)的實(shí)時(shí)性?

          零基礎(chǔ)IM開發(fā)入門(三):什么是IM系統(tǒng)的可靠性?

          零基礎(chǔ)IM開發(fā)入門(四):什么是IM系統(tǒng)的消息時(shí)序一致性?

          IM開發(fā)干貨分享:如何優(yōu)雅的實(shí)現(xiàn)大量離線消息的可靠投遞

          IM掃碼登錄技術(shù)專題(三):通俗易懂,IM掃碼登錄功能詳細(xì)原理一篇就夠

          IM掃碼登錄技術(shù)專題(四):你真的了解二維碼嗎?刨根問底、一文掌握!

          理解IM消息“可靠性”和“一致性”問題,以及解決方案探討

          IM開發(fā)干貨分享:萬字長文,詳解IM“消息“列表卡頓優(yōu)化實(shí)踐

          IM開發(fā)干貨分享:網(wǎng)易云信IM客戶端的聊天消息全文檢索技術(shù)實(shí)踐

          IM開發(fā)技術(shù)學(xué)習(xí):揭秘微信朋友圈這種信息推流背后的系統(tǒng)設(shè)計(jì)

          本文已同步發(fā)布于“即時(shí)通訊技術(shù)圈”公眾號(hào)。

          同步發(fā)布鏈接是:http://www.52im.net/thread-3742-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)載請注明出處(也可前往 我的52im.net 找到我)。


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 余姚市| 兰坪| 恩施市| 五河县| 清远市| 蓬溪县| 通山县| 阜城县| 敦化市| 黄梅县| 临沧市| 郯城县| 宁夏| 延津县| 白河县| 华阴市| 通渭县| 红原县| 南丹县| 利川市| 甘南县| 吴桥县| 达州市| 桃江县| 蛟河市| 扎鲁特旗| 基隆市| 南江县| 南皮县| 宜宾市| 潞城市| 康定县| 古交市| 定远县| 城固县| 沙河市| 巴彦淖尔市| 二连浩特市| 壤塘县| 皮山县| 行唐县|