Sentinel源码解析

痴心易碎 提交于 2021-01-16 12:51:04


@author:zxw

@email:[502513206@qq.com](mailto:502513205@qq.com)

@ Jishou University 

------

## 1.前言

限流可以说是高并发中比较重要的一个问题了,面试的时候也经常有关此类的问题,刚好最近在学习限流算法时,苦于找不到好的实现,想起以前用过的sentinel框架里面就有限流的功能,所以顺道来学习下sentinel中限流的实现。

## 2.源码解析

我们先来看看Sentinel怎么配置限流策略,在FlowRule对象中,通过配置`controlBehavior`属性就可以指定限流策略了,默认使用默认的限流策略。

`private int controlBehavior = RuleConstant.CONTROL_BEHAVIOR_DEFAULT;`

```java
private static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("addUser");
    // 默认填写qps的阈值控制方式
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    // 配置限流策略
    // Rate limiter control behavior. 0. default(reject directly), 1. warm up, 2. rate limiter, 3. warm up + rate limiter
        rule.setControlBehavior(2);
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
```

前面生成的废话源码,这边我们直接跳过,直接跳到最核心的ruleMap构建中

`FlowRuleManager.buildFlowRuleMap`在这里会对限流规则rule对象进行一系列的校验,然后组装map,我们直接跳到`TrafficShapingController rater = generateRater(rule);`代码,这里生成我们的限流类

```java
public static <K> Map<K, List<FlowRule>> buildFlowRuleMap(List<FlowRule> list, Function<FlowRule, K> groupFunction,
                                                              Predicate<FlowRule> filter, boolean shouldSort) {
        Map<K, List<FlowRule>> newRuleMap = new ConcurrentHashMap<>();
        if (list == null || list.isEmpty()) {
            return newRuleMap;
        }
        Map<K, Set<FlowRule>> tmpMap = new ConcurrentHashMap<>();

        for (FlowRule rule : list) {
            // 校验
            if (!isValidRule(rule)) {
                RecordLog.warn("[FlowRuleManager] Ignoring invalid flow rule when loading new flow rules: " + rule);
                continue;
            }
            if (filter != null && !filter.test(rule)) {
                continue;
            }
            if (StringUtil.isBlank(rule.getLimitApp())) {
                // 默认使用default名称
                rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);
            }
            // 指定我们的限流规则
            TrafficShapingController rater = generateRater(rule);
            rule.setRater(rater);

            K key = groupFunction.apply(rule);
            if (key == null) {
                continue;
            }
            Set<FlowRule> flowRules = tmpMap.get(key);

            if (flowRules == null) {
                // Use hash set here to remove duplicate rules.
                flowRules = new HashSet<>();
                tmpMap.put(key, flowRules);
            }

            flowRules.add(rule);
        }
        Comparator<FlowRule> comparator = new FlowRuleComparator();
        for (Entry<K, Set<FlowRule>> entries : tmpMap.entrySet()) {
            List<FlowRule> rules = new ArrayList<>(entries.getValue());
            if (shouldSort) {
                // Sort the rules.
                Collections.sort(rules, comparator);
            }
            newRuleMap.put(entries.getKey(), rules);
        }

        return newRuleMap;
    }
```

往下看看限流规则生成,可以看到这里判断流量控制的方式是基于qps还是thread,默认为qps

```java
private static TrafficShapingController generateRater(/*@Valid*/ FlowRule rule) {
        if (rule.getGrade() == RuleConstant.FLOW_GRADE_QPS) {
            // 根据我们配置的controlBehavior值来判断使用哪个限流方式
            switch (rule.getControlBehavior()) {
                case RuleConstant.CONTROL_BEHAVIOR_WARM_UP:
                    // 预热
                    return new WarmUpController(rule.getCount(), rule.getWarmUpPeriodSec(),
                        ColdFactorProperty.coldFactor);
                case RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER:
                    // 流速
                    return new RateLimiterController(rule.getMaxQueueingTimeMs(), rule.getCount());
                case RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
                    // 流速与预热
                    return new WarmUpRateLimiterController(rule.getCount(), rule.getWarmUpPeriodSec(),
                        rule.getMaxQueueingTimeMs(), ColdFactorProperty.coldFactor);
                case RuleConstant.CONTROL_BEHAVIOR_DEFAULT:
                default:
                    // Default mode or unknown mode: default traffic shaping controller (fast-reject).
            }
        }
    // 立即拒绝策略
        return new DefaultController(rule.getCount(), rule.getGrade());
```

现在我们可以来看看不同的限流策略对应哪些值了,根据代码来看一共有如下4种限流策略

```java
public static final int CONTROL_BEHAVIOR_DEFAULT = 0; // 默认,超过限制拒绝
    public static final int CONTROL_BEHAVIOR_WARM_UP = 1; // 预热
    public static final int CONTROL_BEHAVIOR_RATE_LIMITER = 2; // 流速控制
    public static final int CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER = 3; // 预热与流速相结合
```

有关限流的接口为`TrafficShapingController`,看看此接口的实现类就是我们上面对应的4中限流种类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GzY5LanF-1610763638293)(Sentinel源码解析 - 限流算法种类简介.assets/image-20210115215418440.png)]

这下我们就知道了如果要配置指定的限流策略可以通过`rule.setControlBehavior(2);`语句设置对应的限流方式,还可以通过`rule.setGrade(RuleConstant.FLOW_GRADE_QPS);`方法设置是QPS还是thread方式限流,有关具体限流的实现之后博文再讲。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!