分布式系統中故障不可避免,所以為了提高可用性一定要做彈力設計,也就是容錯設計。
常見的容錯手段有:
- 隔離設計
- 異步通信
- 冪等設計
隔離設計
隔離分為兩種,一種是以服務為種類來做隔離,另一種是以用戶為種類來做分離。
服務維度的隔離是指不同的服務種類設計成獨立的系統,比如電商平台,將用戶注冊登陸設計為一個系統,商品中心設計為另一系統,評論和社交設計為一個系統。這三個系統彼此相互獨立,互不耦合,這三個系統的接入層、應用層和數據層都完全隔離的。這樣一來,一個板塊出了故障就不會影響到其他功能了。在分布式系統中,每個服務都應該有自己獨立的數據庫,多個服務間不應該共享數據庫,否則出了問題很難定位。比如審核系統有很多字段,有些字段不同的服務都會去修改,若設計成多個服務共享一個hbase,那么一個字段狀態不對了就很難排查到底是哪個服務把這個狀態寫錯了。
帶來的問題
- 如果我們需要獲取多個板塊的數據,那么需要協調多個服務,進行多次調用,這會降低性能,響應時間會增加。對此需要在展示的時候做好分頁,每次展示有限數量的內容。
- 如果有大數據平台,就會有把各個服務的數據抽到一個數據倉庫,這會增加數據聚合的難度。這個時候,需要一個中間件或者服務來聚合各個自服務的數據。
- 如果有些業務流程需要跨板塊的話,某個板塊出現問題會導致整個服務走不下去。一方面要保證服務的高可用,另一方面業務流程要做到step-by-step,保存每一步的處理結果(狀態),這樣如果某一步失敗了,重試的時候就無需從頭開始執行了。
- 多板塊的交互也會變得復雜,需要消息中間件來打通各個板塊之間的交互和信息交流
- 如果多板塊存在分布式事務,需要引入兩階段提交
按照用戶來做隔離
將不同的用戶進行分組,部署不同的實例。這樣某些服務實例掛掉后,只會影響其對應的用戶組,不會影響其他用戶。比如秒殺用戶不會影響其他的網購用戶。不同的用戶組的應用層和數據層可以獨立部署,也可以共享數據。如果該用戶組是非常重要的大客戶,可以單獨部署服務層和數據庫。一般來說都是折中方案。
異步通信設計
分布式系統很多時候是為了解決高吞吐的場景。此時,異步通信就比同步通信有更大的優勢了。因為異步通信節省了很多調用時等待response的時間。
同步調用還會導致系統被最慢的那個服務拖垮,此外如果某個服務掛掉后會產生雪崩,導致其他服務也不能正常使用。異步調用可以將各個服務徹底解偶。
異步通信有三種方式:
業務方不斷輪訓、服務方回調通知、broker方式。前兩種方式有一定偶爾,broker方式則完全解偶。
Broker方式就是EDA(事件驅動模式),服務間通過消息來完成交流和整個流程的驅動。
帶來的問題
- 無法保證時間的順序,會出現亂序
- 事務處理會變的很復雜,需要用兩階段提交來保證數據的一致性
冪等設計
網絡調用種有三種狀態:成功、失敗和超時。前兩者是明確的,而超時是一種未知狀態。
面對超時,client重試可能會導致副作用。為了解決副作用,一般有兩種處理方式:
- 服務方提供查詢接口,給調用方查詢結果是否被執行了;
- 提供冪等接口,讓client放心重試;
有些操作是有副作用的,比如http post表示新建。為了實現冪等,我們一般會把每個任務用唯一的識別碼(雪花算法)表示,然后將結果存到存儲種。這樣不管是查詢還是提供冪等接口都需要,也便於服務的擴展。
服務的狀態
將服務從有狀態到無狀態的遷移是微服務的設計理念之一。這樣做可以提高服務的伸縮性。將服務的狀態存到第三方存儲是通用的方法;而有狀態服務的好處是數據本地化,響應時間比較快。有狀態服務的數據可以通過gossip協議還有就是session-sticky。
此外
此外分布式系統還要做好業務補償,流程到某一步實在做不下去了要做好補償。重試、限流、熔斷、降級等也是必須的。