【sentinel】深入淺出之原理篇FlowSlot

FlowSlot則用于根據(jù)預(yù)設(shè)的限流規(guī)則,以及前面 slot 統(tǒng)計的狀態(tài),來進(jìn)行限流。
官方文檔:如何使用Sentinel

流控規(guī)則

public class FlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
                      boolean prioritized, Object... args) throws Throwable {
        //流控檢查
        checkFlow(resourceWrapper, context, node, count, prioritized);
        fireEntry(context, resourceWrapper, node, count, prioritized, args);
    }

    void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {
        // 獲取該Resource對應(yīng)配置的流控規(guī)則 一個resource可以指定多個規(guī)則
        Map<String, List<FlowRule>> flowRules = FlowRuleManager.getFlowRuleMap();
        List<FlowRule> rules = flowRules.get(resource.getName());
        if (rules != null) {
            for (FlowRule rule : rules) {
                //規(guī)則逐一校驗
                if (!canPassCheck(rule, context, node, count, prioritized)) {
                    throw new FlowException(rule.getLimitApp(), rule);
                }
            }
        }
    }

    //檢查是否通過
    boolean canPassCheck(FlowRule rule, Context context, DefaultNode node, int count, boolean prioritized) {
        return FlowRuleChecker.passCheck(rule, context, node, count, prioritized);
    }
    @Override
    public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        fireExit(context, resourceWrapper, count, args);
    }
}

在流控檢查的時候,判斷是否對該Resource有配置規(guī)則,如果配置了流控規(guī)則,則逐一檢查配置規(guī)則。在檢查規(guī)則的時候,又分為集群控流或者單機(jī)控流,集群控流或者單機(jī)控流具體文檔參考:http://www.itdecent.cn/p/a52bf4073873
在流控的時候,首先要根據(jù)請求的Resource和請求策略(詳細(xì)見上圖),選擇流控節(jié)點(diǎn),再根據(jù)不同的流控策略,選擇不同的Controller去判斷是否通過。

private static boolean passLocalCheck(FlowRule rule, Context context, DefaultNode node, int acquireCount,
                                      boolean prioritized) {
    Node selectedNode = selectNodeByRequesterAndStrategy(rule, context, node);
    if (selectedNode == null) {
        return true;
    }
    //判斷是否通過
    return rule.getRater().canPass(selectedNode, acquireCount);
}


//根據(jù)請求選擇節(jié)點(diǎn)
static Node selectNodeByRequesterAndStrategy(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node) {
    // The limit app should not be empty.
    String limitApp = rule.getLimitApp();
    int strategy = rule.getStrategy();
    String origin = context.getOrigin();
    if (limitApp.equals(origin) && filterOrigin(origin)) {
        if (strategy == RuleConstant.STRATEGY_DIRECT) {
            // Matches limit origin, return origin statistic node.
            return context.getOriginNode();
        }
        return selectReferenceNode(rule, context, node);
    } else if (RuleConstant.LIMIT_APP_DEFAULT.equals(limitApp)) {
        if (strategy == RuleConstant.STRATEGY_DIRECT) {
            // Return the cluster node.
            return node.getClusterNode();
        }
        return selectReferenceNode(rule, context, node);
    } else if (RuleConstant.LIMIT_APP_OTHER.equals(limitApp)
        && FlowRuleManager.isOtherOrigin(origin, rule.getResource())) {
        if (strategy == RuleConstant.STRATEGY_DIRECT) {
            return context.getOriginNode();
        }
        return selectReferenceNode(rule, context, node);
    }
    return null;
}

Controller.png

根據(jù)配置FlowRule配置的controlBehavior選擇不同的Controller
對應(yīng)關(guān)系:

    1. default(reject directly) DefaultController
    1. warm up WarmUpController
    1. rate limiter RateLimiterController
    1. warm up + rate limiter WarmUpRateLimiter

