阿里 sentinel —— core 模塊淺析

1 什麼是 Sentinel

  • Sentinel 是 2018 年, 阿里開源的一個輕量級流量控制組件
  • 它以流量爲切入點,從限流、熔斷降級、系統負載等多個維度來保證服務端的穩定性
    • 限流(flowslot):指定某個接口最大 QPS 或 最大併發線程數,當超過指定值時,會採用幾種限流策略
      • 通過 FlowRule.controlBehavior 字段指定
      • 直接拒絕(0)
      • 預熱(1):當突然有大流量來時,會逐漸提高流量限制的閾值,最終才達到指定值。用來應對服務端初始化資源時和初始化資源後,它的流量負載能力不一樣的場景
      • 流量規整(2):使得流量按規定的 QPS 進入資源,其餘的等待(有最大等待時間)
      • 預熱 + 流量規整(3)
    • 熔斷降級(degradeslot):當某個資源的平均響應時間或異常比例超過指定值時拒絕請求
    • 系統負載:當應用的 QPS、併發線程數、CPU 使用率、平均響應時間等達到指定值時拒絕請求

2 Sentinel 核心概念簡介

2.1 resource

  • 資源是對受保護的某一方法或代碼塊的唯一標識,用 resourceName 來表示

2.2 context

  • 用 context 來構成資源調用的鏈路

2.3 slot

  • 它是 Sentinel 功能實現的核心,通過不同的 slot 來做不同維度的保護,如 flowSlot 做限流保護、degradeSlot 做熔斷降級保護、paramSlot 做熱點參數限流保護、systemSlot 做系統負載保護、statisticSlot 收集 Metrics 數據等

2.4 slotChain

  • 由多個 slot 串聯成的一個調用鏈,這樣使得所有定義的 slot 按一定的順序執行

2.5 slotChainBuilder

  • 通過不同的 slotChainBuilder 來創建不同的 slotChain,默認爲 DefaultSlotChainBuilder,可以通過 SPI 接口擴展自定義的 slotChainBuilder

2.6 Node

  • 通過不同的 Node 收集 Metrics 數據,各個 Slot 就是使用 Node 中的數據來做保護判斷的,如 QPS、併發線程數都被實時的收集在不同的 Node 中

3 Sentinel 擴展點

3.1 InitFunc

  • 通過實現 InitFunc 接口,並且在 META-INF/services 目錄下的 com.alibaba.csp.sentinel.init.InitFunc 文件中指定該實現類全名
  • 當第一次資源調用的時候,就會通過 Env 類中的 static 塊加載到,並且運行 init 方法
  • 所以我們可以在項目中創建 InitFunc 實例,並指定
    • 如通過 InitFunc 實例來初始化配置數據源
    • 如 sentinel-parameter-flow-control 包中就通過此擴展點註冊了 ParamFlowStatisticEntryCallback 和 ParamFlowStatisticExitCallback

3.2 StatisticSlotCallbackRegistry

  • StatisticSlot 中會調用此類來獲取所有的 SlotEntryCallback、SlotExitCallback 實例 的 onPass、onBlocked 、onExit 來處理其他的一些成功或阻塞後的一些邏輯
  • 如 ParamFlowStatisticCallback 來處理熱點參數的線程數信息
  • 註冊動作可以通過 InitFunc 方式來添加 Callback 實例

3.3 SlotChainBuilder

  • 通過實現 SlotChainBuilder 接口,並且在 META-INF/services 目錄下的 com.alibaba.csp.sentinel.slotchain.SlotChainBuilder 文件中指定該實現類全名
  • 當第一次資源調用的時候,就會通過 SlotChainProvider 類加載此文件中指定的類,如果有多個實例,就會選取一個最爲唯一的 SlotChainBuilder 類
  • 所以我們可以在項目中創建 SlotChainBuilder 實例,並指定
    • 如我們需要自定義某種 slot,那就需要通過自定義 SlotChainBuilder 來將我們定義的 slot 加入到 slotChain 中
    • 如 sentinel-parameter-flow-control 包中就通過此擴展點實現了 HotParamSlotChainBuilder,將 ParmaFlowSlot 加入到 slotChain 中

3.4 MetricExtension

  • 通過實現 MetricExtension 接口,並且在 META-INF/services 目錄下的 com.alibaba.csp.sentinel.metric.extension.MetricExtension 文件中指定該實現類全名
  • 當第一次資源調用的時候,就會通過 MetricExtensionProvider 類加載此文件中指定的類,並放入 metricExtensions 列表中
  • 目前 在 MetricEntryCallback、MetricExitCallback 中就會調用所有的 MetricExtension 實例
  • 作用:可以通過它對 statistic 做擴展

4 Slot 簡介

4.1 NodeSelectorSlot

  • 生成 contextName 對應的 resource 屬性,並存入 map 中
    • 此 map 爲 實例屬性,又因爲 一個 slot 實例對應一個 resourceName
    • 所以這個 map 存儲的是一個 resource(value) 下,對應的多個 contextName(key)
    • 這樣的話,一個 resource 就會對應 多個 DefaultNode 了!因爲一個 resource 下的每一個 contextName 都會對應不同的 DefaultNode
    • 那怎麼通過 resource 下所有的 statistics 呢?用 ClusterNode!
  • 設置 context 的 curNode 屬性爲 新建的 DefaultNode(resourceWrapper,null)
  • 往後傳的 node 就是 DefaultNode(resourceWrapper,null) 了!
  • Sentinel 通過 NodeSelectorSlot 建立不同資源間的調用的關係,並且通過 ClusterNodeBuilderSlot記錄每個資源的實時統計信息。

