如何設計兜底方案(高可用)

冰魄秋雨發表於2024-06-04

場景:
很多時候,在同步資料時,都會有一個重新推送的按鈕,不管是重新推送還是重新拉去。這些動作都是失敗後,再次操作,直到成功。
image

這種設計的原因是,程式的執行,不知道什麼原因會失敗。網路、資料庫、伺服器,B服務BUG都會導致這段程式碼執行失敗,從而無法保證該功能準確執行。

設計的設計中都是需要兜底的方式,或者冗餘的設計

  1. 系統自動重試
  2. 主動備份,透過備份能夠繼續訪問
  3. 人為操作程式來完成錯誤後的流程

框架程式中兜底的設計

1.OpenFeign框架的重試

OpenFeign請求框,雖然預設情況下沒有開啟重試的機制,但是隻需要配置,請求呼叫在失敗後,會進行重試。


@Configuration  // 儲存 Ioc
public class RetryerConfig {
    @Bean
    public Retryer retryer() {
        return new Retryer.Default(
            1000,  // 重試間隔時間
            1000,  // 最大重試間隔時間
            3  // 最大重試次數
        );
    }
}

2.Rocketmq中NameServer

rocketmq的nameServer掛了,本地已儲存的配置在一段時間內能夠保證服務能夠送達。

試想我們有一個配置中心服務,它會定期更新線上各服務的配置引數。那麼當我們設計服務時,其實是需要考慮到一旦配置中心出現故障,對我們服務的影響。

我們可以這麼設計:首先提供一個本地配置檔案(當然它的引數肯定比較過時了),作為任何異常情況下的兜底。其次將每次從配置中心上拉下來的配置引數,寫一份到本地,這樣即使後續讀取失敗,我們也會有一份比較新的配置引數可用。最後我們再開一個執行緒,實時拉取新的引數,進行更新操作。

按照這種方式,將服務從強依賴配置中心,改為了弱依賴。不過需要考慮到這種設計帶來的複雜度,如拉取新的配置檔案到寫入本地磁碟,這一過程是原子操作的。

3.XXL-JOB的人工介入的重試

新開發的運營系統,需要每天凌晨跑一個job,這個job比較複雜,其中涉及到了多個端的呼叫
設計的方案:首先讓它每隔一小時就啟動判斷一次,如果該任務當天已經完成了,就不再重新啟動,否則開始執行當天的job;如果第一次job執行失敗了,之後的job也會執行成功。
其次會假設萬一當天執行的job失敗了,我在配置檔案中仍然會配置一個預設引數,這時直接使用該引數進行兜底。

高可用的實踐方案

網路上高可用實踐方案總結:

  • 1、對等節點的故障轉移,Nginx和服務治理框架均支援一個節點失敗後訪問另一個節點。
  • 2、非對等節點的故障轉移,透過心跳檢測並實施主備切換(比如redis的哨兵模式或者叢集模式、MySQL的主從切換等)。
  • 3、介面層面的超時設定、重試策略和冪等設計。
  • 4、降級處理:保證核心服務,犧牲非核心服務,必要時進行熔斷;或者核心鏈路出問題時,有備選鏈路。
  • 5、限流處理:對超過系統處理能力的請求直接拒絕或者返回錯誤碼。
  • 6、MQ場景的訊息可靠性保證,包括producer端的重試機制、broker側的持久化、consumer端的ack機制等。
  • 7、灰度釋出,能支援按機器維度進行小流量部署,觀察系統日誌和業務指標,等執行平穩後再推全量。
  • 8、監控報警:全方位的監控體系,包括最基礎的CPU、記憶體、磁碟、網路的監控,以及Web伺服器、JVM、資料庫、各類中介軟體的監控和業務指標的監控。
  • 9、災備演練:類似當前的“混沌工程”,對系統進行一些破壞性手段,觀察區域性故障是否會引起可用性問題。

高可用的方案主要從冗餘、取捨、系統運維3個方向考慮,同時需要有配套的值班機制和故障處理流程,當出現線上問題時,可及時跟進處理。

image

相關文章