• Sentinel 熔断与限流


    概述

    官网:GitHub - alibaba/Sentinel: A powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件)

    功能同Hystrix

    解决:服务雪崩,服务降级,服务熔断,服务限流

    安装Sentinel控制台

    1. 下载https://github.com/alibaba/Sentinel/releases

    0LPLKX9tQfpng

    1. 运行java -jar sentinel-dashboard-1.7.0.jar

    cmd19YkChCaAMpng

    1. 访问前台管理界面http://localhost:8080

    msedgeaxgRA4mpfMpng

    登录账号密码均为sentinel

    测试准备

    1. 新建cloudalibaba-sentinel-service8401

    2. POM

    <dependencies>
            <!--SpringCloud ailibaba nacos -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</artifactId>
            </dependency>
            <!--SpringCloud ailibaba sentinel -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            </dependency>
            <!--openfeign-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <!-- SpringBoot整合Web组件+actuator -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!--日常通用jar包配置-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>4.6.3</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    1. YML
    server:
      port: 8401
    
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        nacos:
          discovery:
            #Nacos服务注册中心地址
            server-addr: localhost:8848
        sentinel:
          transport:
            #配置Sentinel dashboard地址
            dashboard: localhost:8080
            #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
            port: 8719
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1. 主启动
    @EnableDiscoveryClient
    @SpringBootApplication
    public class MainApp8401
    {
        public static void main(String[] args) {
            SpringApplication.run(MainApp8401.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 测试类
    @RestController
    public class FlowLimitController
    {
    
        @GetMapping("/testA")
        public String testA()
        {
            return "------testA";
        }
    
        @GetMapping("/testB")
        public String testB()
        {
            return "------testB";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. 启动nacos,sentinel和8401

    由于sentienl采取懒加载的策略,所以需要先执行一次访问http://localhost:8401/testA

    查看sentienl控制台

    msedgebKzih4MJKopng

    此时sentinel8080正在监控微服务8401

    流控规则

    概述

    msedge6MBBiH7mZtpng

    msedgeKRFSKrkkT3png

    msedgeAGhAjZ9WYlpng

    流控模式

    直接(默认)

    为testA增加流控,其默认是 直接–快速失败

    msedge5nnVe0nr2Zpng

    当设置每秒访问量QPS为1后,快速连续访问testA会报错

    msedgeM6bsnkS5sYpng

    同样的如果设置的是线程数,则只能最多同时处理阈值线程数的请求

    关联

    效果:当与A关联的资源B达到阀值后,就限流A自己

    为A增加流控,关联B,仍是设置A的配置

    msedgemgal1A19mSpng

    利用Jmeter(参照Hystrix中Jmeter的使用)对testB进行高并发访问

    此时再访问testA,返回失败

    链路

    如果A,B同时会调用资源C,那么对C设置链路流控,就可以针对某个服务A或B进行限制

    msedgeT497dBuLKWpng

    1.7.0的Sentinel链路有大问题,等下次用更高版再试试

    流控效果

    快速失败

    字面意思

    Warm Up(预热)

    阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

    默认coldFactor为3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。

    例,阀值为10+预热时长设置5秒。系统初始化的阀值为10 / 3 约等于3,即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10

    就不测试了,,

    排队等待

    也是字面意思,但匀速排队,阈值必须设置为QPS

    降级规则

    官网:熔断降级 · alibaba/Sentinel Wiki · GitHub

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

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

    Sentinel的断路器没有半开状态

    Sentinel 提供以下几种熔断策略:

    • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
    • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
    • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

    msedgeAzo6U3k32hpng

    新版Sentinel可以设置(直接在图形化界面设置)以上参数,较旧版更多

    慢调用比例(RT)

    添加方法用于测试

    @GetMapping("/testD")
        public String testD()
        {
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            log.info("testD 测试RT");
            return "------testD";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Sentinel添加降级

    msedgexboim5tUsYpng

    简单的来讲,如果在RT时间(200ms)内没有处理完请求,则熔断时间窗口时间(1s)

    Jmeter配置10个线程每秒发送一次请求

    测试,按照上述配置,

    永远一秒钟发送10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了

    后续停止Jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复

    异常比例

    当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,熔断

    msedgeU4rgkEybKupng

    异常数

    旧版异常数是按照分钟统计的

    新版Sentinel将可以自己设置统计时长,熔断时长,最小请求数,异常数

    msedgeZ42ui3YzPspng

    热点key限流

    官网:热点参数限流 · alibaba/Sentinel Wiki (github.com)

    热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

    • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
    • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

    热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效

    测试

    这里必须要用@SentinelResource为方法建立资源才能实现热点限流(虽然不知道为什么)

    其中value参数为资源名(自定义),blockHandler参数为兜底的方法名

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2){
        return "------testHotKey";
    }
    public String dealHandler_testHotKey(String p1, String p2, BlockException exception)
    {
        return "-----dealHandler_testHotKey";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    配置热点限流

    msedge1T94R3b6gIpng

    其中参数索引就是需要监控方法的第几个参数,下标从零开始

    此时快速访问http://localhost:8401/testHotKey?p1=abc&p2=33,就会出错

    msedgejYtgsTy54Mpng

    而快速访问http://localhost:8401/testHotKey,则没有问题

    高级选项

    期望参数当它是某个特殊值时,它的限流值和平时不一样

    例如,下面就允许当参数值为5时,限流阈值为200

    msedge65Ye5vW975png

    系统规则

    官网:系统自适应限流 · alibaba/Sentinel Wiki · GitHub

    系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

    简单来讲就是不再具体到每个方法,而是针对整个系统设定阈值

    总共可以设置五种参数

    • 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 达到阈值即触发系统保护。

    @SentinelResource

    基本使用

    其中value参数为资源名(自定义),blockHandler参数为兜底的方法名

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2){
        return "------testHotKey";
    }
    public String dealHandler_testHotKey(String p1, String p2, BlockException exception)
    {
        return "-----dealHandler_testHotKey";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    此时在设置限流规则时,对于资源名可以使用URL参数,也可以使用value参数

    AefFvhQ0itpng

    存在缺陷

    1 系统默认的,没有体现我们自己的业务要求。(已解决)

    2 依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。

    3 每个业务方法都添加一个兜底的,那代码膨胀加剧。

    4 全局统一的处理方法没有体现。

    自定义限流处理逻辑

    创建CustomerBlockHandler类用于实现自定义限流处理逻辑

    public class CustomerBlockHandler
    {
        public static CommonResult handleException(BlockException exception){
            return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler");
        }
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    然后只需要配置blockHandlererClass参数(类名)和blockHandler参数(方法名)即可

    @GetMapping("/rateLimit/customerBlockHandler")
        @SentinelResource(value = "customerBlockHandler",
                blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2")
        public CommonResult customerBlockHandler()
        {
            return new CommonResult(200,"按客户自定义限流处理逻辑");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    服务熔断

    sentinel整合ribbon+openFeign+fallback

    Ribbon系列

    @SentinelResourc的两个注解@blockHandler和@fallback

    blockHandler是作为sentinel限流、降级等无法访问时的兜底方法

    fallback是作为java代码运行时抛出异常的兜底方法(没有fallback之前时返回404)

    简单的来讲,blockHandler所设置的方法替换了sentinel原来默认的限流之后的策略,而fallback所设置的方法替换了原来运行时错误而返回的404页面

    Feign系列

    按前面openFeign来就行

    规则持久化

    一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化

    将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效

    实现

    1. 修改cloudalibaba-sentinel-service8401

    2. POM添加依赖

    <!--SpringCloud ailibaba sentinel-datasource-nacos -->
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</artifactId>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. YML添加配置
    spring:
      cloud:
        sentinel:
          datasource:
            ds1:
              nacos:
                server-addr: localhost:8848
                dataId: ${spring.application.name}
                groupId: DEFAULT_GROUP
                data-type: json
                rule-type: flow
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 添加Nacos业务规则配置

    在Nacos中添加配置

    msedgezkPLmegXcOpng

    其中Data ID即是上面YML中添加的配置

    JSON格式的配置内容,就是希望持久化的配置,各标签意义如下:

    resource:资源名称;

    limitApp:来源应用;

    grade:阈值类型,0表示线程数,1表示QPS;

    count:单机阈值;

    strategy:流控模式,0表示直接,1表示关联,2表示链路;

    controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;

    clusterMode:是否集群。

    1. 启动8401后刷新sentinel发现业务规则有了
      msedge_4dWuOBRJIA.png
  • 相关阅读:
    【数据结构与算法系列3】有序数组的平方 (C++ & Python)
    模拟Proactor模式实现 I/O 处理单元
    第2-2-2章 常见组件与中台化-常用组件服务介绍-通用权限系统
    Android Framework通信:Handler
    C++ vector容器
    基于ubuntu tun虚拟网卡设备完成ping的发送与模拟接收
    生产者消费者模式(c++实现)
    1965. 丢失信息的雇员
    【星海出品】flask (二) request替代VUE测试flask接口
    Dynamic CRM一对多关系的数据删除时设置自动删除关联的数据
  • 原文地址:https://blog.csdn.net/qq_46636391/article/details/125556459