专栏首页码匠的流水账聊聊sentinel的FlowSlot

聊聊sentinel的FlowSlot

本文主要研究一下sentinel的FlowSlot

FlowSlot

com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java

public class FlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args)
        throws Throwable {

        FlowRuleManager.checkFlow(resourceWrapper, context, node, count);

        fireEntry(context, resourceWrapper, node, count, args);
    }

    @Override
    public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        fireExit(context, resourceWrapper, count, args);
    }

}

FlowRuleManager.checkFlow

com/alibaba/csp/sentinel/slots/block/flow/FlowRuleManager.java

    public static void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count)
        throws BlockException {
        List<FlowRule> rules = flowRules.get(resource.getName());
        if (rules != null) {
            for (FlowRule rule : rules) {
                if (!rule.passCheck(context, node, count)) {
                    throw new FlowException(rule.getLimitApp());
                }
            }
        }
    }
  • 这里调用FlowRule的passCheck方法

FlowRule

com/alibaba/csp/sentinel/slots/block/flow/FlowRule.java

/***
 * <p>
 *     Each flow rule is mainly composed of three factors: <strong>grade</strong>,
 * <strong>strategy</strong> and <strong>controlBehavior</strong>.
 * </p>
 * <ul>
 *     <li>The {@link #grade} represents the threshold type of flow control (by QPS or thread count).</li>
 *     <li>The {@link #strategy} represents the strategy based on invocation relation.</li>
 *     <li>The {@link #controlBehavior} represents the QPS shaping behavior (actions on incoming request when QPS
 *     exceeds the threshold).</li>
 * </ul>
 *
 * @author jialiang.linjl
 * @author Eric Zhao
 */
public class FlowRule extends AbstractRule {

    public static final String LIMIT_APP_DEFAULT = "default";
    public static final String LIMIT_APP_OTHER = "other";

    public FlowRule(){
        super();
        setLimitApp(LIMIT_APP_DEFAULT);
    }

    /**
     * The threshold type of flow control (0: thread count, 1: QPS).
     */
    private int grade = RuleConstant.FLOW_GRADE_QPS;

    /**
     * Flow control threshold count.
     */
    private double count;

    /**
     * Flow control strategy based on invocation chain.
     *
     * {@link RuleConstant#STRATEGY_DIRECT} for direct flow control (by origin);
     * {@link RuleConstant#STRATEGY_RELATE} for relevant flow control (with relevant resource);
     * {@link RuleConstant#STRATEGY_CHAIN} for chain flow control (by entrance resource).
     */
    private int strategy = RuleConstant.STRATEGY_DIRECT;

    /**
     * Reference resource in flow control with relevant resource.
     */
    private String refResource;

    /**
     * Rate limiter control behavior.
     * 0. default, 1. warm up, 2. rate limiter
     */
    private int controlBehavior = RuleConstant.CONTROL_BEHAVIOR_DEFAULT;

    private int warmUpPeriodSec = 10;

    /**
     * Max queueing time in rate limiter behavior.
     */
    private int maxQueueingTimeMs = 500;

    private Controller controller;

    //......

    @Override
    public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
        String limitApp = this.getLimitApp();
        if (limitApp == null) {
            return true;
        }

        String origin = context.getOrigin();
        Node selectedNode = selectNodeByRequesterAndStrategy(origin, context, node);
        if (selectedNode == null) {
            return true;
        }

