Design for failure常見的12種設計思想
本文轉(zhuǎn)載自微信公眾號「架構(gòu)精進之路」,作者張張 。轉(zhuǎn)載本文請聯(lián)系架構(gòu)精進之路公眾號。
hello,大家好,我是張張,「架構(gòu)精進之路」公號作者。
通常情況下,我們的一個請求會經(jīng)過三個服務來處理。
請求從客戶端發(fā)出,到達Proxy Layer(執(zhí)行一些公共的邏輯,如邏輯、流控、審計等),完成后,發(fā)往App Layer(執(zhí)行具體業(yè)務邏輯),執(zhí)行完畢后,發(fā)向Data Laye(進行數(shù)據(jù)持久化)。
事情看起來很簡單,然而,在一個分布式系統(tǒng)中:出錯是常態(tài)。
因此,我們需要:Design For Failure。即當你的系統(tǒng)將錯誤當作正常流時,系統(tǒng)便已經(jīng)對錯誤免疫了。
在此,跟大家介紹常見的12種設計思想。
1、防御性設計(Defensive Design)
所謂的防御性設計實際上就是“防呆”,英文叫Idiot Proofing。說白了就是用戶有時候會不自覺的做一些蠢事,我們在設計的時候要盡量考慮到一些不規(guī)范的交互行為,如果你的用戶是一只猴子,你要寫包單保證系統(tǒng)不被玩壞。
例如,在Android開發(fā)中使用到的Monkey Test就是用于這樣的目的。
2、邊界情況(Edge Case)
這個設計思想在測試領(lǐng)域比較常見,就是我們在設計我們的設計案例的時候有沒有充分考慮在邊界情況下的系統(tǒng)行為。
比較常見的例如,閏年情況、跨日情況等邊界。
3、防誤措施(Mistake Proofing)
怎么保證不會發(fā)生錯誤。例如在人機交互環(huán)節(jié),能不能進行輸入校驗?
4、解耦(Decoupling)
設計的時候,哪怕是最基礎(chǔ)的代碼也應該符合開閉原則。
Spring的IOC就是為了把對象創(chuàng)建及維護從原來的由引用類負責這種強耦合模式轉(zhuǎn)成通過spring容器負責。且解耦一般的做法是通過把內(nèi)部邏輯封裝起來,暴露對外統(tǒng)一API接口,調(diào)用方不需要了解被調(diào)用方的內(nèi)部邏輯實現(xiàn),只需要知道提供什么功能即可。
再引申一下,解耦的作用就在于復用,把所有的高內(nèi)聚功能獨立成一個個模塊,然后就可以像樂高積木一樣根據(jù)調(diào)用方的實際需求進行組裝。
5、冗余(Redundancy)
所謂的冗余指的通過重復配置關(guān)鍵組件或部件,保證在關(guān)鍵組件失效的情況下還有備份組件運作以便保證系統(tǒng)可以繼續(xù)提供服務。生活中的例子請參與飛機的雙引擎設計。
主從模式就是冗余的體現(xiàn)。在正常情況下,主實例負責提供全部的服務,從實例在主實例整體或部分不可用的情況下,完全替代主實例整體或局部而對外提供服務。
6、重試(Retry)
重試是在分布式系統(tǒng)下處理瞬態(tài)故障的一個基本手段,簡單有效(當然重試的前提是要求冪等)。但是重試也是可以很危險的,它能夠引起把一個局部小時間迅速升級為一個系統(tǒng)重大故障,嚴重者導致系統(tǒng)假死。
舉個簡單例子:如果我們的鏈路類似上圖,這里會發(fā)生什么問題?
在極端情況下,重試次數(shù)達到5*5*5*5=625次。
當鏈路中的其中一個服務故障率異常的時候,那重試風暴便開啟了,因為重試為服務器帶來額外的開銷和線程的占用,然后其他新來的請求又形成排隊,這樣的話就形成了類似的DDos惡性事件。
7、冷備(Cold Standby)
冷備實際上也是冗余設計的其中一種體現(xiàn),只是它會更側(cè)重于“冷”,意思是當系統(tǒng)發(fā)生宕機時,這個系統(tǒng)是需要手動啟動用于替換下線的主實例,它是跟熱備是不一樣,熱備更多體現(xiàn)在自動切換。
8、熔斷(Derating)
熔斷本質(zhì)上就是一種防御性設計或者策略。假設一個微服務體系下的系統(tǒng),其中A服務調(diào)用B服務。系統(tǒng)的QPS是千級別,當時如果B服務掛掉的話A的線程絕對在短時間內(nèi)占滿耗盡而導致假死,從而形成大量A請求積壓而導致情況惡化,最終形成雪崩。
9、容錯(Error Tolerance)
狹義的容錯泛指人機交互界面的時候需要對用戶輸入進行輸入校驗,保證數(shù)據(jù)準確性。
廣義的容錯應該是兩個具有明確邊界的事物(如服務間,系統(tǒng)間)交互時候針對可能發(fā)生的一切主客觀異常情況的防御性手段。常見的容錯機制有failsafe、failback、failover、failfast。
- failfast 更多指的是快速失敗,避免線程積壓導致系統(tǒng)滾雪球式崩潰。
- failover 指的是失效轉(zhuǎn)移。
- failsafe 指的是失效安全。
- failback 指的是失效自動恢復,將故障實例切換到備實例。
10、失效安全(Fail safe)
所謂的失效安全,就是指在特定失效的情況下,一個系統(tǒng)或者服務也不會對業(yè)務造成損害。
例如:我們使用token進行安全登錄也是一種失效安全的體現(xiàn),如果token失效了(如時間過期),用戶是無法登錄的,因為正常登錄需要token有一種約束因素,這種因素就是時間。如果時間過了,代表這種約束因素不存在或者不再有效了,登錄功能就不能正常工作了。
11、優(yōu)雅降級(Graceful Degradation)
服務降級跟熔斷還是挺像的,只是降級來得更加溫和和優(yōu)雅一點。熔斷是直接斷掉防止異常進一步擴大而導致雪崩,但是我們的終極目標是提供盡可能多的服務,這個就是優(yōu)雅降級的理念。在一些異常情況或者秒殺場景下,為了保證核心服務(如商品下單、支付)的正??捎茫瑫艞壍粢恍┓呛诵姆?如歷史賬單查詢),這就是所謂的服務降級。
在微服務框架中,一般會使用Hystrix的@HystrixCommand或Feign的@FeignClient對服務進行聲明,然后為每個服務配置相應的fallback類,最終結(jié)合起來進行服務降級。
12、耐用性(Durability)
這里我理解的是系統(tǒng)或數(shù)據(jù)的耐受性。
例如數(shù)據(jù),為什么我們一定要持久化到數(shù)據(jù)庫,因為就是要借助數(shù)據(jù)庫硬件各種維度的耐受性。
補充
作為一名designer或者developer,應該要對墨菲定律心存敬畏。
另外,需要額外補充一點的就是:監(jiān)控(Monitoring)。
我們的系統(tǒng)有哪幾個緯度的監(jiān)控,估計最多就是常規(guī)的硬件狀態(tài)監(jiān)控。當然這里的監(jiān)控我理解除了技術(shù)指標監(jiān)控,還更應該有業(yè)務指標監(jiān)控,否則我們都在裸泳,等海水退下去后就一覽無遺。
監(jiān)控實際上是為了更好的主動防御,一套完善的告警監(jiān)控系統(tǒng),能夠快速通知開發(fā)與運維,開發(fā)側(cè)能夠完成緊急修復并能夠協(xié)同運維進行快速部署。