sentinel的熔断,降级,限流使用

sentinel

  • 一、说明
  • 二、使用步骤
    • 1.开始
    • 2.流控规则(流量控制)
      • 1.使用
      • 2.阈值类型/(关联)
      • 3.流控效果(warm up 预热)
      • 4.排队等待
    • 3.降级规则
    • 4.热点key限流
    • 5.系统自适应限流
    • 6.熔断
    • 3.持久化

一、说明

官方文档
sentinel下载
Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

sentinel分为两个部分:
客户端:不依赖任何框架,能够运行于所有java运行时环境
控制台:基于spring boot开发,打包后直接运行,不需要额外的tomcat等应用

我们直接启动jar包就可以了,默认的访问端口是8080 账号密码:sentinel

二、使用步骤

1.开始

父工程

<dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--spring cloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

.........
        </dependencies>
  </dependencyManagement>

//这三个依赖是必备的

创建子服务:

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <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>
        <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>

yml:

server:
  port: 8003
spring:
  application:
    name: cloudsentinel-8003
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719
#        clientIp: localhost:8003

#默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口

management:
  endpoints:
    web:
      exposure:
        include: '*'
#我们上面搭配了nacos的注册中心,当然你不搭也可以,但是微服务是必须要有注册中心的,单纯的写个demo也可以不使用。

此时访问sentinel的管理后端是没有效果的,应为sentinel是懒加载
我们就写一个controller来访问一下
此时就会有数据了
sentinel的熔断,降级,限流使用_第1张图片

2.流控规则(流量控制)

sentinel的熔断,降级,限流使用_第2张图片

资源名:唯一名称,默认请求路径
针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
阈值类型/单机阈值:
   >直接:api达到限流条件时,直接限流(默认)
   >关联:当关联的资源达到阈值时,就限流自己
   >链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)[api级别的针对来源]

流控效果:
   >快速失败:直接失败;抛异常
   >Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值codeFactor,经过预热时长,才达到设置的QPS阈值
   >排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置QPS,否则无效

1.使用

测试:给我们的/test接口请求添加限流设置
使用QPS

sentinel的熔断,降级,限流使用_第3张图片
此时我们疯狂请求这个接口:
sentinel的熔断,降级,限流使用_第4张图片
则已经帮我们限流了,访问不到
上面的是使用的是直接QPS和直接拒绝,线程数则是并发数,一直同一个浏览器或同一个窗口发请求是没有问题的,多个浏览器或开其他端口访问就会有问题了,这里就不累赘了,都是一样的配置。

2.阈值类型/(关联)

上面我们使用的是直接拒绝,到达了阈值就直接返回错误信息,
那这个关联呢?
sentinel的熔断,降级,限流使用_第5张图片
说明: 当/testb请求的阈值达到了2,那么他会导致/testa不可用,返回错误信息,
这种情况适用于一些链路调用,请求数过大或并发量过大,直接快速失败关联的请求接口

3.流控效果(warm up 预热)

有快速失败,warm up 排队等待。
上面的例子都是使用的快速失败。

快速失败在页面上直接返回错误信息
它的配置在源码的:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController 类上

公式:阈值除以coldFactor(冷因子默认值为3),经过预热时长后才会达到阈值
sentinel的熔断,降级,限流使用_第6张图片
这个图表示,当流量过来时,会以总的单机阈值 10/3(冷因子)=3,3是单机阈值,通过时长5秒慢慢的达到10的阈值
这个WarmUp的源码在com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController,
可以自己去配置他的冷因子

4.排队等待

sentinel的熔断,降级,限流使用_第7张图片
说明:排队等待只可以是QPS,不支持线程数。表示这个/testb每秒可接收5个请求,剩下的进行等待,而超时时间是500毫秒。
匀速排队:会严格的控制请求通过的间隙时间,让请求均匀速度通过,对应的是漏桶算法。

排队等待的源码实现:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

3.降级规则

sentinel的熔断,降级,限流使用_第8张图片

