sentinel設計思想

首先咱們看一下Sentinel項目的整個結構:version:1.6.0app

* sentinel-core 核心模塊,限流、降級、系統保護等都在這裏實現
* sentinel-dashboard 控制檯模塊,能夠對鏈接上的sentinel客戶端實現可視化的管理
* sentinel-transport 傳輸模塊,提供了基本的監控服務端和客戶端的API接口,以及一些基於不一樣庫的實現
* sentinel-extension 擴展模塊,主要對DataSource進行了部分擴展實現
* sentinel-adapter 適配器模塊,主要實現了對一些常見框架的適配
* sentinel-demo 樣例模塊,可參考怎麼使用sentinel進行限流、降級等
* sentinel-benchmark 基準測試模塊,對核心代碼的精確性提供基準測試

底層原理:sentinel 入口是 SphU.entry建立框架

private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)

    throws BlockException {

    Context context = ContextUtil.getContext();

    if (context instanceof NullContext) {

        // The {@link NullContext} indicates that the amount of context has exceeded the threshold,

        // so here init the entry only. No rule checking will be done.

        return new CtEntry(resourceWrapper, null, context);

    }

  

  

    if (context == null) {

        // Using default context.

        context = MyContextUtil.myEnter(Constants.CONTEXT\_DEFAULT\_NAME, "", resourceWrapper.getType());

    }

  

  

    // Global switch is close, no rule checking will do.

    if (!Constants.ON) {

        return new CtEntry(resourceWrapper, null, context);

    }

  

  

    ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);

  

  

    /\*

     \* Means amount of resources (slot chain) exceeds {@link Constants.MAX\_SLOT\_CHAIN\_SIZE},

     \* so no rule checking will be done.

     \*/

    if (chain == null) {

        return new CtEntry(resourceWrapper, null, context);

    }

  

  

    Entry e = new CtEntry(resourceWrapper, chain, context);

    try {

        chain.entry(context, resourceWrapper, null, count, prioritized, args);

    } catch (BlockException e1) {

        e.exit(count, args);

        throw e1;

    } catch (Throwable e1) {

        // This should not happen, unless there are errors existing in Sentinel internal.

        RecordLog.info("Sentinel unexpected exception", e1);

    }

    return e;

}

這個方法能夠分爲如下幾個部分:less

* 1.對參數和全局配置項作檢測,若是不符合,不會再進行後面的限流檢測,不然進入下面的檢測流程。
* 2.根據包裝過的資源對象獲取對應的SlotChain
* 3.執行SlotChain的entry方法

    * 3.1.若是SlotChain的entry方法拋出了BlockException,則將該異常繼續向上拋出
    * 3.2.若是SlotChain的entry方法正常執行了,則最後會將該entry對象返回
* 4.若是上層方法捕獲了BlockException,則說明請求被限流了,不然請求能正常執行

其中比較重要的是第二、3兩個步驟,咱們來分解一下這兩個步驟。建立SlotChain默認的實現類爲 DefaultProcessorSlotChain:鏈表實現的責任鏈測試

private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)

    throws BlockException {

    Context context = ContextUtil.getContext();

    if (context instanceof NullContext) {

        // The {@link NullContext} indicates that the amount of context has exceeded the threshold,

        // so here init the entry only. No rule checking will be done.

        return new CtEntry(resourceWrapper, null, context);

    }

  

  

    if (context == null) {

        // Using default context.

        context = MyContextUtil.myEnter(Constants.CONTEXT\_DEFAULT\_NAME, "", resourceWrapper.getType());

    }

  

  

    // Global switch is close, no rule checking will do.

    if (!Constants.ON) {

        return new CtEntry(resourceWrapper, null, context);

    }

  

  

    ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);

  

  

    /\*

     \* Means amount of resources (slot chain) exceeds {@link Constants.MAX\_SLOT\_CHAIN\_SIZE},

     \* so no rule checking will be done.

     \*/

    if (chain == null) {

        return new CtEntry(resourceWrapper, null, context);

    }

  

  

    Entry e = new CtEntry(resourceWrapper, chain, context);

    try {

        chain.entry(context, resourceWrapper, null, count, prioritized, args);

    } catch (BlockException e1) {

        e.exit(count, args);

        throw e1;

    } catch (Throwable e1) {

        // This should not happen, unless there are errors existing in Sentinel internal.

        RecordLog.info("Sentinel unexpected exception", e1);

    }

    return e;

}
* NodeSelectorSlot 負責收集資源的路徑,並將這些資源的調用路徑,以樹狀結構存儲起來,用於根據調用路徑來限流降級;
* ClusterBuilderSlot 則用於存儲資源的統計信息以及調用者信息,例如該資源的 RT, QPS, thread count 等等,這些信息將用做爲多維度限流,降級的依據;
* StatistcSlot 則用於記錄,統計不一樣緯度的 runtime 信息;
* FlowSlot 則用於根據預設的限流規則,以及前面 slot 統計的狀態,來進行限流;
* AuthorizationSlot 則根據黑白名單,來作黑白名單控制;
* DegradeSlot 則經過統計信息,以及預設的規則,來作熔斷降級;
* SystemSlot 則經過系統的狀態,例如 load1 等,來控制總的入口流量;
*

執行完業務邏輯處理後,調用了fireEntry()方法,由此觸發了下一個節點的entry方法。此時咱們就知道了sentinel的責任鏈就是這樣傳遞的:每一個Slot節點執行完本身的業務後,會調用fireEntry來觸發下一個節點的entry方法。ui

相關文章
相關標籤/搜索