Sentine-限流降级权限

作者: spilledyear | 来源:发表于2019-01-27 21:07 被阅读74次

    流量控制

    直接拒绝

    • provider
    @Override
    public User testFlowQPSDefault(Long userId) {
        return new User(100L, "三爷");
    }
    
    • consumer
    /**
     * 限流测试 QPS 直接拒绝
     */
    @Scheduled(cron = "0/10 * *  * * ? ")
    public void testFlowQPSDefault() {
        for (int i = 1; i <= 10; i++) {
            try {
                log.info("{} : {} ", i, userService.testFlowQPSDefault(100L).getUserName());
            } catch (Exception e) {
                log.error("第 {} 个限流失败", i);
            }
        }
    }
    
    • 限流规则
    [{"app":"titans-provider3","clusterMode":false,"controlBehavior":0,"count":6.0,"grade":1,"key":"1548575169161","limitApp":"titans-consumer","maxQueueingTimeMs":500,"resource":"@DUBBO@com.zto.sentinel.service.UserService:testFlowQPSDefault(java.lang.Long)","strategy":0,"warmUpPeriodSec":10}]
    
    • 结果分析
      这个很好理解,每秒通过6个,其它的直接拒绝
    2019-01-27 15:50:40.003 : 1 : 三爷 
    2019-01-27 15:50:40.005 : 2 : 三爷 
    2019-01-27 15:50:40.006 : 3 : 三爷 
    2019-01-27 15:50:40.007 : 4 : 三爷 
    2019-01-27 15:50:40.009 : 5 : 三爷 
    2019-01-27 15:50:40.011 : 6 : 三爷 
    2019-01-27 15:50:40.016 : 第 7 个限流失败
    2019-01-27 15:50:40.020 : 第 8 个限流失败
    2019-01-27 15:50:40.025 : 第 9 个限流失败
    2019-01-27 15:50:40.031 : 第 10 个限流失败
    2019-01-27 15:50:50.001 : 1 : 三爷 
    2019-01-27 15:50:50.003 : 2 : 三爷 
    2019-01-27 15:50:50.005 : 3 : 三爷 
    2019-01-27 15:50:50.006 : 4 : 三爷 
    2019-01-27 15:50:50.008 : 5 : 三爷 
    2019-01-27 15:50:50.010 : 6 : 三爷 
    2019-01-27 15:50:50.014 : 第 7 个限流失败
    2019-01-27 15:50:50.021 : 第 8 个限流失败
    2019-01-27 15:50:50.026 : 第 9 个限流失败
    2019-01-27 15:50:50.030 : 第 10 个限流失败
    2019-01-27 15:51:00.004 : 1 : 三爷 
    2019-01-27 15:51:00.006 : 2 : 三爷 
    2019-01-27 15:51:00.008 : 3 : 三爷 
    2019-01-27 15:51:00.009 : 4 : 三爷 
    2019-01-27 15:51:00.011 : 5 : 三爷 
    2019-01-27 15:51:00.013 : 6 : 三爷 
    2019-01-27 15:51:00.018 : 第 7 个限流失败
    2019-01-27 15:51:00.022 : 第 8 个限流失败
    2019-01-27 15:51:00.026 : 第 9 个限流失败
    2019-01-27 15:51:00.030 : 第 10 个限流失败
    

    预热冷启

    • provider
    @Override
    public User testFlowQPSWarmUp(Long userId) {
        return new User(100L, "三爷");
    }
    
    • consumer
    /**
     * 限流测试 QPS Warm UP
     */
    @Scheduled(fixedDelay = 50000)
    public void testFlowQPSWarmUp() throws InterruptedException {
        for (int i = 1; i <= Integer.MAX_VALUE; i++) {
            // 前10个请求,让qps在一个非常低的水平
            if (i <= 10) {
                long time = System.currentTimeMillis() % 2000;
                if (time < 500) {
                    time = 500;
                }
                Thread.sleep(time);
            }
    
            if (i > 10) {
                // 流量突然增大,为了方便测试,这里设置sleep为10之内,qps阈值为20,对于测试来说够了
                Thread.sleep(System.currentTimeMillis() % 10);
            }
            try {
                log.info("{} : {} ", i, userService.testFlowQPSWarmUp(100L).getUserName());
            } catch (Exception e) {
            }
        }
    }
    
    • 限流规则
    [{"app":"titans-provider3","clusterMode":false,"controlBehavior":1,"count":20,"grade":1,"key":"1548575169161","limitApp":"titans-consumer","maxQueueingTimeMs":500,"resource":"@DUBBO@com.zto.sentinel.service.UserService:testFlowQPSDefault(java.lang.Long)","strategy":0,"warmUpPeriodSec":10}]
    
    • 结果分析
    【前10个请求qps很低】
    2019-01-27 16:48:29.947  : 1 : 三爷 
    2019-01-27 16:48:31.897  : 2 : 三爷 
    2019-01-27 16:48:33.795  : 3 : 三爷 
    2019-01-27 16:48:35.592  : 4 : 三爷 
    2019-01-27 16:48:37.184  : 5 : 三爷 
    2019-01-27 16:48:38.369  : 6 : 三爷 
    2019-01-27 16:48:38.870  : 7 : 三爷 
    2019-01-27 16:48:39.744  : 8 : 三爷 
    2019-01-27 16:48:41.492  : 9 : 三爷 
    2019-01-27 16:48:42.985  : 10 : 三爷 
    
    【qps突增加,在接下来的10s,要将QPS从一个很低的值增加要20,下面统计了接下来十几秒内每秒的QPS数量】
    
    【42--3】
    【43--6】
    【44--7】
    【45--7】
    【46--7】
    【47--8】
    【48--9】
    【49--9】
    【50--10】
    【51--12】
    【52--14】
    【53--17】
    【54--20】
    【55--20】
    【56--20】
    【57--20】
    
    【从上面的结果可以看到,到54秒的时候,QPS达到了阈值20,之后就一直保持在20,这样算一下好像 42 到 54 秒超过了10秒中,这是因为第10个请求完成的时间是16:48:42.985,这接近43秒了,这样看偏差会更小一点】
    

    匀速排队

    count=10,maxQueueingTimeMs = 20000, count=10代表1s可以通过10个请求,所以每个请求平均100ms,maxQueueingTimeMs = 20000代表队中的请求最长等待时间为20s,也就是 大概能给处理 每秒/200 个请求

    • provider
      如果时dubbo服务,主要设置dubbo服务的timeout >= 20000
    /**
     * QPS 匀速排队
     *
     * @param userId
     * @return
     */
    @Override
    public User testFlowQPSPace(Long userId) throws InterruptedException {
        return new User(100L, "三爷");
    }
    
    • consumer
      consumer 需要修改不同的并发数来达到测试效果, 并发数分别为:100、200、250
    /**
     * 限流测试 QPS 匀速排队
     */
    @Scheduled(fixedDelay = 100000)
    public void testFlowQPSPace() throws InterruptedException {
        for (int i = 1; i <= 250; i++) {
            new Thread(() -> {
                try {
                    TimeUnit.MILLISECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    log.info("{} ", userService.testFlowQPSPace(100L).getUserName());
                } catch (Exception e) {
                    log.error(e.getMessage());
                    log.error("请求被限流");
                }
            }).start();
        }
    }
    
    • 限流规则
      count=10,maxQueueingTimeMs = 20000, count=10代表1s可以通过10个请求,所以每个请求平均100ms,maxQueueingTimeMs = 20000代表队中的请求最长等待时间为20s,也就是 大概能给处理 每秒/200 个请求,当超过200请求/s 时,多出来的请求就会被直接拒绝
    [{"app":"titans-provider3","clusterMode":false,"controlBehavior":2,"count":10,"grade":1,"key":"1548575169161","limitApp":"titans-consumer","maxQueueingTimeMs":20000,"resource":"@DUBBO@com.zto.sentinel.service.UserService:testFlowQPSPace(java.lang.Long)","strategy":0,"warmUpPeriodSec":10}]
    
    • 结果分析
    【100个并发,即 100请求/s 情况】
    【观察时间,可以发现请求时匀速通过,每100ms一个,耗时大概10s】
    2019-01-27 18:08:08.269  : 1 : 三爷 
    2019-01-27 18:08:08.368  : 2 : 三爷 
    2019-01-27 18:08:08.469  : 3 : 三爷 
    2019-01-27 18:08:08.568  : 4 : 三爷 
    2019-01-27 18:08:08.668  : 5 : 三爷 
    2019-01-27 18:08:08.768  : 6 : 三爷 
    2019-01-27 18:08:08.868  : 7 : 三爷 
    2019-01-27 18:08:08.969  : 8 : 三爷 
    2019-01-27 18:08:09.068  : 9 : 三爷 
    ......省略一些......
    2019-01-27 18:08:17.968  : 98 : 三爷 
    2019-01-27 18:08:18.070  : 99 : 三爷 
    2019-01-27 18:08:18.168  : 100 : 三爷
    
    
    【200个并发,即 200请求/s 情况】
    【观察时间,可以发现请求时匀速通过,每100ms一个,耗时大概20s】
    2019-01-27 18:40:56.498  : 三爷 
    2019-01-27 18:40:56.498  : 三爷 
    2019-01-27 18:40:56.498  : 三爷 
    2019-01-27 18:40:56.575  : 三爷
    2019-01-27 18:40:56.676  : 三爷
    ......省略一些......
    2019-01-27 18:41:15.868  : 三爷 
    2019-01-27 18:41:15.971  :  三爷 
    2019-01-27 18:41:16.071  : 三爷
    
    【220个并发,即 220请求/s 情况,每100ms一个,大概有20个请求被直接降级】
    2019-01-27 18:44:08.782 : 三爷 
    2019-01-27 18:44:08.829 : 三爷 
    2019-01-27 18:44:08.834 : 请求被限流
    2019-01-27 18:44:08.834 : 请求被限流
    2019-01-27 18:44:08.835 : 请求被限流
    2019-01-27 18:44:08.835 : 请求被限流
    2019-01-27 18:44:08.836 : 请求被限流
    2019-01-27 18:44:08.836 : 请求被限流
    2019-01-27 18:44:08.837 : 请求被限流
    2019-01-27 18:44:08.838 : 请求被限流
    2019-01-27 18:44:08.839 : 请求被限流
    2019-01-27 18:44:08.839 : 请求被限流
    2019-01-27 18:44:08.840 : 请求被限流
    2019-01-27 18:44:08.841 : 请求被限流
    2019-01-27 18:44:08.842 : 请求被限流
    2019-01-27 18:44:08.843 : 请求被限流
    2019-01-27 18:44:08.844 : 请求被限流
    2019-01-27 18:44:08.845 : 请求被限流
    2019-01-27 18:44:08.846 : 请求被限流
    2019-01-27 18:44:08.846 : 请求被限流
    2019-01-27 18:44:08.928 : 三爷 
    2019-01-27 18:44:09.020 : 三爷 
    2019-01-27 18:44:09.122 : 三爷 
    2019-01-27 18:44:09.224 : 三爷 
    ......省略一些......
    

    线程数

    • provider
    /**
     * 线程数
     *
     * @param userId
     * @return
     */
    @Override
    public User testFlowThread(Long userId) throws InterruptedException {
        // sleep 1000ms 是为了制造并发场景,其实可以当作时模拟服务调用,在sleep期间可能会堆积大量的请求
        Thread.sleep(1000);
        return new User(100L, "三爷");
    }
    
    • consumer
    @Scheduled(fixedDelay = 20000)
    public void testFlowThread() throws InterruptedException {
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                try {
                    log.info("{} ", userService.testFlowThread(100L).getUserName());
                } catch (Throwable e) {
                    log.error("请求被限流");
                }
            }).start();
        }
    }
    
    • 限流规则
      count=20,代表线程数20为阈值
    [{"app":"titans-provider3","clusterMode":false,"controlBehavior":0,"count":20.0,"grade":0,"key":"1548587521446","limitApp":"titans-consumer","maxQueueingTimeMs":500,"resource":"@DUBBO@com.zto.sentinel.service.UserService:testFlowThread(java.lang.Long)","strategy":0,"warmUpPeriodSec":10}]
    
    • 结果分析
    【通过21个,限流9个,第一次有点偏差?】
    2019-01-27 19:58:05.029  请求被限流
    2019-01-27 19:58:05.031  请求被限流
    2019-01-27 19:58:05.031  请求被限流
    2019-01-27 19:58:05.031  请求被限流
    2019-01-27 19:58:05.032  请求被限流
    2019-01-27 19:58:05.031  请求被限流
    2019-01-27 19:58:05.032  请求被限流
    2019-01-27 19:58:05.032  请求被限流
    2019-01-27 19:58:05.032  请求被限流
    2019-01-27 19:58:06.019  三爷 
    2019-01-27 19:58:06.019  三爷 
    ......省略部分......
    2019-01-27 19:58:06.019  三爷 
    
    【通过20个,限流10个】
    2019-01-27 19:58:25.011 E: 请求被限流
    2019-01-27 19:58:25.013 E: 请求被限流
    2019-01-27 19:58:25.013 E: 请求被限流
    2019-01-27 19:58:25.014 E: 请求被限流
    2019-01-27 19:58:25.014 E: 请求被限流
    2019-01-27 19:58:25.015 E: 请求被限流
    2019-01-27 19:58:25.016 E: 请求被限流
    2019-01-27 19:58:25.015 E: 请求被限流
    2019-01-27 19:58:25.015 E: 请求被限流
    2019-01-27 19:58:25.016 E: 请求被限流
    2019-01-27 19:58:25.965  : 三爷 
    2019-01-27 19:58:25.966  : 三爷 
    ......省略部分......
    2019-01-27 19:58:25.994  : 三爷 
    
    【通过20个,限流10个】
    2019-01-27 19:58:45.001 E: 请求被限流
    2019-01-27 19:58:45.001 E: 请求被限流
    2019-01-27 19:58:45.003 E: 请求被限流
    2019-01-27 19:58:45.004 E: 请求被限流
    2019-01-27 19:58:45.004 E: 请求被限流
    2019-01-27 19:58:45.004 E: 请求被限流
    2019-01-27 19:58:45.004 E: 请求被限流
    2019-01-27 19:58:45.005 E: 请求被限流
    2019-01-27 19:58:45.005 E: 请求被限流
    2019-01-27 19:58:45.006 E: 请求被限流
    2019-01-27 19:58:45.991  : 三爷 
    ......省略部分......
    2019-01-27 19:58:45.995  : 三爷 
    

    链路限流

    -provider

    /**
     * 链路限流,入口为testRefResource01的调用才会记录到 REF_RESOURCE 的限流统计当中
     *
     * @return
     * @throws BlockException
     */
    @Override
    public String testRefResource01() throws BlockException {
        testRefResource();
        return "三爷";
    }
    
    /**
     * 链路限流,入口为testRefResource02的调用不会记录到 REF_RESOURCE 的限流统计当中
     *
     * @return
     * @throws BlockException
     */
    @Override
    public String testRefResource02() throws BlockException {
        testRefResource();
        return "三爷";
    }
    
    /**
     * 链路限流,testRefResource01 和 testRefResource02 方法里面调用了这个方法,会根据REF_RESOURCE上的限流规则的refResource字段来决定是否对他们生效
     *
     * @throws BlockException
     */
    private void testRefResource() throws BlockException {
        Entry entry = SphU.entry("REF_RESOURCE");
        if (entry != null) {
            entry.exit();
        }
    
    }
    
    • consumer
      为了查看限流效果,分别执行以下两个定时任务,为了测试方便,这里写到一起
    /**
     * 入口为testRefResource01的调用才会记录到 REF_RESOURCE 的限流统计当中
     */
    @Scheduled(fixedDelay = 1000)
    public void testRefResource01() {
        for (int i = 1; i <= 10; i++) {
            try {
                log.info("{} : {}", i, userService.testRefResource01());
            } catch (Exception e) {
                log.error("第 {} 个限流失败", i);
            }
        }
    }
    
    /**
     * 入口为testRefResource02的调用不会记录到 REF_RESOURCE 的限流统计当中
     */
    @Scheduled(fixedDelay = 1000)
    public void testRefResource02() {
        for (int i = 1; i <= 10; i++) {
            try {
                log.info("{} : {}", i, userService.testRefResource02());
            } catch (Exception e) {
                log.error("第 {} 个限流失败", i);
            }
        }
    }
    
    [{"app":"titans-provider3","clusterMode":false,"controlBehavior":0,"count":6.0,"grade":1,"key":"1548675382541","limitApp":"titans-consumer","maxQueueingTimeMs":500,"refResource":"@DUBBO@com.zto.sentinel.service.UserService:testRefResource01()","resource":"REF_RESOURCE","strategy":2,"warmUpPeriodSec":10}]
    
    • 结果分析
    【运行定时任务testRefResource01的结果如下,规则生效了】
    2019-01-28 19:45:16.830 : 1 : 三爷
    2019-01-28 19:45:16.831 : 2 : 三爷
    2019-01-28 19:45:16.833 : 3 : 三爷
    2019-01-28 19:45:16.835 : 4 : 三爷
    2019-01-28 19:45:16.837 : 5 : 三爷
    2019-01-28 19:45:16.839 : 6 : 三爷
    2019-01-28 19:45:16.841 : 第 7 个限流失败
    2019-01-28 19:45:16.843 : 第 8 个限流失败
    2019-01-28 19:45:16.845 : 第 9 个限流失败
    2019-01-28 19:45:16.849 : 第 10 个限流失败
    2019-01-28 19:45:17.851 : 1 : 三爷
    2019-01-28 19:45:17.852 : 2 : 三爷
    2019-01-28 19:45:17.854 : 3 : 三爷
    2019-01-28 19:45:17.855 : 4 : 三爷
    2019-01-28 19:45:17.857 : 5 : 三爷
    2019-01-28 19:45:17.858 : 6 : 三爷
    2019-01-28 19:45:17.861 : 第 7 个限流失败
    2019-01-28 19:45:17.863 : 第 8 个限流失败
    2019-01-28 19:45:17.865 : 第 9 个限流失败
    2019-01-28 19:45:17.867 : 第 10 个限流失败
    
    【运行定时任务testRefResource01的结果如下,规则没有生效,符合预期】
    2019-01-28 19:46:38.777  : 1 : 三爷
    2019-01-28 19:46:38.780  : 2 : 三爷
    2019-01-28 19:46:38.781  : 3 : 三爷
    2019-01-28 19:46:38.783  : 4 : 三爷
    2019-01-28 19:46:38.785  : 5 : 三爷
    2019-01-28 19:46:38.786  : 6 : 三爷
    2019-01-28 19:46:38.788  : 7 : 三爷
    2019-01-28 19:46:38.789  : 8 : 三爷
    2019-01-28 19:46:38.791  : 9 : 三爷
    2019-01-28 19:46:38.793  : 10 : 三爷
    2019-01-28 19:46:39.799  : 1 : 三爷
    2019-01-28 19:46:39.805  : 2 : 三爷
    2019-01-28 19:46:39.809  : 3 : 三爷
    2019-01-28 19:46:39.812  : 4 : 三爷
    2019-01-28 19:46:39.815  : 5 : 三爷
    2019-01-28 19:46:39.817  : 6 : 三爷
    2019-01-28 19:46:39.820  : 7 : 三爷
    2019-01-28 19:46:39.823  : 8 : 三爷
    2019-01-28 19:46:39.825  : 9 : 三爷
    2019-01-28 19:46:39.827  : 10 : 三爷
    
    【测试结果符合预期,测试成功】
    

    关联限流

    • provider
    /**
     * 关联限流,读方,对读方设置限流规则 strategy = RuleConstant.STRATEGY_RELATE,refResource = 写方,其中的count代表允许 【写方】每秒通过的请求数
     *
     * @return
     */
    @Override
    public String testRefResourceRelateRead() throws InterruptedException {
        Thread.sleep(300);
        return "三爷";
    }
    
    /**
     * 关联限流,写方
     *
     * @return
     */
    @Override
    public String testRefResourceRelateWrite(int i) throws InterruptedException {
        Thread.sleep(200);
        return "三爷";
    }
    
    • consumer
      下面两个定时任务分别代表读方和写方,为了便于观察结果,按以下顺序进行操作
      1、不设置任何限流规则,启动读方,观察日志输出;
      2、不设置任何限流规则,启动读方,然后启动写方,观察日志输出;
      3、通过provider的代码可以发现,写方的QPS小于5,这时候对读方添加限流规则,count 分别设置小于5,大于5,启动读方,然后启动写方,观察日志输出;
    /**
     * 关联限流,读方, 对读方设置限流规则 strategy = RuleConstant.STRATEGY_RELATE,refResource = 写方,其中的count代表允许 【写方】每秒通过的请求数
     */
    @Scheduled(fixedDelay = 1000)
    public void testRefResourceRelateRead() {
        for (int i = 1; i <= Integer.MAX_VALUE; i++) {
            try {
                log.info("{} : {}", i, userService.testRefResourceRelateRead());
            } catch (Exception e) {
                log.error("读方第 {} 个限流失败", i);
            }
        }
    }
    
    
    /**
     * 关联限流,写方
     */
    @Scheduled(fixedDelay = 1000)
    public void testRefResourceRelateWrite() {
        log.info("写方开始启动");
        for (int i = 1; i <= Integer.MAX_VALUE; i++) {
            try {
                log.info("{} : {}", i, userService.testRefResourceRelateWrite(i));
            } catch (Exception e) {
                log.error("写方第 {} 个限流失败,这个按理来说不会打印", i);
            }
        }
    }
    
    [{"app":"titans-provider3","clusterMode":false,"controlBehavior":0,"count":3.0,"grade":1,"key":"1548679522569","limitApp":"titans-consumer","maxQueueingTimeMs":500,"refResource":"@DUBBO@com.zto.sentinel.service.UserService:testRefResourceRelateWrite(int)","resource":"@DUBBO@com.zto.sentinel.service.UserService:testRefResourceRelateRead()","strategy":1,"warmUpPeriodSec":10}]
    
    
    [{"app":"titans-provider3","clusterMode":false,"controlBehavior":0,"count":6.0,"grade":1,"key":"1548679522569","limitApp":"titans-consumer","maxQueueingTimeMs":500,"refResource":"@DUBBO@com.zto.sentinel.service.UserService:testRefResourceRelateWrite(int)","resource":"@DUBBO@com.zto.sentinel.service.UserService:testRefResourceRelateRead()","strategy":1,"warmUpPeriodSec":10}]
    
    • 结果分析
    1、【不设置规则,只启动读方,日志输出正常,读方没有被限流】
    2、【不设置规则,先启动读方,然后启动写方,日志输出正常,读方没有被限流】
    3、【设置规则,count=3,先启动读方,然后启动写方,在写方启动之后读方开始被完全限流,关闭写方之后读方恢复正常】
    4、【设置规则,count=6,先启动读方,然后启动写方,日志输出正常,读方没有被限流】
    

    熔断降级

    RT

    • provider
    /**
     * 理想情况
     * 平均响应时间阈值为20毫秒,第40个请求的时候,平局响应时间为20毫秒, 接下来的5个请求 sleep 时间为 41,42,43,44,45
     * 这5个请求的RT均超过阈值, 接下来时间窗口内的请求将被直接拒绝  2s
     *
     * <p>
     * 实际情况
     * 考虑服务调用本身的耗时,每个服务调用大概需要1-3ms,这里估算2ms
     *
     * @param userId 这里的userId为1-1000的递增数字
     * @return
     * @throws InterruptedException
     */
    @Override
    public User testDegrRT(Long userId) throws InterruptedException {
        Thread.sleep(userId % 50);
        return new User(100L, "三爷");
    }
    
    • consumer
    /**
     * 测试降级,RT timeWindow 2s, count 20ms,10s执行一次
     */
    @Scheduled(cfixedDelay = 10000)
    public void testDegrRT() {
        for (int i = 1; i <= 1000; i++) {
            try {
                log.info("{} : {} ", i, userService.testDegrRT(Long.valueOf(i)).getUserName());
            } catch (Exception e) {
            }
        }
    }
    
    • 限流规则
      指定时间窗口为2s,阈值为20ms
    [{"app":"titans-provider3","count":20.0,"cut":false,"grade":0,"key":"1548391072645","limitApp":"titans-consumer","passCount":0,"resource":"@DUBBO@com.zto.sentinel.service.UserService","timeWindow":2}]
    
    • 测试结果
    【第一个10s之内的请求数】
    2019-01-25 13:01:00.067   [pool-2-thread-1]   : 1 : 三爷 
    2019-01-25 13:01:00.072   [pool-2-thread-1]   : 2 : 三爷 
    2019-01-25 13:01:00.077   [pool-2-thread-1]   : 3 : 三爷 
    2019-01-25 13:01:00.083   [pool-2-thread-1]   : 4 : 三爷 
    2019-01-25 13:01:00.089   [pool-2-thread-1]   : 5 : 三爷 
    2019-01-25 13:01:00.097   [pool-2-thread-1]   : 6 : 三爷 
    2019-01-25 13:01:00.106   [pool-2-thread-1]   : 7 : 三爷 
    2019-01-25 13:01:00.116   [pool-2-thread-1]   : 8 : 三爷 
    2019-01-25 13:01:00.127   [pool-2-thread-1]   : 9 : 三爷 
    2019-01-25 13:01:00.139   [pool-2-thread-1]   : 10 : 三爷 
    2019-01-25 13:01:00.152   [pool-2-thread-1]   : 11 : 三爷 
    2019-01-25 13:01:00.165   [pool-2-thread-1]   : 12 : 三爷 
    2019-01-25 13:01:00.180   [pool-2-thread-1]   : 13 : 三爷 
    2019-01-25 13:01:00.196   [pool-2-thread-1]   : 14 : 三爷 
    2019-01-25 13:01:00.213   [pool-2-thread-1]   : 15 : 三爷 
    2019-01-25 13:01:00.231   [pool-2-thread-1]   : 16 : 三爷 
    2019-01-25 13:01:00.250   [pool-2-thread-1]   : 17 : 三爷 
    2019-01-25 13:01:00.270   [pool-2-thread-1]   : 18 : 三爷 
    2019-01-25 13:01:00.291   [pool-2-thread-1]   : 19 : 三爷 
    2019-01-25 13:01:00.313   [pool-2-thread-1]   : 20 : 三爷 
    2019-01-25 13:01:00.336   [pool-2-thread-1]   : 21 : 三爷 
    2019-01-25 13:01:00.360   [pool-2-thread-1]   : 22 : 三爷 
    2019-01-25 13:01:00.386   [pool-2-thread-1]   : 23 : 三爷 
    2019-01-25 13:01:00.413   [pool-2-thread-1]   : 24 : 三爷 
    2019-01-25 13:01:00.441   [pool-2-thread-1]   : 25 : 三爷 
    2019-01-25 13:01:00.471   [pool-2-thread-1]   : 26 : 三爷 
    2019-01-25 13:01:00.500   [pool-2-thread-1]   : 27 : 三爷 
    2019-01-25 13:01:00.530   [pool-2-thread-1]   : 28 : 三爷 
    2019-01-25 13:01:00.560   [pool-2-thread-1]   : 29 : 三爷 
    2019-01-25 13:01:00.592   [pool-2-thread-1]   : 30 : 三爷 
    2019-01-25 13:01:00.624   [pool-2-thread-1]   : 31 : 三爷 
    2019-01-25 13:01:00.658   [pool-2-thread-1]   : 32 : 三爷 
    2019-01-25 13:01:00.693   [pool-2-thread-1]   : 33 : 三爷 
    2019-01-25 13:01:00.729   [pool-2-thread-1]   : 34 : 三爷 
    2019-01-25 13:01:00.766   [pool-2-thread-1]   : 35 : 三爷 
    2019-01-25 13:01:00.804   [pool-2-thread-1]   : 36 : 三爷 
    2019-01-25 13:01:00.843   [pool-2-thread-1]   : 37 : 三爷 
    2019-01-25 13:01:00.883   [pool-2-thread-1]   : 38 : 三爷 
    2019-01-25 13:01:00.923   [pool-2-thread-1]   : 39 : 三爷 
    2019-01-25 13:01:00.964   [pool-2-thread-1]   : 40 : 三爷 
    2019-01-25 13:01:01.007   [pool-2-thread-1]   : 41 : 三爷 
    2019-01-25 13:01:01.050   [pool-2-thread-1]   : 42 : 三爷 
    【加上服务调用本身的时间,第37个请求的时候平均响应时间达到了20,后面5个请求的响应时间都超过了20,所以对这5个请求之后的2s之内的请求直接降级】
    
    【2s过后,接下来的5个请求响应时间都大于20(对50取余),所以这5个请求通过后,接下来的请求被直接降级,即 577 -1000 的请求被直接降级了,所以没有打印】
    2019-01-25 13:01:03.078   [pool-2-thread-1]   : 572 : 三爷 
    2019-01-25 13:01:03.103   [pool-2-thread-1]   : 573 : 三爷 
    2019-01-25 13:01:03.129   [pool-2-thread-1]   : 574 : 三爷 
    2019-01-25 13:01:03.156   [pool-2-thread-1]   : 575 : 三爷 
    2019-01-25 13:01:03.183   [pool-2-thread-1]   : 576 : 三爷 
    
    
    【消费端定时任务休息了10s之后继续发送请求,这时候上面总共通过了47个请求,平均响应时间 (42*43/2 + 24*3)/47 + 每个请求实际耗时1-2ms】
    【上面计算的这个结果是大于20的,但是马上又被接下来的请求耗时给平均下去了】
    2019-01-25 13:01:10.004   [pool-2-thread-1]   : 1 : 三爷 
    2019-01-25 13:01:10.007   [pool-2-thread-1]   : 2 : 三爷 
    2019-01-25 13:01:10.011   [pool-2-thread-1]   : 3 : 三爷 
    2019-01-25 13:01:10.017   [pool-2-thread-1]   : 4 : 三爷 
    2019-01-25 13:01:10.025   [pool-2-thread-1]   : 5 : 三爷 
    2019-01-25 13:01:10.032   [pool-2-thread-1]   : 6 : 三爷 
    2019-01-25 13:01:10.039   [pool-2-thread-1]   : 7 : 三爷 
    2019-01-25 13:01:10.049   [pool-2-thread-1]   : 8 : 三爷 
    2019-01-25 13:01:10.060   [pool-2-thread-1]   : 9 : 三爷 
    2019-01-25 13:01:10.071   [pool-2-thread-1]   : 10 : 三爷 
    2019-01-25 13:01:10.084   [pool-2-thread-1]   : 11 : 三爷 
    2019-01-25 13:01:10.097   [pool-2-thread-1]   : 12 : 三爷 
    2019-01-25 13:01:10.112   [pool-2-thread-1]   : 13 : 三爷 
    2019-01-25 13:01:10.129   [pool-2-thread-1]   : 14 : 三爷 
    2019-01-25 13:01:10.146   [pool-2-thread-1]   : 15 : 三爷 
    2019-01-25 13:01:10.163   [pool-2-thread-1]   : 16 : 三爷 
    2019-01-25 13:01:10.182   [pool-2-thread-1]   : 17 : 三爷 
    2019-01-25 13:01:10.202   [pool-2-thread-1]   : 18 : 三爷 
    2019-01-25 13:01:10.223   [pool-2-thread-1]   : 19 : 三爷 
    2019-01-25 13:01:10.244   [pool-2-thread-1]   : 20 : 三爷 
    2019-01-25 13:01:10.267   [pool-2-thread-1]   : 21 : 三爷 
    2019-01-25 13:01:10.291   [pool-2-thread-1]   : 22 : 三爷 
    2019-01-25 13:01:10.315   [pool-2-thread-1]   : 23 : 三爷 
    2019-01-25 13:01:10.340   [pool-2-thread-1]   : 24 : 三爷 
    2019-01-25 13:01:10.368   [pool-2-thread-1]   : 25 : 三爷 
    2019-01-25 13:01:10.395   [pool-2-thread-1]   : 26 : 三爷 
    2019-01-25 13:01:10.424   [pool-2-thread-1]   : 27 : 三爷 
    2019-01-25 13:01:10.453   [pool-2-thread-1]   : 28 : 三爷 
    2019-01-25 13:01:10.485   [pool-2-thread-1]   : 29 : 三爷 
    2019-01-25 13:01:10.518   [pool-2-thread-1]   : 30 : 三爷 
    2019-01-25 13:01:10.551   [pool-2-thread-1]   : 31 : 三爷 
    2019-01-25 13:01:10.585   [pool-2-thread-1]   : 32 : 三爷 
    2019-01-25 13:01:10.621   [pool-2-thread-1]   : 33 : 三爷 
    2019-01-25 13:01:10.657   [pool-2-thread-1]   : 34 : 三爷 
    2019-01-25 13:01:10.695   [pool-2-thread-1]   : 35 : 三爷 
    2019-01-25 13:01:10.732   [pool-2-thread-1]   : 36 : 三爷 
    2019-01-25 13:01:10.770   [pool-2-thread-1]   : 37 : 三爷 
    2019-01-25 13:01:10.810   [pool-2-thread-1]   : 38 : 三爷 
    2019-01-25 13:01:10.851   [pool-2-thread-1]   : 39 : 三爷 
    2019-01-25 13:01:10.893   [pool-2-thread-1]   : 40 : 三爷 
    2019-01-25 13:01:10.936   [pool-2-thread-1]   : 41 : 三爷 
    【前面41个请求和第一个10s类似,不过因为第一个10s内的请求平均耗时大于20s,所以这里的平均响应时间提前达到阈值,即 41 的时候就到了】
    
    【接下来类似,只要平均响应到了20 ,就判断接下来的5个请求是否大于阈值,大于就降级 2s】
    2019-01-25 13:01:12.944   [pool-2-thread-1]   : 556 : 三爷 
    2019-01-25 13:01:12.953   [pool-2-thread-1]   : 557 : 三爷 
    2019-01-25 13:01:12.964   [pool-2-thread-1]   : 558 : 三爷 
    2019-01-25 13:01:12.975   [pool-2-thread-1]   : 559 : 三爷 
    2019-01-25 13:01:12.987   [pool-2-thread-1]   : 560 : 三爷 
    2019-01-25 13:01:13.001   [pool-2-thread-1]   : 561 : 三爷 
    2019-01-25 13:01:13.014   [pool-2-thread-1]   : 562 : 三爷 
    2019-01-25 13:01:13.027   [pool-2-thread-1]   : 563 : 三爷 
    2019-01-25 13:01:13.042   [pool-2-thread-1]   : 564 : 三爷 
    2019-01-25 13:01:13.058   [pool-2-thread-1]   : 565 : 三爷 
    2019-01-25 13:01:13.075   [pool-2-thread-1]   : 566 : 三爷 
    2019-01-25 13:01:13.094   [pool-2-thread-1]   : 567 : 三爷 
    2019-01-25 13:01:13.114   [pool-2-thread-1]   : 568 : 三爷 
    2019-01-25 13:01:13.134   [pool-2-thread-1]   : 569 : 三爷 
    2019-01-25 13:01:13.155   [pool-2-thread-1]   : 570 : 三爷 
    2019-01-25 13:01:13.178   [pool-2-thread-1]   : 571 : 三爷 
    2019-01-25 13:01:13.202   [pool-2-thread-1]   : 572 : 三爷 
    2019-01-25 13:01:13.227   [pool-2-thread-1]   : 573 : 三爷 
    2019-01-25 13:01:13.253   [pool-2-thread-1]   : 574 : 三爷 
    2019-01-25 13:01:13.278   [pool-2-thread-1]   : 575 : 三爷 
    2019-01-25 13:01:13.306   [pool-2-thread-1]   : 576 : 三爷 
    2019-01-25 13:01:13.334   [pool-2-thread-1]   : 577 : 三爷 
    2019-01-25 13:01:13.363   [pool-2-thread-1]   : 578 : 三爷 
    2019-01-25 13:01:13.393   [pool-2-thread-1]   : 579 : 三爷 
    2019-01-25 13:01:13.425   [pool-2-thread-1]   : 580 : 三爷 
    2019-01-25 13:01:13.457   [pool-2-thread-1]   : 581 : 三爷 
    2019-01-25 13:01:13.491   [pool-2-thread-1]   : 582 : 三爷 
    2019-01-25 13:01:13.525   [pool-2-thread-1]   : 583 : 三爷 
    2019-01-25 13:01:13.560   [pool-2-thread-1]   : 584 : 三爷 
    2019-01-25 13:01:13.597   [pool-2-thread-1]   : 585 : 三爷 
    2019-01-25 13:01:13.633   [pool-2-thread-1]   : 586 : 三爷 
    

    异常比例

    这种方式的降级和上面稍有不同,在dubbo服务中,平均RT中的资源可以是接口,也可以时具体的方法,但在和异常相关的降级中,资源只能是方法。 每秒的异常数/每秒的请求量 如果大于阈值,就会在接下来的时间窗口内降级,有一个需要注意的地方,这一秒的请求数达到5之后才会开始计算

    • provider
    /**
     * 理想情况
     * 每100毫秒一个请求,一秒钟可以处理10个请求,阈值设置为0.1,timeWindow为2s
     * <p>
     * 这里每3个请求抛出一个异常,1s之内抛出的异常数大于 10%, 所以会被降级2s , 接下来又是一个周期
     *
     * @param userId
     * @return
     * @throws InterruptedException
     */
    @Override
    public User testDegrRatio(Long userId) throws InterruptedException {
        Thread.sleep(100);
        if (userId % 3 == 0) {
            throw new NullPointerException("手动抛出一个业务异常");
        }
        return new User(100L, "三爷");
    }
    
    • consumer
    @Scheduled(fixedDelay = 10000)
    public void testDegrRatio() {
        for (int i = 1; i <= 100; i++) {
            try {
                log.info("{} : {} ", i, userService.testDegrRatio(Long.valueOf(i)).getUserName());
            } catch (Exception e) {
                if (e instanceof NullPointerException) {
                    log.error("第 {} 个请求被手动抛出业务异常", i);
                }
    
                if (e instanceof RpcException) {
                    log.error("第 {} 个限流失败", i);
                }
            }
        }
    }
    
    • 降级规则
      指定时间窗口为2s,阈值为0.1,
    [{"app":"titans-provider3","count":0.1,"cut":false,"grade":1,"key":"1548558413966","limitApp":"titans-consumer","passCount":0,"resource":"@DUBBO@com.zto.sentinel.service.UserService:testDegrRatio(java.lang.Long)","timeWindow":2}]
    
    • 测试结果
    2019-01-27 13:07:14.584 : 1 : 三爷 
    2019-01-27 13:07:14.687 : 2 : 三爷 
    2019-01-27 13:07:14.790 : 第 3 个请求被手动抛出业务异常
    2019-01-27 13:07:14.891 : 4 : 三爷 
    2019-01-27 13:07:14.992 : 5 : 三爷 
    
    【第3个请求抛出了一个业务异常,但是接下来并没有被直接降级,因为这里还有一个隐藏条件,当这一秒的请求数达到5之后才开始计算,所以第六个请求就被直接降级了】
    【而时间窗口定义为2s,该2s内直接拒绝100个请求】
    2019-01-27 13:07:14.998 : 第 6 个限流失败
    2019-01-27 13:07:15.003 : 第 7 个限流失败
    2019-01-27 13:07:15.007 : 第 8 个限流失败
    2019-01-27 13:07:15.011 : 第 9 个限流失败
    2019-01-27 13:07:15.015 : 第 10 个限流失败
    2019-01-27 13:07:15.019 : 第 11 个限流失败
    2019-01-27 13:07:15.023 : 第 12 个限流失败
    2019-01-27 13:07:15.027 : 第 13 个限流失败
    2019-01-27 13:07:15.031 : 第 14 个限流失败
    2019-01-27 13:07:15.034 : 第 15 个限流失败
    2019-01-27 13:07:15.037 : 第 16 个限流失败
    2019-01-27 13:07:15.041 : 第 17 个限流失败
    2019-01-27 13:07:15.045 : 第 18 个限流失败
    2019-01-27 13:07:15.049 : 第 19 个限流失败
    2019-01-27 13:07:15.053 : 第 20 个限流失败
    2019-01-27 13:07:15.057 : 第 21 个限流失败
    2019-01-27 13:07:15.061 : 第 22 个限流失败
    2019-01-27 13:07:15.064 : 第 23 个限流失败
    2019-01-27 13:07:15.068 : 第 24 个限流失败
    2019-01-27 13:07:15.071 : 第 25 个限流失败
    2019-01-27 13:07:15.074 : 第 26 个限流失败
    2019-01-27 13:07:15.078 : 第 27 个限流失败
    2019-01-27 13:07:15.082 : 第 28 个限流失败
    2019-01-27 13:07:15.086 : 第 29 个限流失败
    2019-01-27 13:07:15.090 : 第 30 个限流失败
    2019-01-27 13:07:15.094 : 第 31 个限流失败
    2019-01-27 13:07:15.098 : 第 32 个限流失败
    2019-01-27 13:07:15.102 : 第 33 个限流失败
    2019-01-27 13:07:15.106 : 第 34 个限流失败
    2019-01-27 13:07:15.110 : 第 35 个限流失败
    2019-01-27 13:07:15.113 : 第 36 个限流失败
    2019-01-27 13:07:15.117 : 第 37 个限流失败
    2019-01-27 13:07:15.120 : 第 38 个限流失败
    2019-01-27 13:07:15.124 : 第 39 个限流失败
    2019-01-27 13:07:15.127 : 第 40 个限流失败
    2019-01-27 13:07:15.130 : 第 41 个限流失败
    2019-01-27 13:07:15.134 : 第 42 个限流失败
    2019-01-27 13:07:15.137 : 第 43 个限流失败
    2019-01-27 13:07:15.141 : 第 44 个限流失败
    2019-01-27 13:07:15.146 : 第 45 个限流失败
    2019-01-27 13:07:15.149 : 第 46 个限流失败
    2019-01-27 13:07:15.153 : 第 47 个限流失败
    2019-01-27 13:07:15.157 : 第 48 个限流失败
    2019-01-27 13:07:15.161 : 第 49 个限流失败
    2019-01-27 13:07:15.164 : 第 50 个限流失败
    2019-01-27 13:07:15.168 : 第 51 个限流失败
    2019-01-27 13:07:15.172 : 第 52 个限流失败
    2019-01-27 13:07:15.176 : 第 53 个限流失败
    2019-01-27 13:07:15.179 : 第 54 个限流失败
    2019-01-27 13:07:15.182 : 第 55 个限流失败
    2019-01-27 13:07:15.186 : 第 56 个限流失败
    2019-01-27 13:07:15.190 : 第 57 个限流失败
    2019-01-27 13:07:15.194 : 第 58 个限流失败
    2019-01-27 13:07:15.197 : 第 59 个限流失败
    2019-01-27 13:07:15.202 : 第 60 个限流失败
    2019-01-27 13:07:15.206 : 第 61 个限流失败
    2019-01-27 13:07:15.210 : 第 62 个限流失败
    2019-01-27 13:07:15.214 : 第 63 个限流失败
    2019-01-27 13:07:15.219 : 第 64 个限流失败
    2019-01-27 13:07:15.225 : 第 65 个限流失败
    2019-01-27 13:07:15.229 : 第 66 个限流失败
    2019-01-27 13:07:15.233 : 第 67 个限流失败
    2019-01-27 13:07:15.237 : 第 68 个限流失败
    2019-01-27 13:07:15.242 : 第 69 个限流失败
    2019-01-27 13:07:15.246 : 第 70 个限流失败
    2019-01-27 13:07:15.251 : 第 71 个限流失败
    2019-01-27 13:07:15.257 : 第 72 个限流失败
    2019-01-27 13:07:15.263 : 第 73 个限流失败
    2019-01-27 13:07:15.268 : 第 74 个限流失败
    2019-01-27 13:07:15.275 : 第 75 个限流失败
    2019-01-27 13:07:15.280 : 第 76 个限流失败
    2019-01-27 13:07:15.284 : 第 77 个限流失败
    2019-01-27 13:07:15.288 : 第 78 个限流失败
    2019-01-27 13:07:15.293 : 第 79 个限流失败
    2019-01-27 13:07:15.298 : 第 80 个限流失败
    2019-01-27 13:07:15.302 : 第 81 个限流失败
    2019-01-27 13:07:15.308 : 第 82 个限流失败
    2019-01-27 13:07:15.312 : 第 83 个限流失败
    2019-01-27 13:07:15.316 : 第 84 个限流失败
    2019-01-27 13:07:15.319 : 第 85 个限流失败
    2019-01-27 13:07:15.323 : 第 86 个限流失败
    2019-01-27 13:07:15.327 : 第 87 个限流失败
    2019-01-27 13:07:15.330 : 第 88 个限流失败
    2019-01-27 13:07:15.334 : 第 89 个限流失败
    2019-01-27 13:07:15.338 : 第 90 个限流失败
    2019-01-27 13:07:15.342 : 第 91 个限流失败
    2019-01-27 13:07:15.345 : 第 92 个限流失败
    2019-01-27 13:07:15.349 : 第 93 个限流失败
    2019-01-27 13:07:15.354 : 第 94 个限流失败
    2019-01-27 13:07:15.358 : 第 95 个限流失败
    2019-01-27 13:07:15.361 : 第 96 个限流失败
    2019-01-27 13:07:15.364 : 第 97 个限流失败
    2019-01-27 13:07:15.367 : 第 98 个限流失败
    2019-01-27 13:07:15.370 : 第 99 个限流失败
    2019-01-27 13:07:15.373 : 第 100 个限流失败
    

    异常数量

    一分钟内的以异常数如果超过一个阈值,在接下来的timeWindow内服务将处于降级状态,如果timeWindow小于60, 结果是不精确的,所以强烈建议将timeWindow的值设置为大于或者等于60

    • provider
    /**
     * 理想情况
     * 每1秒一个请求,一分钟可以处理60个请求,阈值设置为6,每5个请求抛出一个异常,30个请求之后异常数达到阈值,此时耗时30,
     * 然后根据timeWindow进行降级,这时候分两种情况
     * 1、当timeWindow小于60,这时候降级时间是不精确的,不推荐这种做法
     * <p>
     * 2、当timeWindow>=60, 限流时间 从 第一个降级请求开始算,在接下来的timeWindow内,服务将处于降级状态,
     * 例如第一个降级请求时间是:15:01:10.619, timeWindow=70,那么在 15:01:10.619 - 15:02:20.619 这段时间内服务将处于降级状态
     *
     * @param userId
     * @return
     * @throws InterruptedException
     */
    @Override
    public User testDegrCount(Long userId) throws InterruptedException {
        Thread.sleep(1000);
        if (userId % 5 == 0) {
            throw new NullPointerException("手动抛出一个业务异常");
        }
        return new User(100L, "三爷");
    }
    
    • consumer
    /**
     * 测试降级, 一分钟之内业务异常数, timeWindow 40s, count 6
     */
    @Scheduled(fixedDelay = 10000)
    public void testDegrCount() {
        for (int i = 1; i <= 100; i++) {
            try {
                log.info("{} : {} ", i, userService.testDegrCount(Long.valueOf(i)).getUserName());
            } catch (Exception e) {
                if (e instanceof NullPointerException) {
                    log.error("第 {} 个请求被手动抛出业务异常", i);
                }
    
                if (e instanceof RpcException) {
                    log.error("第 {} 个限流失败", i);
                }
            }
        }
    }
    
    • 降级规则
    [{"app":"titans-provider3","count":6.0,"cut":false,"grade":2,"key":"1548569038841","limitApp":"titans-consumer","passCount":0,"resource":"@DUBBO@com.zto.sentinel.service.UserService:testDegrCount(java.lang.Long)","timeWindow":50}]
    
    • 测试结果
      这一步的结果分析可能会更复杂一些,所以一些连续性的日志我会省略,但不影响分析结果
    【13:44:26.187 完成第一个请求】
    
    2019-01-27 13:44:26.187 : 1 : 三爷 
    2019-01-27 13:44:27.189 : 2 : 三爷 
    2019-01-27 13:44:28.189 : 3 : 三爷 
    2019-01-27 13:44:29.191 : 4 : 三爷 
    2019-01-27 13:44:30.196 : 第 5 个请求被手动抛出业务异常
    2019-01-27 13:44:31.199 : 6 : 三爷 
    2019-01-27 13:44:32.202 : 7 : 三爷 
    2019-01-27 13:44:33.203 : 8 : 三爷 
    2019-01-27 13:44:34.204 : 9 : 三爷 
    2019-01-27 13:44:35.207 : 第 10 个请求被手动抛出业务异常
    2019-01-27 13:44:36.208 : 11 : 三爷 
    2019-01-27 13:44:37.210 : 12 : 三爷 
    2019-01-27 13:44:38.211 : 13 : 三爷 
    2019-01-27 13:44:39.212 : 14 : 三爷 
    2019-01-27 13:44:40.214 : 第 15 个请求被手动抛出业务异常
    2019-01-27 13:44:41.216 : 16 : 三爷 
    2019-01-27 13:44:42.217 : 17 : 三爷 
    2019-01-27 13:44:43.218 : 18 : 三爷 
    2019-01-27 13:44:44.220 : 19 : 三爷 
    2019-01-27 13:44:45.223 : 第 20 个请求被手动抛出业务异常
    2019-01-27 13:44:46.224 : 21 : 三爷 
    2019-01-27 13:44:47.225 : 22 : 三爷 
    2019-01-27 13:44:48.227 : 23 : 三爷 
    2019-01-27 13:44:49.228 : 24 : 三爷 
    2019-01-27 13:44:50.230 : 第 25 个请求被手动抛出业务异常
    2019-01-27 13:44:51.232 : 26 : 三爷 
    2019-01-27 13:44:52.233 : 27 : 三爷 
    2019-01-27 13:44:53.234 : 28 : 三爷 
    2019-01-27 13:44:54.236 : 29 : 三爷 
    2019-01-27 13:44:55.238 : 第 30 个请求被手动抛出业务异常
    
    【13:44:55.238 完成第30个请求,耗时30s多一点点,这时候总共抛出了6个业务异常 】
    
    【count=6, timeWindow=40, 因为这时候count已经达到了6,所以第31个请求开始降级】
    2019-01-27 13:44:55.243 : 第 31 个限流失败
    2019-01-27 13:44:55.248 : 第 32 个限流失败
    
    ......这里省略一部分......
    
    2019-01-27 13:44:55.559 : 第 98 个限流失败
    2019-01-27 13:44:55.565 : 第 99 个限流失败
    2019-01-27 13:44:55.569 : 第 100 个限流失败
    
    【请求被直接降级,所以在上一任务最后一个请求完成之后,即13:44:55.569,等待10s,又开始一个新任务,这时候时间刚好过去40s多一点,所以这一轮的请求被直接降级】
    2019-01-27 13:45:05.574 : 第 1 个限流失败
    2019-01-27 13:45:05.578 : 第 2 个限流失败
    
    ......这里省略一部分......
    
    2019-01-27 13:45:05.936 : 第 98 个限流失败
    2019-01-27 13:45:05.939 : 第 99 个限流失败
    2019-01-27 13:45:05.943 : 第 100 个限流失败
    
    【又是一轮任务,这时候时间过去50s多一点,还在一分钟之内,所以请求被直接降级】
    2019-01-27 13:45:15.948 : 第 1 个限流失败
    2019-01-27 13:45:15.952 : 第 2 个限流失败
    
    ......这里省略一部分......
    
    2019-01-27 13:45:16.326 : 第 98 个限流失败
    2019-01-27 13:45:16.329 : 第 99 个限流失败
    2019-01-27 13:45:16.333 : 第 100 个限流失败
    
    【这里又开始了一轮任务,其实还是有点疑问,按理来说,这时候一分钟已经结束了,应该不会被限流,因为是计算有一些误差】
    2019-01-27 13:45:26.349 : 第 1 个限流失败
    2019-01-27 13:45:26.356 : 第 2 个限流失败
    
    ......这里省略一部分......
    
    2019-01-27 13:45:26.709 : 第 98 个限流失败
    2019-01-27 13:45:26.713 : 第 99 个限流失败
    2019-01-27 13:45:26.716 : 第 100 个限流失败
    
    【上一轮降级完成之后,又开始下一轮降级】
    2019-01-27 13:45:37.718 : 1 : 三爷 
    2019-01-27 13:45:38.719 : 2 : 三爷 
    2019-01-27 13:45:39.721 : 3 : 三爷 
    2019-01-27 13:45:40.722 : 4 : 三爷 
    2019-01-27 13:45:41.724 : 第 5 个请求被手动抛出业务异常
    2019-01-27 13:45:42.725 : 6 : 三爷 
    2019-01-27 13:45:43.726 : 7 : 三爷 
    2019-01-27 13:45:44.728 : 8 : 三爷 
    2019-01-27 13:45:45.729 : 9 : 三爷 
    

    考虑到这里需要根据不同的timeWindow考虑各种情况,下面是一个结果汇总

    当 timeWindow = 20 的时候, 第1个请求 完成时间  14:47:03.402, 第30个请求完成时间 14:47:32.483。接下来就是降级,在 14:48:04.031 的时候还处于降级状态,在 14:48:15.033 的时候处于非降级状态
    
    当 timeWindow = 30 的时候, 第1个请求 完成时间  14:43:27.979, 第30个请求完成时间 14:43:57.054。接下来就是降级,在 14:44:49.285 的时候还处于降级状态,在 14:45:00.287 的时候处于非降级状态
    
    当 timeWindow = 40 的时候, 第1个请求 完成时间  14:53:12.703, 第30个请求完成时间 14:53:41.834。接下来就是降级,在 14:54:13.409 的时候还处于降级状态,在 14:54:24.411 的时候处于非降级状态
    
    当 timeWindow = 50 的时候, 第1个请求 完成时间  14:56:01.244, 第30个请求完成时间 14:56:30.345。接下来就是降级,在 14:57:12.310 的时候还处于降级状态,在 14:57:23.315 的时候处于非降级状态
    
    【当timeWindow>=60, 限流时间 从 第一个降级请求开始算,在接下来的timeWindow内,服务将处于降级状态, 例如第一个降级请求时间是:15:01:10.619, timeWindow=70,那么在 15:01:10.619 - 15:02:20.619 这段时间内服务将处于降级状态】
    当 timeWindow = 60 的时候, 第1个请求 完成时间  15:00:41.495, 第30个请求完成时间 15:01:10.619。接下来就是降级,在 15:02:03.071 的时候还处于降级状态,在 15:02:14.075 的时候处于非降级状态
    当 timeWindow = 60 的时候, 第1个请求 完成时间  15:02:14.075, 第30个请求完成时间 15:02:43.140。接下来就是降级,在 15:03:35.314 的时候还处于降级状态,在 15:03:46.316 的时候处于非降级状态     
    
    当 timeWindow = 70 的时候, 第1个请求 完成时间  15:05:08.084, 第30个请求完成时间 15:05:37.145。接下来就是降级,在 15:06:39.727 的时候还处于降级状态,在 15:06:50.730 的时候处于非降级状态
    当 timeWindow = 70 的时候, 第1个请求 完成时间  15:06:50.730, 第30个请求完成时间 15:07:19.775。接下来就是降级,在 15:08:22.343 的时候还处于降级状态,在 15:08:33.345 的时候处于非降级状态
    

    从上面的结果可以看到,timeWindow 在 小于60 的时候, 降级时间是没有规律的,即降级死不精确的,当timeWindow>=60, 限流时间 从 第一个降级请求开始算,在接下来的timeWindow内,服务将处于降级状态, 例如第一个降级请求时间是:15:01:10.619, timeWindow=70,那么在 15:01:10.619 - 15:02:20.619 这段时间内服务将处于降级状态。

    权限控制

    权限控制用于控制哪些调用方可以通过请求,比如指定服务A只有服务B才可以调用,或者只有服务B不可以调用,通过规则中得limitApp来控制

    白名单

    • provider
    /**
     * 权限测试,黑名单,只有titans-consumer,titans-consumer2 才能调用
     *
     * @param userId
     * @return
     */
    @Override
    public User testAuthWhite(Long userId) {
        return new User(100L, "三爷");
    }
    
    • consumer
    /**
     * 权限测试 白名单,只有titans-consumer,titans-consumer2 才能调用,其它都不可以调用
     */
    @Scheduled(fixedDelay = 10000)
    public void testAuthWhite() {
        for (int i = 1; i <= 10; i++) {
            try {
                log.info("{} : {} ", i, userService.testAuthWhite(100L).getUserName());
            } catch (Exception e) {
                log.error("第 {} 个限流失败", i);
            }
        }
    }
    
    • 权限规则
    [{"app":"titans-provider3","key":"1548592173001","limitApp":"titans-consumer,titans-consumer2","resource":"@DUBBO@com.zto.sentinel.service.UserService:testAuthWhite(java.lang.Long)","strategy":0}]
    
    • 结果分析
    【调用方是 titans-consumer 时,调用成功】
    
    【调用方是 titans-consumer2 时,调用成功】
    
    【调用方是 titans-consumer3 时,调用失败】
    

    黑名单

    • provider
    /**
     * 权限测试,黑名单,只有titans-consumer,titans-consumer2 不能调用
     *
     * @param userId
     * @return
     */
    @Override
    public User testAuthBlack(Long userId) {
        return new User(100L, "三爷");
    }
    
    • consumer
    @Scheduled(fixedDelay = 10000)
    public void testAuthBlack() {
        for (int i = 1; i <= 10; i++) {
            try {
                log.info("{} : {} ", i, userService.testAuthBlack(100L).getUserName());
            } catch (Exception e) {
                log.error("第 {} 个限流失败", i);
            }
        }
    }
    
    • 权限规则
    [{"app":"titans-provider3","key":"1548592326969","limitApp":"titans-consumer,titans-consumer2","resource":"@DUBBO@com.zto.sentinel.service.UserService:testAuthBlack(java.lang.Long)","strategy":1}]
    
    • 结果分析
    【调用方是 titans-consumer 时,调用失败】
    
    【调用方是 titans-consumer2 时,调用失败】
    
    【调用方是 titans-consumer3 时,调用成功】
    
    【调用方是 titans-consumer4 时,调用成功】
    

    相关文章

      网友评论

        本文标题:Sentine-限流降级权限

        本文链接:https://www.haomeiwen.com/subject/wuumjqtx.html