在默認(rèn)的Controller中,首先獲取當(dāng)前的線程數(shù),或者QPS數(shù),當(dāng)當(dāng)前的線程數(shù)或者QPS+申請的數(shù)量>配置的總數(shù),則不通過,如果當(dāng)前線程數(shù)或者QPS+申請的數(shù)量<=配置的總數(shù),則直接通過。


public class DefaultController implements TrafficShapingController {

    private static final int DEFAULT_AVG_USED_TOKENS = 0;
    private double count;
    private int grade;
    @Override
    public boolean canPass(Node node, int acquireCount) {
        return canPass(node, acquireCount, false);
    }

    @Override
    public boolean canPass(Node node, int acquireCount, boolean prioritized) {
        //獲取當(dāng)前node節(jié)點(diǎn)的線程數(shù)或者請求的qps總數(shù)
        int curCount = avgUsedTokens(node);
        //當(dāng)前請求數(shù)+申請總數(shù)是否>該資源配置的總數(shù)
        if (curCount + acquireCount > count) {
            return false;
        }
        return true;
    }

    //獲取當(dāng)前node節(jié)點(diǎn)的線程數(shù)或者請求的qps總數(shù)
    private int avgUsedTokens(Node node) {
        if (node == null) {
            return DEFAULT_AVG_USED_TOKENS;
        }
        return grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int) node.passQps();
    }

    private void sleep(int timeMillis) {
        try {
            Thread.sleep(timeMillis);
        } catch (InterruptedException e) {
            // Ignore.
        }
    }
}

和其他Slot一樣,F(xiàn)lowRule的配置在FlowRuleManager#loadRules (List<FlowRule> rules)的,最終更新由FlowPropertyListener來完成。

public static void loadRules(List<FlowRule> rules) {
       currentProperty.updateValue(rules);
}
private static final class FlowPropertyListener implements PropertyListener<List<FlowRule>> {

    @Override
    public void configUpdate(List<FlowRule> value) {
        Map<String, List<FlowRule>> rules = FlowRuleUtil.buildFlowRuleMap(value);
        if (rules != null) {
            flowRules.clear();
            flowRules.putAll(rules);
        }
        RecordLog.info("[FlowRuleManager] Flow rules received: " + flowRules);
    }

    @Override
    public void configLoad(List<FlowRule> conf) {
        Map<String, List<FlowRule>> rules = FlowRuleUtil.buildFlowRuleMap(conf);
        if (rules != null) {
            flowRules.clear();
            flowRules.putAll(rules);
        }
        RecordLog.info("[FlowRuleManager] Flow rules loaded: " + flowRules);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、引子 前面介紹了SystemSlot(系統(tǒng)規(guī)則檢查)和AuthoritySlot(授權(quán)規(guī)則檢查),下面接著分析...
    橘子_好多灰閱讀 2,595評論 1 5
  • 最近在負(fù)責(zé)做網(wǎng)關(guān)類系統(tǒng),需要考慮做限流熔斷功能,基于QPS,基于線程數(shù),對于集群,單機(jī)做限流,熔斷,而Sentin...
    一滴水的堅持閱讀 5,185評論 1 7
  • feisky云計算、虛擬化與Linux技術(shù)筆記posts - 1014, comments - 298, trac...
    不排版閱讀 4,332評論 0 5
  • 摘要:在開發(fā)高并發(fā)系統(tǒng)時有三把利器用來保護(hù)系統(tǒng):緩存、降級和限流。而有些場景并不能用緩存和降級來解決,因此需有一種...
    落羽成霜丶閱讀 2,232評論 0 18
  • 曾杰 今天主要做了招商的一個情景模擬,下午對之前培訓(xùn)的產(chǎn)品知識進(jìn)行了一個全面的復(fù)習(xí)。雖然我是做會戰(zhàn)方面的工作,但是...
    杰出的人閱讀 127評論 0 0

友情鏈接更多精彩內(nèi)容