注意:1.8版本的sentinel和1.8一下的熔断降级有明显的变化,我这里使用的是1.7的,具体参考官方文档
资源名不多说了就是请求路径
RT(平均响应时间,秒级):
  平均响应时间:1s内持续进入5个请求,对应时刻的平均响应时间均超过阈值(这个阈值就是我们每个请求不能超过的值,否则满足熔断条件之一),那么在接下的时间窗口之内,对这个方法的调用都会自动熔断(满足1s内5个请求,并且平均响应时间大于阈值才熔断)
  RT默认最大4900ms(更大的需要通过 -Dcsp.sentinel.statistic.max.rt=xxxx才能生效)

异常比例(秒级)
  当资源的每秒请求量>=5,并且每秒异常总数占通过的比值超过阈值,资源进入降级状态,即在接下的时间窗口之内,
  对这个方法的调用都会自动的返回,异常比例的阈值范围[0.0,1.0] 表示10%~100%

异常数(分钟级)
  当资源近一分钟的异常数超过阈值后会进行熔断,注意由于统计时间窗口是分钟级别的,
  若时间窗口是小于60s,则结束熔断状态后仍可能在进入熔断,所有要设置大于60



时间窗口,就是熔断的时间,到了时间,则会退出熔断,再根据策略等原来判断是否再次熔断。

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

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


具体的就不演示了,

但是要注意,在异常比例的情况下:如果请求达不到5或者5以上,系统会报错但不会被熔断的。  

4.热点key限流

文档地址
说明:何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。
源码:com.alibaba.csp.sentinel.slots.block.BlockException

    @GetMapping("/test")
    @SentinelResource(value = "test",blockHandler = "block")   //blockHandel指定熔断需要访问的方法 ,注意这个value,我们有用
    public String test(@RequestParam(value = "id") String id){
        return "正常";
    }

    //上面的blockHandler指定的方法
    public String block(String id, BlockException block){
        System.out.println(block);
        return "熔断";
    }

这里和之前的兜底方法很相识
注意:使用了@SentinelResource注解,写了blockHandler属性指定了兜底的方法,当违背配置规则后,就执行指定的兜底方法,
前提再sentinel配置的时候我们指定的资源名称是value的情况下

如果我们在sentinel后台配置的情况下指定的资源名是我们的请求的路径,那么就会有一些变化
使用了@SentinelResource注解,有blockHandler属性指定了兜底的方法,当违背配置规则后,就执行指定的兜底方法,
没有指定的兜底方法的话就是系统默认的兜底方法

上面两种的细微差别


而且该注解不支持private的权限修饰的接口方法

新增热点规则:
sentinel的熔断,降级,限流使用_第9张图片

参数索引就是我们的参数id索引位置。资源名称不是请求名称,而是我们配置的value.
上面的代码我们有一个参数id,那么我们携带其他的参数是没有效果的,也就是不限流
比如
 url?id=3  限流
 url?id=4&idd=6 限流
 url?no=8 不限流

并且要注意的是:
 @SentinelResource(value = "test",blockHandler = "block") 
 blockHandler 指定的方法,当接口出现异常跟会不会执行这个方法是没有关系的
 会执行这个方法是违背了sentinel里面的热点key的配置才会执行的,接口报错和它没有必然关系
但想要有友好的返回效果,我们可以使用上面说到的降级规则。也就是说这个注解管不了我们的异常。
只有违背了配置才会调用这个指定的方法。

那么还有一些情况,虽然我们设置了参数,只有携带了指定的参数时,才会有兜底的方法,
sentinel还有一些其他的设置,比如当这个参数等于某个值的时候可以再对其设置阈值
如下:
在高级选项中
sentinel的熔断,降级,限流使用_第10张图片
当这个参数的值等于5时,我们给的阈值等于100,就是1s内可以有100个请求都不会走兜底的方法。

5.系统自适应限流

官方文档
sentinel的熔断,降级,限流使用_第11张图片
这里的设置是对这个服务的全局的配置

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

兜底方法改进

