天天看點

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

作者:程式員進階碼農II

擴充Sentinel實作開關降級

Sentinel實作了插件功能,支援将自定義處理器插槽(ProcessorSlot)通過SPI注冊到ProcessorSlotChain中,或者通過自實作SlotChainBuilder建構ProcessorSlotChain,将自定義處理器插槽注冊到ProcessorSlotChain中。是以,我們可以通過自定義ProcessorSlot為Sentinel添加開關降級功能。

與限流、熔斷降級等流量控制的實作一樣,首先定義開關降級規則類,實作loadRulesAPI;然後提供一個Checker,由Checker判斷開關是否打開,是否需要拒絕目前請求;最後自定義ProcessorSlot與SlotChainBuilder,實作攔截請求的功能。

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

與使用AOP實作開關降級有所不同,擴充Sentinel實作開關降級不需要在接口方法或類上添加注解,可以全部通過配置規則實作,這也是為什麼選擇擴充Sentinel實作開關降級功能的原因。

一個開關通常會控制很多接口,是以一個開關對應一個開關降級規則,一個開關降級規則可配置多個資源。開關降級規則類SwitchRule的代碼如下。

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

SwitchRule類字段說明如下。

• status:開關狀态,取值為open或close。

• resources:開關控制的資源。

Resources内部類字段說明如下。

• include:包含的資源。

• exclude:排除的資源。

靈活,不僅隻是不需要使用注解,還需要可以靈活地指定開關控制哪些資源,是以,配置開關控制的資源應支援以下幾種情況:指定該開關隻控制哪些資源(include),或控制除

了哪些資源(exclude)的其他資源,或者控制全部資源。是以,SwitchRule的資源配置與Sentinel的限流、熔斷降級規則的資源配置不一樣,SwitchRule支援以下3種資源配置方式。

• 如果不配置resources,則開關作用于全部資源。

• 如果配置了include,則開關作用于include指定的所有資源。

• 如果不配置include且配置了exclude,則除exclude指定的資源外,其他資源都受這個開關的控制。

接着實作loadRulesAPI。在Sentinel中,提供loadRulesAPI的類通常被命名為XxxRuleManager,即Xxx規則管理器,是以我們定義開關降級規則管理器的名稱為SwitchRuleManager。SwitchRuleManager的代碼如下。

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

SwitchRuleManager提供了兩個API。

• loadSwitchRules:用于更新或加載開關降級規則。

• getRules:擷取目前生效的全部開關降級規則。

同樣地,Sentinel一般會将決定規則是否達到觸發開關降級的門檻值由XxxRuleChecker完成,即Xxx規則檢查員。是以我們定義開關降級規則檢查員的名稱為SwitchRuleChecker,由SwitchRuleChecker檢查開關是否打開,若開關打開,則抛出SwitchException,拒絕請求。

SwitchRuleChecker的代碼如下。

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

① 周遊規則,每個打開狀态的開關都有可能控制目前資源,隻要其中一個關聯到目前資源,就拒絕目前請求。

② 判斷開關狀态,如果開關未打開,則跳過。

③ 實作include語意,如果規則配置了include,并且include包含目前資源,則比對成功,抛出SwitchException以拒絕目前請求。

④實作exclude語意,如果規則配置了exclude,并且exclude不包含目前資源,則抛出SwitchException以拒絕目前請求。

整個checkSwitch方法實作的功能:SwitchRuleChecker從SwitchRuleManager中擷取配置的開關降級規則,并周遊開關降級規則,如果開關打開,且比對到目前資源名稱被該開關控制,則抛出SwitchException。

SwitchException需繼承BlockException,如果抛出的SwitchException沒有被捕獲,則由全局異常處理器處理。

注意:必須抛出BlockException的子類異常,否則抛出的異常會被資源名額資料統計收集,會影響到熔斷降級等功能的準确性。

雖然SwitchRuleChecker使用了for循環周遊開關降級規則,但是一個項目中的開關是很少的,一般隻有一個或幾個,并且使用hash比對include與exclude,時間複雜度接近O(1),是以這樣實作的開關降級對性能影響并不大。

要使用開關功能,我們還需要自定義處理器插槽:SwitchSlot。

SwitchSlot類繼承AbstractLinkedProcessorSlot抽象類,負責在entry方法中調用SwitchRuleChecker#checkSwitch方法,檢查是否需要拒絕目前請求。SwitchSlot類的代碼如下。

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

現在,我們需要自定義SlotChainBuilder,即MySlotChainBuilder,将自定義的SwitchSlot添加到ProcessorSlotChain的末尾。當然,可以将SwitchSlot添加到任何位置,因為SwitchSlot沒有用到資源名額資料,是以将SwitchSlot放在哪裡都不會影響Sentinel的正常工作。

MySlotChainBuilder的代碼如下。

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

如上述代碼所示,MySlotChainBuilder繼承DefaultSlotChainBuilder隻是為了使用DefaultSlotChainBuilder#build方法。若要簡化ProcessorSlotChain的構造步驟,則隻需要在DefaultSlotChainBuilder構造好的連結清單尾部添加一個SwitchSlot即可。

但是MySlotChainBuilder還沒有生效,隻有将MySlotChainBuilder注冊到SlotChainBuilder接口的SPI配置檔案中後,MySlotChainBuilder才會生效。具體操作為在目前項目的resources/META-INF/service資源目錄下建立一個名稱為com.alibaba.csp.sentinel.slotchain.SlotChainBuilder的檔案,并在該檔案中配置MySlotChainBuilder類的全名,代碼如下。

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

在上述操作完成後,我們在MySlotChainBuilder#build方法中添加斷點,然後啟動項目,在正常情況下,程式會在該斷點停下。但是因為我們并未配置開關降級規則,是以還看不到效果。

為了驗證開關降級效果,我們通過寫死方式添加一個開關配置。建立SpringBoot配置類,并在配置類的初始化方法中調用SwitchRuleManager#loadRules API添加開關降級規則,代碼如下。

深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

上述代碼配置了一個開關降級規則,配置了該規則的status字段值為open,該開關降級規則隻控制接口(資源)“/v1/test/demo”。

注意:這種配置方式隻适用于本地測試,在實際項目中需要通過動态配置實作。

小結

本篇主要介紹如何使用Spring AOP實作開關降級,以及擴充Sentinel實作開關降級。

使用Spring AOP實作開關降級的缺點是配置不靈活:如果讓一個開關控制多個接口,則無法實作動态為開關添加或移除其管理的接口;如果讓一個開關僅控制一個接口,則需要多個開關配置,不易于管理。

在不使用Sentinel的項目中,使用Spring AOP實作開關降級是一種不錯的方式,而如果在項目中已經使用了Sentinel,建議采用擴充Sentinel實作開關降級,并結合動态配置,實作更為靈活的開關降級。

本文給大家講解的内容是深度解析微服務高并發實作開關降級 :擴充Sentinel實作開關降級

  • 下篇文章給大家講解的内容是深度解析微服務高并發動态資料源 :實作規則動态配置的兩種方式,使用Redis動态資料源
  • 感謝大家的支援!

繼續閱讀