zoukankan      html  css  js  c++  java
  • 十五、Sentinel实现限流降级(2)

    一、降级规则

    官网

    gibhub降级

    1. 基本介绍

    img

    • RT(平均响应时间,秒级)

    平均响应时间超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级窗口期过后关闭断路器

    • RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)

    异常比列(秒级)
    QPS >=5且比例(秒级统计)超过阈值时,触发降级,时间窗口结束后,关闭降级

    1.1进一步说明

    Sentinel的断路器是没有半开状态的

    Sentinel熔断隆级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高) ,对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。

    当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。

    半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用,具体参考Hystrix

    1.2 复习Hystrix

    img

    2. 降级策略实战

    2.1RT是什么

    • 平均响应时间( DEGRADE_GRADE_RT ):当1s内持续进入5个请求,对应时刻的平均响应时间(秒级)均超过阈值( count ,以ms为单位),那么在接下的时间窗口( DegradeRule中的
      timewindow,以s为单位)之内,对这个方法的调用都会自动地熔断(抛出
      DegradeException )。注意Sentinel默认统计的RT上限是4900 ms,超出此阈值的都会算作4900 ms,若需要变更此上限可以通过启动配置项-Dcsp.sentine1.statistic.max. rt=xxx来配置。

    在这里插入图片描述

    测试
    配置降级规则
    在这里插入图片描述

        @GetMapping("/testD")
        public String testD() {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("testD 测试RT");
            return "----testD";
        }
    

    用Jmeter压测
    然后浏览器http://127.0.0.1:8401/testD发现无法访问了
    代码

    • 按照上述配置,

    永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,
    如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了
    后续我停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK

    2.2 异常比例

    介绍

    异常比例( DEGRADE_GRADE_EXCEPTION_RATIO ):当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值( DegradeRule中的count )之后,资源进入降级状态,即在接下的时间窗口( DegradeRule中的timewindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%- 100%。
    在这里插入图片描述
    测试
    在这里插入图片描述

    @GetMapping("/testD")
        public String testD()
        {
    
            log.info("testD 测试RT");
            int age = 10/0;
            return "------testD";
        }
    

    运行Jmeter测试
    浏览器中输入http://127.0.0.1:8401/testD
    已经熔断在这里插入图片描述

    2.3 熔断数

    异常数( DEGRADF_GRADE_EXCEPTION_cOuNT ):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timewindow小于60s,则结束熔断状态后仍可能再进入熔断状态。时间窗口一定要大于60s
    在这里插入图片描述
    测试
    在这里插入图片描述

    controller控制层代码

    @GetMapping("/testE")
    public String testE()
    {
        log.info("testE 测试异常数");
        int age = 10/0;
        return "------testE 测试异常数";
    }
    

    浏览器http://localhost:8401/testE
    http://localhost:8401/testE,第一次访问绝对报错,因为除数不能为零,
    我们看到error窗口,但是达到5次报错后,进入熔断后降级。

    二、@SentinelResource

    1. 兜底方法

    兜底方法分两种

    • 系统默认 :

      之前的例子,限流出问题后,都是用sentinel系统默认的提示: Blocked by Sentinel (flow limiting)
      我们能不能自定?类似hystrix,某个方法出问题了,就找对应的兜底降级方法?

    • 客户自定义

      从HystrixCommand到SentinelResource
      从HystrixCommand到哨兵资源

    兜底方法

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2) {
        //int age = 10/0;
        return "------testHotKey";
    }
     
    //兜底方法
    public String deal_testHotKey (String p1, String p2, BlockException exception){
        return "------deal_testHotKey,o(╥﹏╥)o";  
    }
    

    测试代码

    @RestController
    public class RateLimitController {
    
        @GetMapping("/byResource")
        @SentinelResource(value = "byResource", blockHandler = "handleException")
        public CommonResult byResource() {
            return new CommonResult(200, "按照资源名称限流测试", new Payment(2020L, "serial001"));
        }
    
        @GetMapping("/byResource/exection")
        @SentinelResource(value = "byResourceForExection", blockHandler = "handleException")
        public CommonResult byResourceForExection() {
            int i = 10 / 0;
            return new CommonResult(200, "按照异常数做降级", new Payment(2020L, "serial001"));
        }
    
        public CommonResult handleException(BlockException exception) {
            return new CommonResult(444, exception.getClass().getCanonicalName() + "	 服务不可用");
        }
    
        @GetMapping("/rateLimit/byUrl")
        @SentinelResource(value = "byUrl")
        //注意如果使用url进行限流降级那么SentinelResource配置的blockHandler将无效
        public CommonResult byUrl() {
            return new CommonResult(200, "按照byUrl限流测试", new Payment(2020L, "serial002"));
        }
    
        //CustomerBlockHandler
        @GetMapping("/rateLimit/customerBlockHandler")
        @SentinelResource(value = "customerBlockHandler",
                blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2")
        public CommonResult customerBlockHandler() {
            return new CommonResult(200, "按照客户自定义限流测试", new Payment(2020L, "serial003"));
        }
    }
    
    

    2. value属性测试

    配置
    在这里插入图片描述
    访问
    在这里插入图片描述
    注意资源名称要和@SentinelResource()的value属性相同才会限流

    3. blockHandler

    包括限流降级等都可以使用 注意 要根据@SentinelResource中的value属性进行配置规则 根据url不会有效果

    替换默认显示Blocked by Sentinel (flow limiting)为我们自定义的
    参考上边代码 返回值参数要一致并且在参数中添加BlockException exception

    4. 自定义处理类

    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.atguigu.springcloud.entities.CommonResult;
    import com.atguigu.springcloud.entities.Payment;
    
    /**
     * @author 夏天
     */
    public class CustomerBlockHandler {
    
        public static CommonResult handlerException(BlockException exception) {
            return new CommonResult(444, "按照客户自定义的Glogal 全局异常处理 ---- 1", new Payment(2020L, "serial003"));
        }
    
        public static CommonResult handlerException2(BlockException exception) {
            return new CommonResult(444, "按照客户自定义的Glogal 全局异常处理 ---- 2", new Payment(2020L, "serial003"));
        }
    }
    

    使用处理类

    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handlerException2")
    public CommonResult customerBlockHandler()
    {
        return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
    }
    

    配置
    在这里插入图片描述

    测试

    http://127.0.0.1:8401/rateLimit/customerBlockHandler
    当点击过快时候触发限制

    在这里插入图片描述

    5. 统一处理

    你知道Sentinel限流、降级的统一处理吗?

    # 只包含主要配置其余省略
    spring:
      cloud:
        sentinel:
          servlet:
            blockPage: https://www.baidu.com/ #配置统一处理页面
    

    三、热点key限流

    官方介绍:github热点key限流

    1 配置

    1.1普通版

    在这里插入图片描述
    在这里插入图片描述
    注意

    资源名要对应 @SentinelResource中的value才会有效果
    浏览器继续使用@getMapper中的路径进行访问 http://127.0.0.1:8401/testHotKey?p1=1

      @GetMapping("/testHotKey")
        @SentinelResource(value = "testHotKeyB", blockHandler = "deal_testHotKey")
        //value 唯一即可 规范一般为方法名 blockHandler如果不配置页面直接抛出信息
        public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                                 @RequestParam(value = "p2", required = false) String p2) {
            return "----testHotKey";
        }
    
        //返回值 请求参数一致 并且添加上 BlockException exception 异常
        public String deal_testHotKey(String p1, String p2, BlockException exception) {
            return "----deal_testHotKey, o(╥﹏╥)o"; // sentinel的默认提示都是: Blocked by Sentinel (flow limiting)
        }
    

    测试

    http://127.0.0.1:8401/testHotKey?p1=1
    根据配置1秒中的QPS的阈值为1次 所以点击过快会出现错误提示,这个提示是通过@SentinelResource注解自定义的
    注意
    资源名要对应 @SentinelResource中的value才会有效果 请注意看边的配置

    在这里插入图片描述

    1.2 高级版

    上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流

    需求

    我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样
    假如当p1的值等于5时,它的阈值可以达到200

    实现

    在这里插入图片描述
    结论

    当p1等于5的时候,阈值变为200
    当p1不等于5的时候,阈值就是平常的1
    前提条件:热点参数的注意点,参数必须是基本类型或者String

    手贱添加异常看看…

    @sentinelResource
    处理的是sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;

    RuntimeException
    int age = 10/0,这个是java运行时报出的运行时异常RunTimeException(其他异常也不管),@SentinelResource不管

    总结
    @sentinelResource主管配置出错,运行出错该走异常走异常

    四、系统规则

    先看看官网介绍:gibhub系统自适应限流
    系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

    系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

    系统规则支持以下的模式:

    • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。
    • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
    • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
      并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
    • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
      原理
      先用经典图来镇楼:
      在这里插入图片描述

    我们把系统处理请求的过程想象为一个水管,到来的请求是往这个水管灌水,当系统处理顺畅的时候,请求不需要排队,直接从水管中穿过,这个请求的RT是最短的;反之,当请求堆积的时候,那么处理请求的时间则会变为:排队时间 + 最短处理时间。

    • 推论一: 如果我们能够保证水管里的水量,能够让水顺畅的流动,则不会增加排队的请求;也就是说,这个时候的系统负载不会进一步恶化。
      我们用 T 来表示(水管内部的水量),用RT来表示请求的处理时间,用P来表示进来的请求数,那么一个请求从进入水管道到从水管出来,这个水管会存在 P * RT 个请求。换一句话来说,当 T ≈ QPS * Avg(RT) 的时候,我们可以认为系统的处理能力和允许进入的请求个数达到了平衡,系统的负载不会进一步恶化。

    接下来的问题是,水管的水位是可以达到了一个平衡点,但是这个平衡点只能保证水管的水位不再继续增高,但是还面临一个问题,就是在达到平衡点之前,这个水管里已经堆积了多少水。如果之前水管的水已经在一个量级了,那么这个时候系统允许通过的水量可能只能缓慢通过,RT会大,之前堆积在水管里的水会滞留;反之,如果之前的水管水位偏低,那么又会浪费了系统的处理能力。

    • 推论二: 当保持入口的流量是水管出来的流量的最大的值的时候,可以最大利用水管的处理能力。
      然而,和 TCP BBR 的不一样的地方在于,还需要用一个系统负载的值(load1)来激发这套机制启动。

    注:这种系统自适应算法对于低 load 的请求,它的效果是一个“兜底”的角色。对于不是应用本身造成的 load 高的情况(如其它进程导致的不稳定的情况),效果不明显。

    配置
    在这里插入图片描述
    配置
    在这里插入图片描述
    测试
    在这里插入图片描述

  • 相关阅读:
    android 运行时异常捕获
    汇编32位寄存器和地址编号的五种书写形式
    各种进制的乘法表,八进制的加法,和数字的源码你,反码,和补码
    第一个c程序和vs2017 在打开MFC rc文件时找不到rcdll.dl
    asdfasdf
    php如何判断一个字符串是否包含另一个字符串
    php计算时间差/两个时间日期相隔的天数,时,分,秒.
    PHP服务器时间差8小时解决方案
    历年学生作品评论
    第一周例行报告
  • 原文地址:https://www.cnblogs.com/idcode/p/14551366.html
Copyright © 2011-2022 走看看