spring-cloud-alibaba sentinel 流控 熔断降级

spring-cloud-alibaba sentinel 流控 熔断降级

  • 一、概述
  • 二、sentinel的安装和使用
  • 三、 与springboot微服务整合(关键代码)
  • 四、各种限流方式总结
    • 4.1. 指定降级方法
    • 4.2 RT (平均响应时间)
    • 4.3 异常比例
    • 4.4 异常数
    • 4.5 热点限流
    • 4.6 系统级限流
  • 五、java运行时fallback降级
  • 六、配置持久化到nacos

一、概述

Sentinel: 分布式系统的流量防卫兵
Sentinel 是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

sentinel 中的熔断降级分为两种

  • 针对于流控导致降级的 blockHandler
  • 针对于java运行时异常导致降级的 fallback

使用sentinel主要还是重点关注其流控熔断,对于java运行时的fallback可以直接使用统一异常处理来解决。让专业的sentinel来做专业的流控。那些运行时的事情就不要他操心了。
另外值得注意的是。作为熔断机制 sentinel并没有半开状态。

二、sentinel的安装和使用

github下载地址:https://github.com/alibaba/Sentinel/tags
本次以1.7.1为基础作为实验
下载:sentinel-dashboard-1.7.1.jar
对应的springcloud springboot 以及 springcloud-alibaba 版本为



    org.springframework.boot
    spring-boot-dependencies
    2.2.5.RELEASE
    pom
    import




    org.springframework.cloud
    spring-cloud-dependencies
    
    Hoxton.SR1

    pom
    import





    com.alibaba.cloud
    spring-cloud-alibaba-dependencies
    2.2.0.RELEASE
    pom
    import

下载完成后 启动本地nacos
并使用java -jar 命令来启动sentinel (它使用的默认端口为8080)
启动完成后 访问 http://localhost:8080 用户名密码默认都是sentinel

三、 与springboot微服务整合(关键代码)

POM



    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery




    com.alibaba.cloud
    spring-cloud-starter-alibaba-sentinel

yml

server:
	port: 8001
