SOFA 源碼分析 — 自動故障剔除

前言

集群中通常一個服務有多個服務提供者。其中部分服務提供者可能由于網(wǎng)絡,配置,長時間 fullgc ,線程池滿,硬件故障等導致長連接還存活但是程序已經(jīng)無法正常響應。單機故障剔除功能會將這部分異常的服務提供者進行降級,使得客戶端的請求更多地指向健康節(jié)點。當異常節(jié)點的表現(xiàn)正常后,單機故障剔除功能會對該節(jié)點進行恢復,使得客戶端請求逐漸將流量分發(fā)到該節(jié)點。單機故障剔除功能解決了服務故障持續(xù)影響業(yè)務的問題,避免了雪崩效應。可以減少人工干預需要的較長的響應時間,提高系統(tǒng)可用率。

這種功能叫做自動故障剔除。

而 SOFA 是怎么實現(xiàn)的呢?

如何使用

自動故障剔除的運行機制:

  • 單機故障剔除會統(tǒng)計一個時間窗口內的調用次數(shù)和異常次數(shù),并計算每個服務對應ip的異常率和該服務的平均異常率。
  • 當達到ip異常率大于服務平均異常率到一定比例時,會對該服務+ip的維度進行權重降級。
  • 如果該服務+ip維度的權重并沒有降為0,那么當該服務+ip維度的調用情況正常時,則會對其進行權重恢復。
  • 整個計算和調控過程異步進行,不會阻塞調用。

根據(jù)官方例子,使用方式如下:

FaultToleranceConfig faultToleranceConfig = new FaultToleranceConfig();
        // 是否開啟調控.
        faultToleranceConfig.setRegulationEffective(true);
        // 是否進行降級
        faultToleranceConfig.setDegradeEffective(true);
        // 時間窗口大小
        faultToleranceConfig.setTimeWindow(20);
        // 每次權重降級的比率
        faultToleranceConfig.setWeightDegradeRate(0.5);

FaultToleranceConfigManager.putAppConfig("appName", faultToleranceConfig);

如上,該應用會在打開了單機故障剔除開關,每20s的時間窗口進行一次異常情況的計算,如果某個服務+ip的調用維度被判定為故障節(jié)點,則會進行將該服務+ip的權重降級為0.5倍。

可以看到,這個功能面向框架用戶的 API 就是這個 FaultToleranceConfig 類,即故障容錯配置。

用戶可以配置某個服務是否開啟調控,是否進行降級,實際窗口大小(秒),每次權重降級的比率。

那么,SOFA 是如何實現(xiàn)的呢?

源碼分析

首先說明,由于這個功能相比較之前的功能,代碼要復雜一些,因此,本次分析主要分析主流程,不會面面俱到。關于詳細的代碼細節(jié),我們將在后面的源碼分析中詳細解釋。

1. 初始化

SOFA 對于該功能的設計使用了 Modle 的方式,簡單來說,就是一個可擴展,可熱插拔的中間件。SOFA 的中間件和 RPC 框架都是通過 Modle 的方式來實現(xiàn)的。

如何實現(xiàn)呢?

RPC 初始化的時候,會調用 RpcRuntimeContext 類的靜態(tài)塊,該靜態(tài)塊內部會初始化其他模塊,即調用 ModuleFactory.installModules() 方法。該方法會加載配置文件中所有 Module 接口的 SPI 文件。然后循環(huán)調用 install 方法,即初始化。

目前的源碼中只有一個 Module 的實現(xiàn)類,即 FaultToleranceModule 。故障容錯模塊。該類的 install 方法 會創(chuàng)建一個訂閱者,在事件總線中訂閱兩個事件:ClientSyncReceiveEvent 和 ClientAsyncReceiveEvent。然后創(chuàng)建一個事件窗口調控器。并初始化該調控器。

TimeWindowRegulator 是故障調控的核心類,內部包含以下屬性:

  1. measureCounter 度量計數(shù)器,每執(zhí)行一次度量任務,就加一。
  2. measureScheduler 度量定時任務線程池,使用 RATE 模式,即從任務開始時間開始計算。如果任務的時間超過了間隔時間,間隔時間將失效。這里的間隔時間是 1 秒。
  3. regulationExecutor 計算線程池,即在定時任務線程池中提交計算任務給這個線程池,以實現(xiàn)快速返回。該線程池核心大小為 2.
  4. measureModels 度量模型,一個存放 MeasureModel 對象的 List。
  5. measureStrategy 計算策略(根據(jù)度量結果,判斷是否需要執(zhí)行降級或者恢復)
  6. weightDegradeStrategy 降級策略: 調整權重
  7. logDegradeStrategy 降級策略: 只打印日志
  8. recoverStrategy 恢復策略:調整權重
  9. listener 調用統(tǒng)計監(jiān)聽器,當發(fā)生事件時,會調用監(jiān)聽器的方法。

屬性很多,暫時不詳細解釋。說主流程。

該類的 intit 方法是初始化這些屬性,并注冊監(jiān)聽器。注冊方式是調用 InvocationStatFactory.addListener(listener) 方法。而這個監(jiān)聽器是該類的內部類 —— TimeWindowRegulatorListener。