//如果我们的兜底方法和业务接口方法写到一起,那么就会造成高耦合的情况,我们应该将他们分开来
//首先先看我们的接口,
    @GetMapping("/test")
    @SentinelResource(value = "test",blockHandlerClass=MyBlockHandel.class ,blockHandler = "block")
    public String test(@RequestParam(value = "id") String id){
        return "正常";
    }

新建一个类,类名对应着blockHandlerClass的属性值,方法名对应着blockHandler 的属性值
public class MyBlockHandel {

    public static String block(String id,BlockException exception){
        return "兜底";
    }
    .....
    //当然这里还可以有其他的兜底方法,注意:方法参数和返回值要一样
}




6.熔断

上面讲了,使用@SentinelResource注解的blockHandler只有在违背了配置情况下才会执行兜底的方法,
但是如果代码发生了异常是不会执行兜底的方法的。

这个时候这个注解就有一个fallback属性可以配置

   @GetMapping("/test")
    @SentinelResource(value = "test",fallback="xxxx")
    public String test(@RequestParam(value = "id") String id){
        int i=10/0;
        return "正常";
    }

    //这个方法的名字就是上面的fallback的值,表示上面的方法报异常了,会执行下面的方法,注意,参数要一样,throwable可加可不加
    public String xxxx(@RequestParam(value = "id") String id,Throwable throwable){
        return "异常";
    }

当然除了fallback属性外,还有fallbackClass指定一个类,和之前的blockHandlerClass属性差不多

问题来了
注意:

如果配置了blockHandler(前提是在控制台配置了规则)和配置了fallback,那么发生了异常和QPS超过了怕配置会执行哪个兜底方法呢?
首先如果是违背了配置的规则,肯定是会执行blockHandler指定的方法的。
那么发生了异常呢会执行fallback指定的方法的。

如果我们的配置规则是QPS为1的时候就降级,然后手动代码中抛出异常,也就是同时满足上面两种情况的话,
是会执行blockHandler指定的方法的,不会执行fallback指定的方法,注意这里

忽略异常:

@SentinelResource还有一个属性exceptionsToIgnore,
@SentinelResource(value="dsd",fallback="xxx",exceptionsToIgnore={yyyException.class})
这种情况,尽管我们指定了fallback属性,报异常了走xxx方法,但是我们这里的exceptionsToIgnore属性指定了忽略的异常,
也就是说当发生这个指定的异常时,不会执行fallback指定的xxx方法,也就是返回 error page。因为不做这个异常的处理。

其次,如果想让Sentinel支持feign
还需要再配置文件中加上一些配置

feign:
  sentinel:
    enabled: true

3.持久化

现在的我们的Sentinel是默认没有持久化的,只要Sentinel重启里面的配置就会情况,
或者说当有关联的服务的一些配置信息在Sentinel上,只要服务重新启动,更这个服务相关的配置也会清空,这是非常不友好的,

所以我们需要配置持久化

添加坐标
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>


配置文件:
server:
  port: 8003
spring:
  application:
    name: cloudsentinel-8003
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719     
        #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudsentinel-8003
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
                

management:
  endpoints:
    web:
      exposure:
        include: '*'

然后配置好后,我们打开nacos的配置列表新增配置
dataID就填写我们上面写的dataId,然后配置格式写json,
内容填写为:
[
    {
         "resource": "/test",
         "limitApp": "default",
         "grade":   1,
         "count":   1,
         "strategy": 0,
         "controlBehavior": 0,
         "clusterMode": false    
    }
 ]
 
 resource:资源名称
 limitApp:来源应用
 grade:阈值类型,0表示线程数,1表示QPS
 count:单机阈值
 strategy:流控模式:0表示直接;1表示关联;2表示链路
 controlBehavior:流控效果:0表示快速失败;1表示Warm Up;2表示排队等待
 clusterMode:是否集群

现在就这些数据持久化到nacos了,要保证nacos也是持久化的,此时服务启动后,配置也不会丢失了。但是要先访问一次资源。

你可能感兴趣的:(java,Sentinel,java)