spring:
  application:
    name: boot-server
  cloud:
    nacos: # 配置nacos
      discovery: # 服务发现地址
        server-addr: 127.0.0.1:8848 # nacos 启动地址
    sentinel: # 配置sentinel
      transport:
        dashboard: 127.0.0.1:8080 # 配置sentinel dashboard 启动地址
        port: 8719 # 直接写8719 端口号默认是8719 如果被占用就是+1 直到找到未被占用端口
      filter:
        url-patterns: /** # 默认是/* 这里改成/** 则会监控所有的请求

这本地的boot-server微服务就被sentinel监控了

编写一个controller

@Slf4j
public class FallbackController {


    @GetMapping("/hot_key/{id}")
    @SentinelResource(value = "fallback|hot_key",blockHandler = "testHotKeyFallback")
    @ApiOperation("热点限流")
    public ResponseEntity testHotKey(@PathVariable("id") String id) throws Exception {
        log.info("进入了 热点限流 测试方法");
        return ResponseEntity.ok(ResponseEntityBody.create("热点限流方法:" + id));
    }

    public ResponseEntity testHotKeyFallback(String id, BlockException exception) throws Exception {
        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(ResponseEntityBody.create(id + "热点限流了!!"));
    }


    @GetMapping("/rt1")
    @ApiOperation("RT,这里要在sentinel中设置 RT小于300 否则不能触发熔断,指定自定义限流方法1")
    // 指定全局限流降级方法
    @SentinelResource(value = "resource_rt1", blockHandlerClass = MyCustomLimiterHandler.class, blockHandler = "globalFallback1")
    public ResponseEntity testRT() {
        log.info("进入了RT测试方法");
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return ResponseEntity.ok(ResponseEntityBody.create("A"));
    }

    @GetMapping("/rt2")
    @ApiOperation("RT,这里要在sentinel中设置 RT小于300 否则不能触发熔断,指定自定义限流方法2")
    // 指定全局限流降级方法
    @SentinelResource(value = "resource_rt2", blockHandlerClass = MyCustomLimiterHandler.class, blockHandler = "globalFallback2")
    public ResponseEntity testRT2() {
        log.info("进入了RT测试方法");
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return ResponseEntity.ok(ResponseEntityBody.create("A"));
    }

    @GetMapping("/rate")
    @ApiOperation("异常比例: 这里是 50%的出错概率 在sentinel中 设置低于50%的错误率就可以触发熔断降级")
    public ResponseEntity testRate() throws Exception {
        log.info("进入了 异常比例 测试方法");
        throw CommonException.create(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ResponseEntityBody.create("出错了!")));
    }

    @GetMapping("/err_num")
    @ApiOperation("异常数: 这里一定会报错 所以 触发熔断后 不会再进入这个方法内 直到下一个窗口期")
    public ResponseEntity testErrNum() throws Exception {
        log.info("进入了 异常数 测试方法");
        throw CommonException.create(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ResponseEntityBody.create("出错了!")));
//        return ServerResponse.createBySuccessMessage("B");
    }

}

统一的降级方法

public class MyCustomLimiterHandler {
    public static ResponseEntity globalFallback1(BlockException exception) {
        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(ResponseEntityBody.create("(Global)服务器太忙 限流 返回限流方法1 "));
    }

    public static ResponseEntity globalFallback2(BlockException exception) {
        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(ResponseEntityBody.create("(Global)服务器太忙 限流 返回限流方法2 "));
    }
}

四、各种限流方式总结

因为sentinel是懒加载机制,所以需要访问一次访问才能看到簇点列表。
可以在簇点列表中对服务设置限流策略。

4.1. 指定降级方法

添加@SentinelResource注解

  • 可以指定blockHandler降级方法
  • 可以指定blockHandlerClass 自定义降级方法类 并指定类中的某个降级方法 blockHandler

注意 使用SentinelResource注解 一定要加资源名称value字段 否则不起作用 ,

因为默认在sentinel控制台是将限流规则配置在url上的,而url配置后 是默认的降级返回。
所以不会找到注解的资源名对应的降级方法

最后会以默认的方法返回降级

4.2 RT (平均响应时间)

平均响应时间超过设定的阈值 并且在时间窗口内通过的请求大于5 则触发熔断降级
窗口期过后 关闭断路器 回复服务
RT的最大值为 4900s 可用通过 -Dcsp.sentinel.statistic.max.rt=xxx 设置最大数

4.3 异常比例

QPS>=5 并且 异常比例(每秒统计) 超过阈值 则触发熔断降级
窗口期过后 关闭断路器 回复服务

4.4 异常数

按分钟来统计服务异常数,如果超过阈值则触发熔断降级,
窗口期过后 关闭断路器 回复服务

4.5 热点限流

可以设置某个资源的请求qps限流
比如:product/query/{id}
注解中的value就是资源名称
方法中的参数 从0开始 可以指定是否传递某个参数 限流
也可以指定某个参数 的值为多少 限流
比如 可以指定 id = 1 qps 不能超过 10 则每秒只能有10个请求 访问该资源。

4.6 系统级限流

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,
结合应用的 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 达到阈值即触发系统保护。
系统级限流规则应该视情况添加。

五、java运行时fallback降级

fallback java运行时异常降级 这个配置与blockHandler相似,也可以使用全局异常处理代替

六、配置持久化到nacos

防止每次启动微服务都会丢失之前的限流配置
pom 增加依赖



   com.alibaba.csp
   sentinel-datasource-nacos

yml增加配置

spring:
	cloud:
      datasource: # 配置sentinel 流控规则持久化
        ds1: # 数据库1
          nacos: # 持久化到 nacos
            server-addr: 127.0.0.1:8848 # nacos 地址
            dataId: ${spring.application.name} # 数据id
            data-type: json # 格式json
            rule-type: flow # 流控规则
            # namespace: public # 使用默认的 命名空间
            # groupId: DEFAULT_GROUP # 使用默认分组

然后在nacos中添加配置文件json

[
    {
        "resource": "resource_rt1",
        "limitApp": "default",
        "grade": 1,
        "count": 5,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

resource:资源名
limitApp:流控针对的调用来源,default不区分来源
grade:限流阈值类型(0-根据并发数量来限流 1-根据QPS来进行流量控制)
count:限流阈值
strategy:调用关系限流策略
controlBehavior:流量控制效果(直接拒绝、WarmUP、匀速排队)
clusterMode:是否集群模式

你可能感兴趣的:(java)