好,初始化完畢之后,開始說流程。

當 RPC 框架調用了發(fā)送消息的方法,并返回(或者失敗)后,就會向事件總線 EventBus 丟一個事件。例如 ClientSyncReceiveEvent 事件,該事件需要包含以下屬性:

    private final ConsumerConfig consumerConfig;
    private final ProviderInfo   providerInfo;
    private final SofaRequest    request;
    private final SofaResponse   response;
    private final Throwable      throwable;

基本包含了此次調用的所有信息。

此時,就會觸發(fā)訂閱者的 onEvent 方法。即 FaultToleranceSubscriber 的 onEvent 方法。該方法會判斷,如果用戶啟用了自動故障剔除功能,則根據(jù) consumerConfig 和 providerInfo 得到一個調用統(tǒng)計器對象,并對調用次數(shù)加一。

關鍵的方法在 onEvent 中調用的 InvocationStatFactory.getInvocationStat(consumerConfig, providerInfo); 該方法會創(chuàng)建一個 InvocationStat 調用統(tǒng)計器對象,放入 Map 中,而對應的 key 則是根據(jù)上面兩個參數(shù)生成的 InvocationStatDimension 統(tǒng)計維度對象。

創(chuàng)建完 InvocationStat 調用統(tǒng)計器對象后,調用所有監(jiān)聽器的 onAddInvocationStat 方法,表示,我添加了一個監(jiān)聽器了,你可以做點什么了。還記得 TimeWindowRegulator 初始化的時候會添加一個監(jiān)聽器嗎。就是這里的監(jiān)聽器。

內部類 TimeWindowRegulatorListener 的方法邏輯如下:
調用度量策略對象的 buildMeasureModel 方法,傳入調用統(tǒng)計器。返回一個度量模型。然后,將這個模型添加進 List(measureModels 屬性) 中。并調用外部類的 startRegulate 方法,開始進行調控。

startRegulate 方法就是啟動了定時任務,使用了一個原子 boolean 變量進行狀態(tài)判斷。

定時任務的內容是什么呢?

答:運行 MeasureRunnable 任務。
該任務首先會對度量計數(shù)器加一。然后循環(huán) List 中的 MeasureModel 度量模型。并判斷該 MeasureModel 是否到達了用戶設定的時間窗口(取于用戶設置的時間大小)。

如果到達了時間窗口,并調用 measureStrategy 度量策略對象(serviceHorizontal)的 measure 方法,參數(shù)則是度量模型,返回一個度量的結果對象 —— MeasureResult。

得到這個對象后,向計算線程池提交一個 RegulationRunnable 任務,該任務內容如下:
拿到剛剛傳入的度量結果拿到度量結果詳情的集合 —— measureResultDetails,循環(huán)這些集合,并執(zhí)行 doRegulate 方法,進行調控。

該方法就是真正的對服務進行調控的方法了。首先,一個服務有 3 個狀態(tài):健康,異常,忽略。狀態(tài)來自于剛剛的 measure 方法。

如果用戶設置了可以降級的話,則判斷服務的度量狀態(tài),如果異常了且不超過一個服務的最大調控 IP 數(shù),則執(zhí)行權重降級邏輯。反之,打印日志。

如果度量狀態(tài)是正常的,則執(zhí)行權重恢復,并從降級 IP 列表中刪除。

如果用戶沒有設置可以降級,且度量狀態(tài)是異常,那么,執(zhí)行日志降級。即對異常 IP 記性異常信息的日志打印。

當對權重進行降級之后,能夠被負載均衡擊中的幾率就會對應的小很多。甚至了無法擊中。

以上,就是 SOFA 自動故障剔除功能的基本實現(xiàn)流程。

總結

還是那句話,由于這個功能比較繁雜,限于篇幅,今天看的是總流程,總結一下這個流程。

RPC 框架在啟動的時候,會自動加載故障容錯模塊,并監(jiān)聽客戶端發(fā)送事件。同時會初始化故障容錯相關的類和監(jiān)聽器。

當發(fā)生訂閱事件的時候,會調用 onEvent 方法,進而調用 TimeWindowRegulatorListener 的監(jiān)聽器方法。該方法會將度量模型添加進 List 中。

定時任務每隔一秒會調度 MeasureRunnable 任務,內容是根據(jù)用戶設置的時間窗口處理 List 中的調度模型。

定時任務會向計算任務線程池提交一個 RegulationRunnable 任務。用于處理度量結果中的數(shù)據(jù)。該任務會循環(huán)度量結果的所有度量結果詳情,并調用 doRegulate 方法進行調控。

最后,doRegulate 方法則是根據(jù) 度量結果詳情 的狀態(tài)判斷是否應該對服務 + IP 進行權重降級或者權重恢復,再或者是打印日志 —— 這依據(jù)用戶設置。

以上就是 SOFA 自動故障剔除的基本流程。后面我們會詳細分析自動故障剔除的細節(jié)代碼。敬請期待。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容