面試官:微服務(wù)如何保證系統(tǒng)高可用?
大家好,我是秀才,今天我們來探討一個(gè)綜合性但至關(guān)重要的話題:給你一個(gè)微服務(wù)應(yīng)用,你該如何系統(tǒng)性地保證其高可用性?
在互聯(lián)網(wǎng)技術(shù)崗的面試中,高并發(fā)、高可用和大數(shù)據(jù)通常被視為衡量候選人經(jīng)驗(yàn)的三大黃金標(biāo)準(zhǔn)。但說實(shí)話,是否擁有真正的高并發(fā)和大數(shù)據(jù)項(xiàng)目經(jīng)驗(yàn),往往帶有一些“運(yùn)氣”成分。如果你不是在頭部大廠的核心業(yè)務(wù)部門,確實(shí)很難接觸到那種動(dòng)輒千萬QPS或PB級(jí)數(shù)據(jù)的真實(shí)場(chǎng)景。
然而,高可用則完全不同。它是一種普適性的工程能力。即便你維護(hù)的系統(tǒng)月活只有一萬人,你依然可以、也應(yīng)該將它打造成一個(gè)高可用的系統(tǒng)。因此,相比于另外兩者,高可用是我們可以在面試中主動(dòng)出擊、重點(diǎn)發(fā)力的方向。
圖片
當(dāng)然,我們也必須清醒地認(rèn)識(shí)到,一個(gè)淘寶量級(jí)的系統(tǒng)所談?wù)摰母呖捎茫鸵粋€(gè)簡(jiǎn)單的后臺(tái)管理系統(tǒng)的高可用,其技術(shù)復(fù)雜度和含金量是截然不同的。但話又說回來,又有多少人真的有機(jī)會(huì)去親手構(gòu)建淘寶那樣的項(xiàng)目呢?所以,如果你正苦于如何將自己看似平凡的項(xiàng)目經(jīng)歷講出亮點(diǎn)和深度,那么今天的內(nèi)容,希望能為你提供一套行之有效的思路和話術(shù)。
1. 高可用的基石:四大核心原則
在開始構(gòu)建我們的高可用體系之前,我們首先要理解其內(nèi)涵。我們通常使用SLA(Service Level Agreement,服務(wù)等級(jí)協(xié)議)來衡量可用性,并用“N個(gè)9”來表示。例如,當(dāng)我們說一個(gè)服務(wù)的可用性是“3個(gè)9”,即99.9%,意味著在一年(365天)的時(shí)間里,該服務(wù)的不可用時(shí)間不能超過8.76小時(shí)。
那么,如何才能構(gòu)建一個(gè)高可用的系統(tǒng)呢?其核心思想可以歸結(jié)為四大原則:
- 容錯(cuò)設(shè)計(jì) (Design for Failure):接受失敗是常態(tài),并為此進(jìn)行設(shè)計(jì)。
- 故障域隔離 (Blast Radius Limitation):限制故障的影響范圍,避免雪崩。
- 快速響應(yīng) (Fast Detection & Recovery):快速發(fā)現(xiàn)故障,并快速從中恢復(fù)。
- 規(guī)范化變更 (Standardized Change Process):控制由變更引入的風(fēng)險(xiǎn)。
1.1 容錯(cuò)設(shè)計(jì) - 優(yōu)雅地“湊合”
容錯(cuò)的核心理念是:無論系統(tǒng)中發(fā)生了什么意想不到的故障,你的系統(tǒng)整體上依然能夠?yàn)橛脩籼峁┓?wù),哪怕是降級(jí)后的、有損的服務(wù)。用一句通俗的話講,就是“湊合著用”。
就像一輛自行車,如果掉了一個(gè)輪子,一個(gè)優(yōu)秀的騎手會(huì)立刻把它當(dāng)成獨(dú)輪車來騎,而不是直接癱倒在地。我們的系統(tǒng)也應(yīng)該具備這種能力。
圖片
系統(tǒng)中的故障源多種多樣,可能來自你的服務(wù)本身、你依賴的其他服務(wù),也可能來自底層的硬件和軟件基礎(chǔ)設(shè)施。在面試中,最重要的是描述如何保證你自己的服務(wù)在遇到故障時(shí),不會(huì)拖垮整個(gè)系統(tǒng)。
圖片
其次,你需要考慮當(dāng)軟件基礎(chǔ)設(shè)施(如Redis、MySQL、消息隊(duì)列)出問題時(shí),你的服務(wù)該如何自處。這里主要有兩個(gè)層面的思考:
- 采用高可用方案:在公司內(nèi)部,優(yōu)先使用基礎(chǔ)設(shè)施的高可用部署方案。例如,使用Redis Cluster或云廠商提供的多可用區(qū)Redis實(shí)例,而不是單機(jī)Redis。
- 設(shè)計(jì)兜底容錯(cuò)手段:做好最壞的打算。比如,我們之前討論過,如果Redis集群整體崩潰,你的服務(wù)可以通過限流來保護(hù)后端的數(shù)據(jù)庫不被瞬間涌入的流量打垮,保證核心功能可用。
至于硬件故障和第三方供應(yīng)商故障,除了上一講提到的特殊場(chǎng)景外,在常規(guī)面試中出現(xiàn)頻率較低,我們?cè)诖瞬蛔鬟^多展開。容錯(cuò)設(shè)計(jì)的核心在于接受不完美,但無論你怎么容錯(cuò),故障終究還是會(huì)發(fā)生。當(dāng)它真的發(fā)生時(shí),我們就需要第二個(gè)原則來發(fā)揮作用。
1.2 故障域隔離 - 將火勢(shì)控制在最小范圍
限制故障影響范圍,或者說“縮小爆炸半徑”,指的是萬一故障真的發(fā)生了,我們要盡一切可能減輕它所帶來的負(fù)面影響。這個(gè)影響范圍可以從三個(gè)維度來考量:造成的業(yè)務(wù)損失更小、被影響的用戶數(shù)量更少、被波及的其他關(guān)聯(lián)組件更少。
而限制影響范圍的最佳策略,就是隔離。微服務(wù)架構(gòu)本身就是一種隔離思想的體現(xiàn),它將一個(gè)復(fù)雜的單體系統(tǒng),按業(yè)務(wù)領(lǐng)域劃分成多個(gè)獨(dú)立的服務(wù)。在服務(wù)內(nèi)部,我們還可以進(jìn)一步細(xì)分核心模塊與非核心模塊、核心服務(wù)與非核心服務(wù),盡可能降低它們之間的耦合和相互影響。
然而,在實(shí)踐中,想要做到徹底的隔離,通常面臨兩大現(xiàn)實(shí)難題:
- 服務(wù)間的強(qiáng)依賴:這種依賴一部分源于業(yè)務(wù)邏輯本身的復(fù)雜性,另一部分則源于不合理的架構(gòu)設(shè)計(jì)。我們可以通過優(yōu)化設(shè)計(jì)來解耦(比如后面會(huì)提到的異步化改造),但不可能做到完全沒有依賴。
- 共享基礎(chǔ)設(shè)施:理論上,只要資金允許,我們可以為每一個(gè)服務(wù)都提供一套完全獨(dú)立的數(shù)據(jù)庫、緩存和消息隊(duì)列。但現(xiàn)實(shí)是,大部分公司出于成本考慮,連多部署一套R(shí)edis集群都可能猶豫再三。因此,我們經(jīng)常聽到某某公司因?yàn)橐粋€(gè)非核心業(yè)務(wù)的錯(cuò)誤操作,拖垮了共享的數(shù)據(jù)庫,導(dǎo)致全站核心業(yè)務(wù)崩潰的慘痛事故。
圖片
在做好了隔離,限制了故障影響范圍之后,下一步就是如何快速地從故障中恢復(fù)。
1.3 快速響應(yīng) - 發(fā)現(xiàn)與恢復(fù)的速度之戰(zhàn)
快速發(fā)現(xiàn),強(qiáng)調(diào)的是建立一套完備的、全方位的觀測(cè)(Observability)和告警(Alerting)系統(tǒng)。觀測(cè)的對(duì)象不僅包括服務(wù)本身,更要覆蓋它所依賴的各種基礎(chǔ)設(shè)施和第三方服務(wù)。尤其是在核心業(yè)務(wù)鏈路上的每一個(gè)依賴點(diǎn),都需要進(jìn)行無死角的觀測(cè)。而沒有告警的觀測(cè)是沒有靈魂的,設(shè)置合理、精準(zhǔn)、分級(jí)的告警,是快速發(fā)現(xiàn)問題的前提。
快速恢復(fù),則旨在盡可能縮短服務(wù)的不可用時(shí)間(MTTR - Mean Time To Recover)。但這與其說是一個(gè)純粹的工程技術(shù)問題,不如說是一個(gè)組織建設(shè)和自動(dòng)化的問題。它要求每個(gè)技術(shù)團(tuán)隊(duì)都需要有24小時(shí)的On-Call(值班)機(jī)制。但更深層次的挑戰(zhàn)是,你不可能要求每一個(gè)值班人員都對(duì)組內(nèi)所有項(xiàng)目的技術(shù)細(xì)節(jié)了如指掌。很多時(shí)候,告警響了,值班人員卻不知道如何處理,或者不敢處理。
圖片
因此,要想真正做到快速修復(fù),不能僅僅依賴于研發(fā)人員的個(gè)人能力和自覺性,而必須依賴于自動(dòng)化的故障處理機(jī)制。這一點(diǎn)我們稍后會(huì)詳細(xì)介紹。
1.4 規(guī)范化變更 - 敬畏每一次上線
統(tǒng)計(jì)數(shù)據(jù)表明,線上絕大多數(shù)的故障都是由“變更”引起的。因此,規(guī)范變更流程,指的是任何人都不能隨意地發(fā)布新版本,也不能隨意地修改生產(chǎn)環(huán)境的配置。任何一個(gè)變更,都必須經(jīng)過嚴(yán)格的審查(Review),并準(zhǔn)備好詳盡的回滾預(yù)案。
在實(shí)踐中,我們最害怕的場(chǎng)景莫過于:系統(tǒng)原本運(yùn)行得好好的,但為了修復(fù)一個(gè)非緊急的Bug或者上線一個(gè)小功能,在沒有充分測(cè)試的情況下就匆忙發(fā)布,結(jié)果不僅老問題沒解決,還引入了新的、更嚴(yán)重的問題,導(dǎo)致系統(tǒng)崩潰。
圖片
因此,建立一套完善的變更流程,是大幅提升系統(tǒng)可用性的關(guān)鍵舉措。但這和快速修復(fù)一樣,很大程度上也是一個(gè)組織管理和文化建設(shè)的問題。
2. 面試攻略
2.1 如何打造你的高可用故事線
在面試前,你需要圍繞你最熟悉的項(xiàng)目,準(zhǔn)備一個(gè)從前端到后端、全方位、系統(tǒng)性的高可用方案。你需要仔細(xì)思考并能清晰闡述以下幾個(gè)環(huán)節(jié):
- 入口防護(hù):面向前端用戶的接口,是否有限流、防刷等措施,以防止惡意攻擊者將系統(tǒng)搞垮?
- 依賴高可用:你所依賴的第三方組件,包括緩存(Redis)、數(shù)據(jù)庫(MySQL)、消息隊(duì)列(Kafka)等,是否都采用了高可用的部署方案?
- 依賴故障容錯(cuò):如果你依賴的某個(gè)第三方組件(如Redis)整體崩潰了,你維護(hù)的服務(wù)會(huì)發(fā)生什么?整個(gè)系統(tǒng)是否還能對(duì)外提供有損服務(wù)?
- 服務(wù)間治理:你的所有服務(wù)之間,是否選擇了合適的負(fù)載均衡算法?是否全面實(shí)施了熔斷、降級(jí)、限流和超時(shí)控制等治理措施?
- 流程規(guī)范:你所在公司的上線流程、配置變更流程是怎樣的?你認(rèn)為這些流程對(duì)系統(tǒng)可用性產(chǎn)生了哪些影響?
接下來,我將為你提供一套非常全面的高可用改造話術(shù)模板。你要做的,就是根據(jù)你的真實(shí)項(xiàng)目經(jīng)歷,對(duì)這套模板進(jìn)行個(gè)性化的改造,并用你自己的語言重新組織。
我在這里使用的都是一些比較普適的例子,這意味著即使你在中小型企業(yè),也能找到可以借鑒的地方。但如果你在頭部大廠,有機(jī)會(huì)接觸到像全鏈路壓測(cè)、混沌工程、故障演練等更高級(jí)的高可用方案,你應(yīng)該優(yōu)先使用那些更亮眼的例子。
強(qiáng)烈建議你在面試前,將整個(gè)故事線寫下來并反復(fù)演練。面試講究的是有備無患,千萬不要寄希望于自己的臨場(chǎng)發(fā)揮。
最佳的面試策略,就是在自我介紹時(shí)就主動(dòng)拋出引子,例如提到自己在“高可用微服務(wù)架構(gòu)”方面的豐富經(jīng)驗(yàn),然后在介紹項(xiàng)目時(shí),著重展示你在入職后,是如何大幅度提高了系統(tǒng)的可用性。之后,面試官大概率會(huì)順著你的話,詳細(xì)追問這個(gè)項(xiàng)目以及你是如何做的。這時(shí),你就可以從容地展開下面的故事線了。
故事線構(gòu)建整個(gè)思路可以拆解成五個(gè)步驟:
發(fā)現(xiàn)問題 -> 規(guī)劃方案 -> 落地實(shí)施 -> 成果展示 -> 持續(xù)改進(jìn)
并且通過“發(fā)現(xiàn)問題”和“取得效果”這兩個(gè)環(huán)節(jié)的前后對(duì)比,來有力地凸顯你在這個(gè)過程中的核心作用和價(jià)值。
2.1.1 第一步:發(fā)現(xiàn)問題(描繪“過去時(shí)”)
這個(gè)部分由“項(xiàng)目的核心挑戰(zhàn)”、“挑戰(zhàn)的具體體現(xiàn)”和“問題的根源分析”三部分組成。
“我之前負(fù)責(zé)的XX業(yè)務(wù),是我們公司的核心變現(xiàn)業(yè)務(wù),因此它的核心挑戰(zhàn)就是必須保證極高的可用性。但在我剛?cè)肼毜臅r(shí)候,我發(fā)現(xiàn)這個(gè)系統(tǒng)的可用性是比較低的,穩(wěn)定性問題頻發(fā)。舉個(gè)例子,我入職的第一個(gè)月,就經(jīng)歷了一次比較嚴(yán)重的線上故障:當(dāng)時(shí)另一個(gè)業(yè)務(wù)組突然上線了一個(gè)新功能,里面包含了大量的Redis大Key操作,導(dǎo)致我們共享的Redis集群響應(yīng)變得非常慢,最終拖垮了我們的核心服務(wù),造成了長(zhǎng)時(shí)間的業(yè)務(wù)中斷。”
“這次故障之后,我牽頭做了一次深入的復(fù)盤和調(diào)研。我總結(jié)下來,系統(tǒng)可用性之所以不高,主要有三個(gè)根源性的原因:”
- “首先,是缺乏有效的監(jiān)控和告警。 這導(dǎo)致我們很多時(shí)候都是‘瞎子’,難以在第一時(shí)間發(fā)現(xiàn)問題;即便發(fā)現(xiàn)了,也因?yàn)樾畔⒉蛔悖y以快速定位問題;最終導(dǎo)致難以高效地解決問題。”
- “其次,是服務(wù)治理體系的缺失。 服務(wù)之間調(diào)用混亂,缺乏熔斷、限流等保護(hù)機(jī)制,導(dǎo)致任何一個(gè)非核心服務(wù)出現(xiàn)故障,都可能像推倒多米諾骨牌一樣,引發(fā)整個(gè)系統(tǒng)的雪崩。”
- “最后,是缺乏合理的變更流程。 我們每次復(fù)盤線上事故時(shí),回過頭看,都覺得如果當(dāng)時(shí)能有一個(gè)更嚴(yán)謹(jǐn)?shù)纳暇€和變更流程,那么大部分事故其實(shí)都是可以避免的。”
2.1.2 第二步:規(guī)劃方案(展現(xiàn)“藍(lán)圖”)
這里有一個(gè)常見的誤區(qū):你在現(xiàn)實(shí)中可能確實(shí)做過類似的事情,但往往是“東一榔頭,西一棒槌”,缺乏系統(tǒng)性規(guī)劃。但在面試時(shí),你必須將這些零散的工作,組織成一個(gè)非常有條理、有計(jì)劃的整體方案。
你要給面試官留下的印象,不僅僅是“你能解決問題”,更是“你能有章法、有策略地解決復(fù)雜問題”。
針對(duì)上面分析出的這幾個(gè)具體痛點(diǎn),我制定了一套分階段、可落地的可用性改進(jìn)計(jì)劃,主要分成了以下幾個(gè)步驟:
- “第一步,補(bǔ)齊短板:引入全方位的監(jiān)控與告警。 這是所有工作的基礎(chǔ),目標(biāo)是讓我們具備快速發(fā)現(xiàn)和定位問題的能力。”
- “第二步,構(gòu)建防線:引入全套的服務(wù)治理措施。 這一步是為了提高服務(wù)本身的健壯性,并有效隔離不同服務(wù)間的故障影響。”
- “第三步,加固地基:為所有第三方依賴引入高可用方案。 這一步是為了從根源上減少由外部依賴不穩(wěn)所帶來的風(fēng)險(xiǎn)。”
- “第四步,核心隔離:拆分核心業(yè)務(wù)與非核心業(yè)務(wù)的共同依賴。 這一步是為了進(jìn)一步提高核心業(yè)務(wù)的可用性,確保在極端情況下,核心功能不受非核心業(yè)務(wù)的拖累。”
- “第五步,規(guī)范流程:推動(dòng)建立標(biāo)準(zhǔn)化的變更流程。 這一步是為了從制度上,降低因人為變更而引入Bug的可能性。”
圖片
2.1.3 第三步:落地實(shí)施(講述“進(jìn)行時(shí)”的挑戰(zhàn)與思考)
接下來,你需要詳細(xì)講述方案的落地過程。在講述時(shí),要補(bǔ)充技術(shù)細(xì)節(jié),同時(shí)也可以巧妙地?fù)诫s一些在落地過程中遇到的真實(shí)痛點(diǎn)和阻力,這會(huì)讓你的陳述顯得更加真實(shí)可信。
“在第一個(gè)步驟中,就監(jiān)控告警來說,我們不僅為所有業(yè)務(wù)服務(wù)都添加了核心業(yè)務(wù)指標(biāo)的監(jiān)控和告警,還為所有的第三方依賴,比如數(shù)據(jù)庫、Redis和消息隊(duì)列,都增加了基礎(chǔ)設(shè)施層面的監(jiān)控。在告警方面,我們綜合考慮了告警的頻率、分級(jí)和通知方式,并不斷優(yōu)化告警信息的內(nèi)容,確保信息的充足性,以減少誤報(bào)和“告警疲勞”。這個(gè)過程本身技術(shù)難度不高,但非常瑣碎,需要我們一個(gè)鏈路一個(gè)鏈路地去梳理,一個(gè)業(yè)務(wù)一個(gè)業(yè)務(wù)地去查漏補(bǔ)缺。”
“在第二個(gè)步驟中,服務(wù)治理的范圍比較廣,我主導(dǎo)引入了包括限流、熔斷、降級(jí)、超時(shí)控制、線程池隔離在內(nèi)的一整套方案。”
“第三個(gè)步驟在推行時(shí),遇到了一些阻力。主要是因?yàn)榇蟛糠值谌揭蕾嚨母呖捎梅桨福夹枰~外的資源投入。比如,我們最開始使用的Redis就是一個(gè)單機(jī)實(shí)例,后面我推動(dòng)改造成Redis Cluster時(shí),就需要申請(qǐng)更多的機(jī)器實(shí)例,這需要和領(lǐng)導(dǎo)以及運(yùn)維團(tuán)隊(duì)進(jìn)行多輪的溝通和成本效益分析。”
“第四個(gè)步驟,拆分共同依賴,也是執(zhí)行得不徹底。我們目前的策略是,所有新上線的核心業(yè)務(wù),都會(huì)使用獨(dú)立的數(shù)據(jù)庫和Redis集群。但是對(duì)于一些歷史悠久的老核心業(yè)務(wù),由于改造成本巨大,目前還是維持原狀,共享基礎(chǔ)設(shè)施。”
你可能發(fā)現(xiàn)了,我在談到第三和第四點(diǎn)時(shí),都坦誠地表示執(zhí)行得并不完美。這會(huì)給面試官留下不好的印象嗎?
恰恰相反。因?yàn)槲谊愂龅模径际侨魏我粋€(gè)工程師在真實(shí)工作中都會(huì)遇到的困難,面試官能夠理解。另一方面,一個(gè)方案不可能十全十美,適當(dāng)?shù)乇┞兑恍﹩栴}和妥協(xié),能夠極大地增強(qiáng)你整個(gè)故事的說服力。
“第五個(gè)步驟則有些特殊,它取決于我在公司的角色和影響力。在我還是一個(gè)普通工程師的時(shí)候,我主要是通過技術(shù)分享、故障復(fù)盤等方式,多次向領(lǐng)導(dǎo)和團(tuán)隊(duì)建議建立更規(guī)范的流程。后來,隨著我在團(tuán)隊(duì)中承擔(dān)的責(zé)任越來越重,我就直接推動(dòng)并和大家一起制定了新的上線規(guī)范,包括詳細(xì)的上線Checklist、Code Review流程以及必須具備的回滾計(jì)劃等等。”
2.1.4 第四步:取得效果(量化“完成時(shí)”的價(jià)值)
既然我們討論的是可用性,那么你取得的效果,最直接的體現(xiàn)就是可用性指標(biāo)的提升。一般來說,我建議你說可用性達(dá)到了“3個(gè)9”,而不是“4-5個(gè)9”,因?yàn)楹笳邔?duì)于絕大多數(shù)系統(tǒng)來說,都有些過于夸張了。
“經(jīng)過這一系列組合拳的改進(jìn)之后,我所維護(hù)的核心服務(wù)的可用性,從原來估算不足‘兩個(gè)9’,穩(wěn)定提升到了‘三個(gè)9’以上。最直觀的感受是,半夜被電話告警叫醒的次數(shù)顯著減少了。”
或者,你也可以用一種更幽默的方式來回答:
“現(xiàn)在我們團(tuán)隊(duì)的Bug復(fù)盤會(huì)上,我已經(jīng)不再是那個(gè)經(jīng)常挨罵的人了,更多時(shí)候是坐在下面,看著別人挨罵了(笑)。”
“同時(shí),你還可以補(bǔ)充一下,系統(tǒng)中超出你影響力范圍的部分,可用性依然有待提升:”
“不過,我的服務(wù)還依賴于一些其他團(tuán)隊(duì)提供的服務(wù),而他們的服務(wù)可用性還是比較差。對(duì)此,我這邊只能是盡量做好容錯(cuò),比如在他們服務(wù)不可用時(shí),提供有損服務(wù)。后續(xù)要想進(jìn)一步提高我們業(yè)務(wù)的整體可用性,還是得推動(dòng)他們一起去提升。”
2.1.5 第五步:后續(xù)改進(jìn)(展望“將來時(shí)”)
最后,你需要補(bǔ)充一下你對(duì)未來的改進(jìn)計(jì)劃。一般來說,改進(jìn)計(jì)劃都是針對(duì)現(xiàn)有方案的缺點(diǎn)和不足。
“目前,我的服務(wù),尤其是一些歷史遺留的老服務(wù),相互之間還是在共享一些基礎(chǔ)設(shè)施。比如,一個(gè)出問題就很容易牽連其他服務(wù)。所以我后續(xù)的一個(gè)重要規(guī)劃,就是進(jìn)一步將這些老服務(wù)進(jìn)行解耦,特別是要推動(dòng)將它們依賴的數(shù)據(jù)庫實(shí)例進(jìn)行拆分,省得因?yàn)閯e的業(yè)務(wù)組一條慢SQL,就牽連到我的核心業(yè)務(wù)。大家一起用一個(gè)東西,出了事,有時(shí)候連責(zé)任都很難界定清楚。”
講述改進(jìn)方案有一個(gè)好處,就是它還沒有實(shí)施,你可以大膽地講,什么高大上、什么代表了未來的方向,你就可以講什么,以此來展現(xiàn)你的技術(shù)視野。
2.2 亮點(diǎn)方案:從優(yōu)秀到卓越的進(jìn)階策略
掌握了上述的面試基本思路,你基本上就能給面試官留下一個(gè)相當(dāng)不錯(cuò)的印象了。在這里,我再額外補(bǔ)充一些可以讓你脫穎而出的亮點(diǎn)方案,你可以選擇其中一兩個(gè),來進(jìn)一步強(qiáng)化你在面試官心目中的專家形象。
2.2.1 異步化/解耦 - “少做不錯(cuò),不做不錯(cuò)”
這個(gè)方案的核心思想是:仔細(xì)梳理你的業(yè)務(wù)流程,將其拆分成“必須同步執(zhí)行成功的關(guān)鍵路徑”和“可以異步執(zhí)行的非關(guān)鍵路徑”。
比如,在一個(gè)簡(jiǎn)單的創(chuàng)建訂單的場(chǎng)景中,“扣減庫存”、“創(chuàng)建訂單”、“調(diào)用支付”這幾個(gè)步驟,是必須同步執(zhí)行成功的核心路徑。但是,另外一些步驟,比如“給用戶發(fā)一封下單成功的郵件通知”、“為用戶增加本次購物的積分”,這些就屬于非關(guān)鍵路徑,它們?cè)试S延遲,甚至單次失敗后重試。
圖片
因此,在設(shè)計(jì)高可用微服務(wù)時(shí),有一個(gè)重要的原則:能夠異步執(zhí)行的,絕對(duì)要異步執(zhí)行;能夠解耦的,必須想辦法解耦。
這種理念,用一句樸素的話來形容就是:“多做多錯(cuò),少做少錯(cuò),不做不錯(cuò)”。你同步執(zhí)行的步驟越少,你的主流程就越穩(wěn)定,可用性自然就越高。
“在完成了基礎(chǔ)的服務(wù)治理之后,我還全面推行了核心業(yè)務(wù)的異步化和解耦改造。我將核心業(yè)務(wù)的邏輯,與產(chǎn)品經(jīng)理一起,一個(gè)一個(gè)地重新梳理,最終將所有核心業(yè)務(wù)流程中,能夠異步執(zhí)行的步驟,全部改造成了異步執(zhí)行。這樣一來,我的業(yè)務(wù)中,需要同步執(zhí)行的關(guān)鍵步驟就大大減少了。而后續(xù)異步執(zhí)行的動(dòng)作,即便失敗了,我們也可以通過消息隊(duì)列的重試機(jī)制來保證最終成功,所以整個(gè)系統(tǒng)的可用性都得到了大幅度的提升。”
“具體的實(shí)現(xiàn)方式是,在核心的A步驟成功執(zhí)行之后,我們不再直接調(diào)用B步驟,而是發(fā)送一條消息到消息隊(duì)列。然后由另一個(gè)獨(dú)立的消費(fèi)服務(wù)來監(jiān)聽消息,并執(zhí)行B步驟。”
2.2.2 自動(dòng)化故障處理 - 邁向“四個(gè)9”的關(guān)鍵
嚴(yán)格來說,我們前面提到的熔斷、降級(jí)、限流,也屬于自動(dòng)化的故障處理。但我這里說的是,構(gòu)建一個(gè)獨(dú)立的、更高維度的系統(tǒng),來自動(dòng)處理業(yè)務(wù)系統(tǒng)發(fā)生的各類故障。
圖片
一個(gè)線上問題,從被發(fā)現(xiàn),到找到臨時(shí)應(yīng)對(duì)方案,再到付諸實(shí)施,一不留神一個(gè)小時(shí)就過去了。所以在可用性達(dá)到“三個(gè)9”以后,如果你還想進(jìn)一步提升,就要么想辦法降低事故發(fā)生的概率,要么想辦法無限提高故障恢復(fù)的速度。
人本身不可能做到24小時(shí)精神高度緊張地待命,也不可能對(duì)所有系統(tǒng)細(xì)節(jié)都了如指掌。所以,自動(dòng)化故障處理機(jī)制,是通往“四個(gè)9”甚至更高可用性的必經(jīng)之路。
這里,我給你一個(gè)最常見的例子:微服務(wù)集群自動(dòng)擴(kuò)容。它是指,對(duì)整個(gè)微服務(wù)集群的負(fù)載進(jìn)行實(shí)時(shí)監(jiān)控,如果發(fā)現(xiàn)集群整體負(fù)載過高,就自動(dòng)增加新的服務(wù)實(shí)例。
圖片
“為了進(jìn)一步提高整個(gè)集群服務(wù)的可用性和彈性,我跟運(yùn)維團(tuán)隊(duì)進(jìn)行了密切合作,共同設(shè)計(jì)并實(shí)現(xiàn)了服務(wù)的自動(dòng)擴(kuò)容機(jī)制。我們?cè)试S不同的業(yè)務(wù)方,根據(jù)自己服務(wù)的特性,設(shè)置不同的擴(kuò)容觸發(fā)條件。比如,我為我的核心服務(wù)設(shè)置了‘CPU使用率’和‘內(nèi)存使用率’兩個(gè)組合指標(biāo)。如果我這個(gè)服務(wù)的所有節(jié)點(diǎn),在持續(xù)一段時(shí)間內(nèi),平均CPU使用率都超過了90%,那么就會(huì)自動(dòng)觸發(fā)擴(kuò)容,每次擴(kuò)容會(huì)新增一個(gè)節(jié)點(diǎn),直到負(fù)載降到安全水位以下。”
這里我用的例子,決策理由也比較簡(jiǎn)單。CPU使用率長(zhǎng)期處于高位,基本上代表節(jié)點(diǎn)處于高負(fù)載狀態(tài)。并且,我特意強(qiáng)調(diào)了是“集群里面的所有節(jié)點(diǎn)都超過了某個(gè)指標(biāo)”,這是為了防止因?yàn)樨?fù)載均衡不均,導(dǎo)致單一節(jié)點(diǎn)過載而引起不必要的擴(kuò)容。
還有一些常見的自動(dòng)化故障處理方案,你可以參考:
- 自動(dòng)修復(fù)數(shù)據(jù):通過定時(shí)任務(wù),比對(duì)不同系統(tǒng)或表中的數(shù)據(jù),如果發(fā)現(xiàn)數(shù)據(jù)不一致,就發(fā)出告警,并同時(shí)觸發(fā)預(yù)設(shè)的自動(dòng)修復(fù)程序。
- 自動(dòng)補(bǔ)發(fā)消息:也是通過定時(shí)任務(wù)等機(jī)制,來掃描業(yè)務(wù)狀態(tài),如果發(fā)現(xiàn)某個(gè)業(yè)務(wù)流程因?yàn)橄G失而卡住了,就觸發(fā)告警,并自動(dòng)進(jìn)行消息補(bǔ)發(fā)。
但凡你的業(yè)務(wù)中,存在大量需要人工介入處理的數(shù)據(jù)不一致或流程中斷問題,你都應(yīng)該思考,是否可以設(shè)計(jì)一個(gè)自動(dòng)化的恢復(fù)程序,去自動(dòng)地發(fā)現(xiàn)和修復(fù)它們。
3. 小結(jié)
這篇文章我們系統(tǒng)性地探討了如何保證微服務(wù)應(yīng)用高可用的綜合性方案。當(dāng)然,這里給出的整個(gè)話術(shù)和方案,是一個(gè)“框架”,面試的時(shí)候你需要根據(jù)你的實(shí)際項(xiàng)目經(jīng)驗(yàn),來填充血肉。業(yè)界有非常多的高可用方案,你可以多學(xué)習(xí)幾種,將它們內(nèi)化成你自己的知識(shí)體系,并整合進(jìn)你的面試方案里。
同時(shí),你也不需要掌握全部的高可用方案,因?yàn)閷?shí)在太多,學(xué)不過來。你只需要重點(diǎn)掌握幾種,然后在面試的時(shí)候,學(xué)會(huì)主動(dòng)引導(dǎo)和把控面試的節(jié)奏,將面試官的提問,巧妙地限制在你所了解和擅長(zhǎng)的那幾種方案上,就足夠了。


