4.2 ClusterBuilderSlot

  • 生成 resourceName(key) 對應的 clusterNode 實例屬性,並存入 map 中
  • 設置 DefaultNode(resourceWrapper,null) 的 clusterNode 屬性
  • 如果 origin != “”,則設置 這個 clusterNode 對應的 originNodeMap 實例屬性
    • 即將同一個 resource 中的 clusterNode 按 origin 細分爲 多個 originNode
    • 爲了使統計針對 origin 粒度的信息
    • 現在的粒度有:contextName(這個粒度可大可小),origin,resource

4.3 LogSlot

  • 記錄日誌

4.4 StatisticSlot

  • 記錄不同粒度的 matrix
//這裏 EntryType 起作用了
if (resourceWrapper.getEntryType() == EntryType.IN) {
    // Add count for global inbound entry node for global statistics.
    Constants.ENTRY_NODE.increaseThreadNum();//只要是 IN 的都會進入這個全局節點
    Constants.ENTRY_NODE.addPassRequest(count);
}

4.5 SystemSlot

  • 系統規則保護:thread、rt、load、cpu。可以自定義設置閾值
  • 則通過系統的狀態,例如 load1 等,來控制總的入口流量
//在此 Slot 中,對 statisticSlot 統計的 ENTRY_NODE 信息進行了規則保護
Constants.ENTRY_NODE

4.6 AuthoritySlot

  • 權限過濾:黑白名單,判斷 origin 是否是被拒絕的 origin

4.7 FlowSlot

  • FlowSlot 通過使用預設的規則,來判斷正在訪問的請求是否應該被阻塞
  • 如果任意預設的規則被觸發了,就會拋 FlowException 異常,用戶可以通過捕獲這個異常來處理他們想要的邏輯
  • 每一個 FlowRule 主要由:grade、strategy 、path 組成
    • grade:0 表示線程指標,1 表示 QPS 指標。這兩個指標都會被實時收集
    • stage:主要用來處理不斷堆積的線程問題,當一個資源訪問耗時的時候
    • 流量規整:使得每段時間只有固定的線程通過

4.8 DegradeSlot

  • 處理降級規則

5 Sentinel 使用案例

5.1 原始接口使用

//其中 contextName對應調用鏈路入口名稱,通過 contextName 形成一條調用鏈
public void foo() {
    Entry entry = null;
    try {
        //ContextUtil.enter("contextName","originName");//可以不用
        entry = SphU.entry("abc");//"abc" 爲被保護資源的唯一標識
        // resource that need protection
    } catch (BlockException blockException) {
        //因爲遍歷的時候會拋 BlockException,所以在這裏處理 blocked handle logic
        //降級、限流、系統保護等拒絕後的邏輯
    } catch (Throwable bizException) {
        // business exception
    } finally {
        // ensure finally be executed
        if (entry != null){
            entry.exit();//必須是同一線程釋放,否則拋 ErrorEntryFreeException 異常
        }
        //ContextUtil.exit();
    }
}
//--------------------- 各個方法分析
//對 resourceName 資源做保護
//1、
//獲取 context,如果之前沒有設置,則會使用 sentinel_default_context 來生成 context
//這裏有個要注意的地方,一個 contextName 可能就對應多個資源了!
//context = new Context(node, name); node 爲 context 中的 entranceNode 屬性

//2、
//生成 resourceName 對應的 slotChain,並存入 map 中
//即,同一個 resourceName 肯定會走同一條 slotChain!
//這個 map 的最大值爲 6000,也就是說一個項目最後定義 6000 個 resourceName

//3、
//生成 resource、slotChain、context 對應的 Entry,最爲返回值,爲了處理 context 等信息

//4、
//遍歷 slotChain,執行相應的方法(功能)
entry = SphU.entry("resourceName");

entry.exit();//清除 context 信息
ContextUtil.exit();//清除線程信息

5.2 註解使用

  • value: 資源名

  • entryType:IN:表示進入系統的流量,OUT:表示出口流量,即調用其他資源。systemSlot 只對 IN 類型的流量生效,目前沒有其它 slot 使用這個屬性

  • blockHandler:被拒絕之後走的處理方法,對應原始接口的 BlockException 後的邏輯

  • blockHandlerClass:定義 blockHandler 所在的類,如果定義了這個,則 blockHandler 對應的類必須是 static 方法(因爲這樣 反射的話就不用指定 類的實例了)

  • blockHandler 方法的返回類型必須和資源的返回類型一樣,參數類型必須必資源的參數多一個 BlockException 參數

  • fallback:處理 blockHandler 不能處理的異常

  • fallbackClass:同理 blockHandlerClass

  • blockHandler 方法的返回類型必須和資源的返回類型一樣,參數類型可以加一個 Throwable 參數,也可以不加

  • defaultFallback:如果之前的 fallback 流程走不通,則走這個 defaultFallback 流程,只是一個備選方案,也對應 fallbackClass。方法參數最多加個 Throwable 參數

  • exceptionsToTrace:非 BlockException 異常,不通過 handleFallback 處理的 異常

  • exceptionsToIgnore:非 BlockException 異常,通過 handleFallback 處理的 異常,且異常會被跟蹤

@SentinelResource(value = "hello")
public String hello(String name) {
    return "hello:" + name;
}
  • 如果要用註解,需要添加依賴,並且要將 SentinelResourceAspect 類注入容器中以使得註解生效
@Configuration
public class SentinelAspect {
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        System.out.println("init SentinelResourceAspect");
        return new SentinelResourceAspect();
    }
}
--- 添加依賴
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-annotation-aspectj</artifactId>
	<version>1.6.3</version>
</dependency>

參考

sentinel-core-1.6.3

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章