        return controller.canPass(selectedNode, acquireCount);
    }

    private Node selectNodeByRequesterAndStrategy(String origin, Context context, DefaultNode node) {
        // The limit app should not be empty.
        String limitApp = this.getLimitApp();

        if (limitApp.equals(origin)) {
            if (strategy == RuleConstant.STRATEGY_DIRECT) {
                return context.getOriginNode();
            }

            String refResource = this.getRefResource();
            if (StringUtil.isEmpty(refResource)) {
                return null;
            }

            if (strategy == RuleConstant.STRATEGY_RELATE) {
                return ClusterBuilderSlot.getClusterNode(refResource);
            }

            if (strategy == RuleConstant.STRATEGY_CHAIN) {
                if (!refResource.equals(context.getName())) {
                    return null;
                }
                return node;
            }

        } else if (LIMIT_APP_DEFAULT.equals(limitApp)) {
            if (strategy == RuleConstant.STRATEGY_DIRECT) {
                return node.getClusterNode();
            }
            String refResource = this.getRefResource();
            if (StringUtil.isEmpty(refResource)) {
                return null;
            }

            if (strategy == RuleConstant.STRATEGY_RELATE) {
                return ClusterBuilderSlot.getClusterNode(refResource);
            }

            if (strategy == RuleConstant.STRATEGY_CHAIN) {
                if (!refResource.equals(context.getName())) {
                    return null;
                }
                return node;
            }

        } else if (LIMIT_APP_OTHER.equals(limitApp) && FlowRuleManager.isOtherOrigin(origin, getResource())) {
            if (strategy == RuleConstant.STRATEGY_DIRECT) {
                return context.getOriginNode();
            }

            String refResource = this.getRefResource();
            if (StringUtil.isEmpty(refResource)) {
                return null;
            }
            if (strategy == RuleConstant.STRATEGY_RELATE) {
                return ClusterBuilderSlot.getClusterNode(refResource);
            }

            if (strategy == RuleConstant.STRATEGY_CHAIN) {
                if (!refResource.equals(context.getName())) {
                    return null;
                }
                if (node != null) {
                    return node;
                }
            }
        }

        return null;
    }

    //......
}
  • 这里首先通过selectNodeByRequesterAndStrategy查找对应的node
  • 之后调用controller.canPass进行限流判断,controller根据不同参数有不同实现类,默认是DefaultController,其余两个为PaceController、WarmUpController
  • controlBehavior有3种,分别是RuleConstant.CONTROL_BEHAVIOR_DEFAULT,直接拒绝;RuleConstant.CONTROL_BEHAVIOR_WARM_UP,冷启动;RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER,均速器。

DefaultController

com/alibaba/csp/sentinel/slots/block/flow/controller/DefaultController.java

public class DefaultController implements Controller {

    double count = 0;
    int grade = 0;

    public DefaultController(double count, int grade) {
        super();
        this.count = count;
        this.grade = grade;
    }

    @Override
    public boolean canPass(Node node, int acquireCount) {
        int curCount = avgUsedTokens(node);
        if (curCount + acquireCount > count) {
            return false;
        }

        return true;
    }

    private int avgUsedTokens(Node node) {
        if (node == null) {
            return -1;
        }
        return grade == RuleConstant.FLOW_GRADE_THREAD ? node.curThreadNum() : (int)node.passQps();
    }

}
  • 默认主要是依据当前node的线程数或qps来判断

小结

  • sentinel的FlowSlot的默认的限流方式有两个维度,一个是基于线程数,一个是基于qps
  • 基于qps的还有其他两种限流策略,一种是冷启动,一个是匀速器
  • 冷启动适用于需要时间准备资源的请求,匀速器则控制请求以均匀的速度通过

doc

  • FlowSlot
  • 流量控制

本文分享自微信公众号 - 码匠的流水账(geek_luandun),作者:码匠乱炖

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-08-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 聊聊jest的NodeChecker

    jest-common-6.3.1-sources.jar!/io/searchbox/client/config/discovery/NodeChecker....

    codecraft
  • 聊聊jest的NodeChecker

    jest-common-6.3.1-sources.jar!/io/searchbox/client/config/discovery/NodeChecker....

    codecraft
  • 聊聊hystrix的fallback

    hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/AbstractCommand.java

    codecraft
  • 腾讯课堂 IMWeb 七天前端求职提升营 Day 2

    本次的系列博文主要是针对 腾讯课堂七天前端求职提升营 课程中,所推送的面试题目及编程练习的一次汇总,期间还包括三次直播课的分享,均由腾讯导师给大家讲解,该系列博...

    Nian糕
  • Leetcode 【553、609、856、1003、1023】

    这道题是给一个数组,各个数字连除,通过加括号,使得除操作的结果最大。刚开始想着是遍历所有加括号的方式,然后求出最大结果。但是,发现加括号的规律很麻烦。

    echobingo
  • mybatis-plus/mybatis 自定义 sql 语句、动态 sql

    MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。在 Java ...

    create17
  • 【CodeForces 624C】Graph and String

    n个表示abc三个字符的点,所有a和b是相连的,所有b和c是相连的,所有相同的是相连的,现在给你n个点和他们之间的m条边,判断是否存在这样的字符串,存在则给出一...

    饶文津
  • 1043. 输出PATest(20)

    给定一个长度不超过10000的、仅由英文字母构成的字符串。请将字符重新调整顺序,按“PATestPATest….”这样的顺序输出,并忽略其它字符。当然,六种字符...

    AI那点小事
  • 聊聊artemis的confirmationWindowEnabled

    本文主要研究一下artemis的confirmationWindowEnabled

    codecraft
  • 聊聊artemis的confirmationWindowEnabled

    本文主要研究一下artemis的confirmationWindowEnabled

    codecraft

扫码关注云+社区

领取腾讯云代金券