軟件系統(tǒng)的皇冠明珠--異地多活
瀏覽量: 次 發(fā)布日期:2023-09-07 23:26:09
軟件系統(tǒng)的皇冠明珠--異地多活
近期,珠海舉辦的“第十四屆中國航展”,作為一名業(yè)余軍迷,看到祖國航空航天領(lǐng)域不論是民用還是軍用,都出現(xiàn)世界一流產(chǎn)品而感到驕傲和自豪。航空發(fā)動機被稱為“工業(yè)之花”,也被譽為“工業(yè)皇冠上的明珠”。軟件系統(tǒng)領(lǐng)域的“皇冠明珠”則是異地多活,那什么是異地多活呢?它解決了什么問題,又帶來哪些挑戰(zhàn),工程師們又是如何解決挑戰(zhàn)呢?
軟件系統(tǒng)的異地多活其實就是字面意思,讓軟件系統(tǒng)在不同的“地方”活著,他是為了提高系統(tǒng)的可用性。任何一個軟件產(chǎn)品,不管宣傳他有多么好的體驗(經(jīng)常不可用也不可能有好的體驗)、多么優(yōu)秀的功能、多么牛逼的性能,如果沒有比較高的可用性那都是0,可用性就是那個“1”,而異地多活是為了提高可用性。
另外,異地多活的理論依據(jù)是CAP中的AP方案,對一致性做了取舍。
CAP:一個分布式系統(tǒng)最多只能同時滿足一致性(Consistency)、可用性(Availability)和分區(qū)容錯性(Partition tolerance)這三項中的兩項。
在介紹系統(tǒng)可用性之前,我們先從系統(tǒng)架構(gòu)設(shè)計原則說起。軟件系統(tǒng)發(fā)展到現(xiàn)在,他的復(fù)雜度越來越高,人們的要求也隨之變高,一個好的系統(tǒng)架構(gòu)應(yīng)該符合幾個原則:
高性能
可擴展
高可用
這三個原則,高性能的概念是最為人所知的,不過他和可擴展性不是本文討論的范圍。推薦下表的IT系統(tǒng)性能量化指標(biāo):
數(shù)據(jù)來源:Jeff Dean
高可用(High Availability,簡稱HA)就是指系統(tǒng)可用性,通過異地多活去實現(xiàn)。在介紹可用性之前,先介紹兩個概念:
MTBF(Mean Time Between Failure):上次故障到這次故障的時間長度,值越大,說明系統(tǒng)穩(wěn)定性越高。
MTTR(Mean Time To Repair):發(fā)生故障到系統(tǒng)恢復(fù)正常的時間長度,值越小,說明系統(tǒng)影響越小。
可用性和兩者關(guān)系,可以用下面公式表示:
可用性(Availability)= MTBF/( MTBF + MTTR )* 100%
這個公式得到的結(jié)果我們稱之為可用性,通常情況下,我們使用幾個九來表示系統(tǒng)的可用性。一般的互聯(lián)網(wǎng)應(yīng)用業(yè)務(wù)系統(tǒng)至少要做到4個9以上,筆者曾工作過的某金融企業(yè)核心系統(tǒng)是要求到達5個9的可用性。
從可用性公式和上述表格中,只有故障間隔越長和恢復(fù)時間越短,系統(tǒng)可用性才會越高。當(dāng)應(yīng)用系統(tǒng)的規(guī)模足夠復(fù)雜時,故障是一定會發(fā)生的,工程師的工作是盡量的增大 MTBF 和減小 MTTR 。軟件系統(tǒng)千奇百怪的故障可以總結(jié)為三個方面:
1、軟件問題:操作系統(tǒng)故障,軟件版本迭代、發(fā)布帶來的代碼Bug
2、硬件問題:CPU、內(nèi)存、硬盤、網(wǎng)卡、路由器、交換機
3、外部問題:機房機柜的風(fēng)、火、水、電以及城市網(wǎng)絡(luò)
我們無法保證每個服務(wù)器上每個硬件不損壞,也無法保障服務(wù)器運行的環(huán)境永遠可靠不出故障(城市的建設(shè)可能會挖斷光纜,機房可能會發(fā)生火災(zāi),甚至城市可能會發(fā)生地震、戰(zhàn)爭)。故障并不可怕,只需要在最短時間恢復(fù)甚至讓用戶沒有感知。為了提高可用性,無數(shù)工程師前輩為之探索,本文將介紹從最簡單的單機架構(gòu)到異地多活的演變之路。
題外話:
軟件應(yīng)用系統(tǒng)的后端服務(wù),按照狀態(tài)可以分為兩大類:有狀態(tài)的存儲(數(shù)據(jù)庫)和無狀態(tài)應(yīng)用層。對于無狀態(tài)的應(yīng)用來說,提高可用性相對比較簡單。常見的方法,有通過硬件(F5)、軟件(SLB、DNS)來實現(xiàn)負載均衡(Load Balancer)。本文說的可用性,專指對有狀態(tài)的數(shù)據(jù)存儲層,這也是在軟件工程中相對比較難的部分。另外,有些系統(tǒng)在應(yīng)用層的內(nèi)存也存在部分有狀態(tài)的數(shù)據(jù),本文不涉及討論這一部分有狀態(tài)數(shù)據(jù)的異地多活。
早期互聯(lián)網(wǎng)公司用戶少、規(guī)模小,相應(yīng)的應(yīng)用系統(tǒng)架構(gòu)就簡單,通常是這樣的:
它非常簡單,應(yīng)用讀寫數(shù)據(jù)庫返回結(jié)果。此時的系統(tǒng)架構(gòu)里,數(shù)據(jù)庫還是單機部署的,因此有致命的缺點,一旦系統(tǒng)出現(xiàn)故障,例如硬盤損壞、操作系統(tǒng)異常或者服務(wù)器異常,就有可能出現(xiàn)數(shù)據(jù)全部丟失問題,丟失數(shù)據(jù)對現(xiàn)代企業(yè)來說是無法承受的。
那如何避免這個問題呢?備份--有備無患,定時對數(shù)據(jù)庫進行全量備份,然后將備份數(shù)據(jù)異地存儲。這樣即使原來服務(wù)器出現(xiàn)異常,也可以利用備份文件恢復(fù)數(shù)據(jù)。這就是早期互聯(lián)網(wǎng)生產(chǎn)系統(tǒng)的架構(gòu),一個簡單的應(yīng)用和數(shù)據(jù)庫架構(gòu),再加上一個備份。
然而隨著業(yè)務(wù)的發(fā)展規(guī)模的擴大數(shù)據(jù)的增加,靠備份恢復(fù)的架構(gòu)帶來挑戰(zhàn):
1、恢復(fù)需要時間。
2、恢復(fù)的數(shù)據(jù)完整性不高。
首先只能數(shù)據(jù)恢復(fù)到備份點,其次如果備份數(shù)據(jù)很大,備份文件的拷貝和恢復(fù)也需要時間。這樣可用性公式中MTTR值就不會小,可用性就低。那如何提高可用性呢?既然“冷備”無法解決數(shù)據(jù)完整性和快速恢復(fù),那就用“熱備”——主從架構(gòu)(Master/Slave)。
早期的單機+備份架構(gòu)帶來的問題,通過主從架構(gòu)可以解決一部分。
主從架構(gòu)的方案,優(yōu)點在于:
數(shù)據(jù)完整性高:主從實時同步,有效降低數(shù)據(jù)不一致情況
抗故障能力提升:主庫有任何異常,從庫可比較快速的升為主庫,繼續(xù)提供服務(wù)
說明:
數(shù)據(jù)庫主從節(jié)點之間的同步方式會帶來較大的系統(tǒng)性能性能變化。常見的同步方式分為強同步、異步同步和半同步。強同步是指從節(jié)點寫入完成后,主節(jié)點才給應(yīng)用返回數(shù)據(jù)。半同步是指有一個從節(jié)點收到消息,主節(jié)點給應(yīng)用返回數(shù)據(jù)。異步同步等同于單機,不需要等待從節(jié)點的信息。
這個方案不錯,對比單機已顯著提高數(shù)據(jù)庫的可用性。美中不足的是該架構(gòu)的從庫(Slave)只作為備份而存在,從資源利用率看并沒有充分使用。再稍加改造,將應(yīng)用一部分的讀業(yè)務(wù)從主庫遷移到從庫上。
無狀態(tài)的應(yīng)用層也需要避免單點問題,部署相同的多個應(yīng)用,這就需要在應(yīng)用層前加上接入層(accesss)。到此,這套主從讀寫分離高可用架構(gòu),不僅提高了系統(tǒng)的可用性,還提升資源利用率和系統(tǒng)吞吐量,看上去這個架構(gòu)似乎已經(jīng)是完美 了,確實這套架構(gòu)已經(jīng)是比較主流的架構(gòu)了。
主從架構(gòu)是解決服務(wù)器層的問題。當(dāng)一個服務(wù)器出現(xiàn)問題,系統(tǒng)可以快速切換到該機房的其他服務(wù)器,從而提高了系統(tǒng)可用性。我們從最開始的單個系統(tǒng)上的故障擴大到服務(wù)器,以此類推,還有機柜、機房甚至城市也會出現(xiàn)故障,這些出現(xiàn)故障上述架構(gòu)是無法解決的。
有同學(xué)會說,至于這么夸張嗎?我們先看幾個2022年的新聞:
1、長沙電信大樓起火,海量數(shù)據(jù)如何保全?
2、韓版騰訊的一場大火,讓韓國淪陷了整整4天
3、UPS 爆炸:菲律賓一數(shù)據(jù)中心失火
再看更久的舊聞:
1、2015 年 5 月,支付寶支付失靈:電纜惹的禍?
2、2016年 9 月,阿里云北京機房內(nèi)網(wǎng)故障,大面積服務(wù)異常
3、年終盤點 | 2020云巨頭們的宕機事件
4、2021 年 7 月,B站回應(yīng)深夜“崩了”:部分服務(wù)器機房發(fā)生故障,對不起!
5、2021 年 7 月,河南暴雨致使機房停電,多家網(wǎng)站陷入癱瘓
可見,機房、市政也不是永遠可靠的,雖然出現(xiàn)的問題概率很小,一旦發(fā)生,影響可能是致命的。機房出現(xiàn)的概率也太小了,工作這么多年了還沒有聽說身邊發(fā)生過這種事,有必要考慮這種事情嗎?如果是一線程序員這么看問題可以理解,如果一家公司的CEO、CIO、架構(gòu)師們也是這么想的,那要么是公司業(yè)務(wù)剛起步,否則筆者建議趁早換公司。
軟件系統(tǒng)在不同階段,他的側(cè)重點是不一樣的。互聯(lián)網(wǎng)蓬勃發(fā)展時代,業(yè)務(wù)剛開始時,用戶規(guī)模和增長速度是最關(guān)鍵指標(biāo)。等有一定用戶規(guī)模,性能就變得尤其重要。而當(dāng)用戶規(guī)模更大時,可用性就變得不能舉足輕重了。大家可以想象下,像微信、支付寶這種國民現(xiàn)象級的產(chǎn)品,如果突然長時間無法提供服務(wù)將會怎樣
因此,對于有些系統(tǒng)來說再小概率的風(fēng)險,也是不能忽視的,跨機房的高可用架構(gòu)就應(yīng)運而生。同城高可用是從災(zāi)備演化的,將存儲層的數(shù)據(jù)每天離線備份到同城的機房。這雖然解決了核心機房出現(xiàn)重大故障,數(shù)據(jù)還能找回來問題。但這種架構(gòu)和單機機一樣,數(shù)據(jù)恢復(fù)的實效性和完整性是比較差的,可用性并沒有很大的提升。
借鑒在單機房中“主從”架構(gòu)的思路,我們比較容易得到比較初級的同城災(zāi)備的架構(gòu),在機房A部署一套完整的系統(tǒng),在機房B部署一套數(shù)據(jù)庫系統(tǒng),將機房A的數(shù)據(jù)單向同步到機房B的數(shù)據(jù)庫中。實現(xiàn)數(shù)據(jù)實時保存在同一個城市的不同機房上,這樣在數(shù)據(jù)安全性有了很大的提升。但是系統(tǒng)的可用性,不是指數(shù)據(jù)存在而是在指系統(tǒng)可用,顯然這個架構(gòu)并不符合系統(tǒng)可用。
我們可以想象下,當(dāng)機房A出現(xiàn)問題時,最理想狀態(tài)要怎樣才能把這個系統(tǒng)重新啟動呢?
1、在機房B部署應(yīng)用,并成功啟動。
2、在機房B部署接入層,配置負載均衡。
3、斷開“專線單向同步”,將機房B數(shù)據(jù)庫升級為Master。
4、域名指向B機房的接入層,接入流量,業(yè)務(wù)恢復(fù)
在最理想狀態(tài)下,當(dāng)機房A出現(xiàn)問題時,機房B需要做上述的事情,在做完這些事情之前,整個系統(tǒng)是不可用的,所以這個架構(gòu)對于系統(tǒng)可用性并不是很高。因此,想要在機房級提高可用性,最好是機房B本身就有應(yīng)用層和接入層的環(huán)境,真正實現(xiàn)“若有戰(zhàn)、召必回、戰(zhàn)必勝”。我們就需要再次改進架構(gòu)圖。
到這里,就算整個機房A宕機,我們只需要做 這2 件事即可:
1、 斷開“專線單向同步”(如果需要),將機房B數(shù)據(jù)庫升級為Master
2、域名指向機房B接入層,接入流量,業(yè)務(wù)恢復(fù)
這樣一來,系統(tǒng)恢復(fù)速度快了很多,也提高了系統(tǒng)可用性。機房B幾乎復(fù)制機房A的所有模塊,從最上層的接入層,到中間的業(yè)務(wù)應(yīng)用層,到最下層的存儲。兩個機房最大區(qū)別是,機房A的數(shù)據(jù)是由業(yè)務(wù)實際產(chǎn)生的,而機房B的數(shù)據(jù)則是由A同步過來的。
到這里有同學(xué)會問,平時機房B不真正干活,關(guān)鍵時刻能起作用?通過筆者過往經(jīng)驗來看,大概率是不能起作用。畢竟是驢是馬要拉出來溜溜才知道,所以我們的架構(gòu)還要再演進。另外,這套架構(gòu)在資源利用率上也不是最佳選擇,所以我們很自然的想到,如果機房B平時也能干活就好了。
為了讓機房B平時正兒八經(jīng)的干活,時刻保持著戰(zhàn)斗狀態(tài)。于是我們的架構(gòu)演進如下:
因為機房B的數(shù)據(jù)只能是從機房A單向同步過來,所以機房B只能接受讀的任務(wù)。同城的機房,一般空間距離是幾十公里,所以他的跨機房數(shù)據(jù)交流還是可以接受的。這樣機房B就有了一個系統(tǒng)的讀/寫完全的實戰(zhàn)能力。到此,這個系統(tǒng)理論上應(yīng)該足夠強大了。
正如前面我們看到的新聞,一個城市有可能發(fā)生自燃災(zāi)難或者是戰(zhàn)爭,所以機房在一個城市并不是終極目標(biāo),同城的“異地”還不夠“異”,于是跨城市的異地多活架構(gòu)應(yīng)運而生。
我們還是以機房A和B舉例,本來是都在一個城市,那當(dāng)一個城市出現(xiàn)災(zāi)難時(比如去年鄭州水災(zāi)),顯然同城兩機房架構(gòu)。所以需要分開城市部署,例如把機房A放在杭州,機房B放在北京。那不同城市的異地雙活和同城是不是照貓畫虎,答案是否定的。
我們再看一遍同城雙活的架構(gòu)圖,他們是有跨機房的數(shù)據(jù)交互,而當(dāng)兩個機房物理位置超過1000km時,即使以光速傳輸,一個來回也需要近 10ms 左右的延遲。實際上,考慮到跨城市的網(wǎng)絡(luò)需要經(jīng)歷更多路由器、交換機等網(wǎng)絡(luò)設(shè)備,基本上在幾十甚至上百毫秒的延遲。
或許有同學(xué)會問,這點延遲對業(yè)務(wù)影響很大嗎?答案是:很大。我們想象下這樣一個場景,某用戶的請求發(fā)到杭州機房,杭州機房要去讀寫北京機房的存儲,一次跨機房網(wǎng)絡(luò)訪問延遲就達到了 50ms左右,這大致是機房內(nèi)網(wǎng)網(wǎng)絡(luò)(0.5 ms)訪問速度的 100 倍,這樣一次請求慢 100 倍,而通常用戶在 App 上的一個操作可能會訪問后端十幾個網(wǎng)絡(luò)請求,每次都跨機房訪問,這個性能怕是用戶要卸載App了。
因此,如果我們只是簡單的把機房部署在異地,這種異地多活是不可用的。那如何做到真正的異地雙活呢?
異地雙活中,跨機房的數(shù)據(jù)交互是不可用的,我們就盡量避免跨機房的訪問,讓本機房的服務(wù)只訪問本機房的資源。但是按照主從架構(gòu),機房B是從庫,不能有業(yè)務(wù)直接寫入,否則系統(tǒng)數(shù)據(jù)就會紊亂。所以機房B只能有讀訪問的架構(gòu)方案是不現(xiàn)實,因為很少有系統(tǒng)只有讀沒有寫。所以必須在存儲層改造了。于是我們系統(tǒng)的架構(gòu)變成這樣:
兩個機房的存儲都是主庫,而且兩個機房的數(shù)據(jù)雙相同步數(shù)據(jù),用戶與任意機房的請求數(shù)據(jù)都能同步到另一個機房,兩個機房都擁有全量數(shù)據(jù),就能支持應(yīng)用任意切換機房。
但是這里會遇到大量的問題,不僅是數(shù)據(jù)庫的數(shù)據(jù)(MySQL、MongoDB等)雙向同步的需求,還有MQ、Kafka、ZK、Redis等等組件,所以通常需要中間件去完成這些工作。這樣就不用再擔(dān)心專線問題,因為即使專線偶爾出問題,通過中間件最終實現(xiàn)數(shù)據(jù)一致。
到了這一步,軟件系統(tǒng)的可用性可以認為完美了嗎?答案:還沒有。。。因為兩個機房都可以完全獨立的完成全部業(yè)務(wù),假設(shè)某個用戶幾乎同時發(fā)起兩個請求并且是操作同一行數(shù)據(jù),就有概率發(fā)生沖突。我們可以想象下這樣的場景:
某銀行在多個平臺上提供借錢服務(wù)器的通道,用戶小王幾乎同時在某音和某手上發(fā)起借錢,這兩條請求最終都會請求到銀行兩個機房。
1、小王兩個請求都是修改在某銀行余額信息。
2、其中某音的請求是借款1000元,將小王在該銀行的余額更新為1000。而此時未同步到另一個機房數(shù)據(jù)庫。
3、某手的的請求是借款2000元,將小王在該銀行的余額更新為2000。此時也未同步到另一個機房數(shù)據(jù)庫。
4、中間件該怎么去同步到對方數(shù)據(jù)庫?
這就是同一個用戶在短時間內(nèi)有2個請求并且是分給兩個機房去修改同一條數(shù)據(jù)的場景,這種場景下就有可能會出現(xiàn)數(shù)據(jù)錯誤,系統(tǒng)發(fā)生故障已經(jīng)很可怕,但更可怕的用戶數(shù)據(jù)錯誤。
那這個問題怎么解決呢?目前業(yè)界常見的做法是在增加路由層,在路由層配置路由規(guī)則,將符合規(guī)則的用戶分配到相應(yīng)的機房。這也有多種實現(xiàn)方式,總結(jié)了常見的兩大類方法:
按用戶GIS地理路由
按用戶ID路由
地理GIS
在一些互聯(lián)網(wǎng)業(yè)務(wù)和地理GIS信息關(guān)系密切,比如外賣、打車等業(yè)務(wù)。因為當(dāng)用戶在這些業(yè)務(wù)場景時,不可能在較短時間內(nèi)同時出現(xiàn)在杭州和北京。這樣就可以路由層制定規(guī)則,比如把杭州的用戶請求就發(fā)到杭州機房,北京的用戶請求發(fā)到北京的機房。這樣的路由分配規(guī)則,就能解決數(shù)據(jù)沖突的問題。
用戶ID
另一種是根據(jù)用戶ID路由。當(dāng)路由層接收到用戶請求時,將用戶ID通過一定的算法計算取模后,分配到對應(yīng)的機房。這樣就能保證同一個用戶發(fā)起的請求一定在一個機房內(nèi)。
總之,路由層的是為了解決在短時間內(nèi),具有相同規(guī)則屬性的數(shù)據(jù)是在一個機房內(nèi)完成所有業(yè)務(wù),兩個機房同時修改一行數(shù)據(jù)的情況。后來有公司把這個模型架構(gòu)叫做單元化。到此,真正機房級的FailOver做到了,不同城市的不同機房可以完成所有業(yè)務(wù),底層通過中間件做好數(shù)據(jù)雙向同步,當(dāng)一個城市的機房出現(xiàn)問題,另一個城市的機房可以頂上。
到異地雙活的架構(gòu)是筆者親身參與過的項目,業(yè)內(nèi)還有異地多活、全球機房等架構(gòu)模型,這些筆者沒有經(jīng)驗可談了。這篇小文不是實戰(zhàn),也不是操作手冊,而是在架構(gòu)層面介紹異地多活的一些思路,算是工作10余年的個人總結(jié)。
其實到了同城雙活的系統(tǒng)架構(gòu)已經(jīng)極其復(fù)雜,需要一個專業(yè)架構(gòu)師團隊,負責(zé)數(shù)據(jù)同步、讀寫分離的業(yè)務(wù)改造、數(shù)據(jù)一致性校驗等等工作,這些不僅需要強大的中間件團隊,同時還要對業(yè)務(wù)有敏銳的觀察力,如業(yè)務(wù)邊界劃分、依賴拆分、數(shù)據(jù)血緣等等一系列工作。而從同城雙活演變到異地雙活,則又是一次數(shù)量級難度的提升。
最后,總結(jié)下這篇小文的幾個觀點:
公司業(yè)務(wù)進入穩(wěn)定期,系統(tǒng)可用性是所有指標(biāo)的前面那個1,不考慮系統(tǒng)穩(wěn)定性,談系統(tǒng)的功能、性能、擴展性都是耍流氓。
服務(wù)器總是會出問題的,機房也有可能發(fā)生地震、火災(zāi)、水災(zāi),系統(tǒng)在面對異常面前,需要在最短時間內(nèi)恢復(fù)正常,異地多活是最有效方法。
多活是通過多副本實現(xiàn)的,從最開始的離線文件備份、數(shù)據(jù)庫備份、同城備份、異地備份,都是通過副本實現(xiàn)。
同城雙活本質(zhì)還是讀寫分離的一種演變架構(gòu),但需要對跨機房業(yè)務(wù)請求的時延有充分的認識。
到了異地雙活一定不能出現(xiàn)跨機房訪問和同一條數(shù)據(jù)有可能在短時間內(nèi)被兩個機房的請求更新。
. 六安移動硬盤數(shù)據(jù)恢復(fù),專業(yè)技術(shù),守護您的數(shù)據(jù)安全
. deep sequence,揭秘高效內(nèi)容生成的秘密武器
. 深圳數(shù)據(jù)恢復(fù)公司排名,揭秘排名前三的數(shù)據(jù)恢復(fù)公司”
. 怎樣恢復(fù)刪除的硬盤數(shù)據(jù),詳解硬盤刪除數(shù)據(jù)恢復(fù)全攻略
. 硬盤數(shù)據(jù)恢復(fù)圖書,從原理到實踐的技術(shù)解析
. 數(shù)據(jù) 恢復(fù),揭秘數(shù)據(jù)丟失背后的原因與高效解決方案
. 沈河區(qū)硬盤數(shù)據(jù)恢復(fù)中心,專業(yè)服務(wù),守護您的數(shù)據(jù)安全”
. 硬盤數(shù)據(jù)恢復(fù)從哪學(xué),從原理到實踐的技術(shù)解析
. emc存儲怎么用,高效數(shù)據(jù)管理的核心策略
. 全免費的數(shù)據(jù)恢復(fù)工具,助您輕松找回丟失文件
. 病毒 移動硬盤數(shù)據(jù)恢復(fù),病毒侵襲下的移動硬盤數(shù)據(jù)恢復(fù)攻略
. 移動硬盤數(shù)據(jù)恢復(fù)正常,從誤刪到恢復(fù)的全方位指導(dǎo)
. 硬盤內(nèi)部儲存器,存儲技術(shù)的核心與未來趨勢
. 硬盤數(shù)據(jù)恢復(fù)流程圖片,從診斷到恢復(fù)的全方位指南
. deepzengo,Deepzengo的突破與創(chuàng)新
. 惠普系統(tǒng)恢復(fù)工具,一鍵還原,輕松守護您的電腦健康
. deepke源碼,揭秘知識圖譜嵌入技術(shù)的核心原理與實踐