使用Sentinel实现流控和服务降级的代码示例

 更新时间:2023年05月21日 10:06:35   作者:Supersist  
Sentinel是面向分布式、多语言异构化服务架构的流量治理组件,本文将详细为大家介绍如何使用Sentinel实现流控和服务降级,文中有相关的代码示例,需要的朋友可以参考下

伴随着微服务的兴起,服务间的调用的可靠性也越发重要了起来,在下面的这种服务调用关系中:

1.服务调用关系图

A服务调用服务C,B服务调用服务D,服务C/D调用服务E,而服务会进行数据库读写,如果服务E在服务C/D的频繁调用下不堪重负,使得服务E宕掉了,则将导致整个服务集群不可用,这种现象简称为服务雪崩,因此为了避免这种情况,就需要额外的技术保证服务的可用性。如常用的hystrixsentinel 就是用来处理这种情况的。前者是 Spring Cloud Netflix 常使用的组件,而后者是 Spring Cloud Alibaba 经常使用的组件。本文以介绍 sentinel 为主。

本文主要有以下内容:

  • Sentinel组件的简单介绍
  • Sentinel流控规则
  • Sentinel服务降级方案

什么是Sentinel

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

服务雪崩现象的发生,一般有两种原因,一种是外部的大量请求调用,如在上面的例子中服务C/D频繁调用服务E,导致服务E不堪重负,另外一种是自身的原因,如服务E内部发生了不可预知的错误,如数数据库读写效率过低,亦或者自身业务逻辑代码抛出了异常等。

为了解决这两种情况,Sentinel提供了针对外部的流量整形和针对本身的服务异常服务容错治理。

针对外部原因:提供了三种流控规则和三种流控效果来进行服务限流。

  • 流控规则
    • 直接流控
    • 关联流控
    • 链路流控
  • 流控效果
    • 快速失败
    • Warm Up
    • 排队等待

针对内部原因:提供了服务降级方案和服务熔断的方式来保证服务的稳定性。

  • 服务降级:针对单次服务调用,如服务C调用服务E时,服务E的方法出现了异常导致无法完成正常的处理逻辑,如响应超时、服务异常,此时我们给服务C提供一个默认的返回值,保证此次调用得到处理。
  • 服务熔断:指服务的异常调用占到一定的数量或者比例,达到了我们的判定条件,如在一个统计的时间窗口内,服务异常比例占比到达70%,触发了服务熔断,即所有的后续请求直接进入降级逻辑,不再调用目标访问方法。

对外部流量的控制

首先搭建sentinel的运行环境:

在 Sentinel官网页面下载可执行的jar文件,版本sentinel-dashboard-1.8.2.jar。下载完成后通过命令 java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar启动 Sentinel 。通过 127.0.0.1:8080访问 sentinel控制台,默认的账户密码均为sentinel

接着在项目中集成sentinel

pom.xml添加下列依赖

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

application.yml中添加如下配置

    spring:
      cloud:
        sentinel:
          transport:
            # sentinel api端口,默认8719
            port: 8719
            # dashboard地址
            dashboard: localhost:8080

ConsumerController添加如下代码

    @GetMapping("sentinel")
    @SentinelResource(
        value = "sentinel",
        blockHandler = "consumerSentinelResource_Blocked",
        fallback = "consumerSentinelResource_fallback")
    public String consumerSentinelResource() {
      //  if (Math.random() > 0.6 ){
      //     System.out.println("执行fallback降级逻辑");
      //      throw new RuntimeException("RuntimeException");
      //  }
        return "正常返回值";
    }
    ​
    public String consumerSentinelResource_Blocked(BlockException blockException){
        System.out.println("执行BlockException降级逻辑");
        return new Date().toLocaleString() + "BlockException: 服务被降级";
    }
    ​
    public String consumerSentinelResource_fallback(){
        return new Date().toLocaleString() +  "通用异常解决方法: 服务被降级";
    }

@SentinelResource 注解表明这是一个Sentinel资源。

  • value属性:资源名称必须填写。
  • blockHandler:处理因触发流控规则的请求抛出的BlockException,执行的的降级方法

流控规则

启动 sentinel并登录控制台后,侧边栏初始状态下并没有我们的服务,这时需要我们访问一下服务,随便调用一个服务接口,侧边栏就会出现我们注册的服务。

2.sentinel控制台截图

点开我们的服务,在侧边栏有个流控规则按钮,点击流控规则,在页面的右上角有一个新增流控规则按钮,点击此按钮,就可以新增流控规则。

直接流控

直接流控是我们常用的流控,一般情况下直接添加即可。按照下图添加流控规则:

3.直接流控截图

规则说明:在每秒请求数超过1个时,就触发流控规则,即执行consumerSentinelResource_Blocked()方法的逻辑,通过postman 调试接口即可得到下图的结果:

4.触发直接流控规则

关联流控

如果两个资源之间存在竞争关系,如共享一个线程池或者数据库连接池,这时候就可以使用关联流控,此时在低优先级的资源上设置流控规则,进而使得高优先级的资源获得竞争优势,

例如:资源A和资源B存在竞争关系,此时在资源A上设置流控规则和判断阈值,此时当高优先级的请求数量达到判断阈值时,就会对低优先级的资源进行流控,

ConsumerController添加如下代码:

    @SentinelResource(value = "condition")
    @GetMapping("condition")
    public String condition() {
        return "condition: 我是高优先级的资源";
    }

在控制台添加如下规则

5.配置关联流控规则

ps:通过postman工具怎么都无法出现低优先级服务降级的响应,于是乎我使用了一个python脚本模拟http请求,关联流控规则就起作用了!脚本内容如下

    import requests
     
    url = "http://127.0.0.1:10001/consumer/condition"
    url2 = "http://127.0.0.1:10001/consumer/sentinel"
    while(True):
        res = requests.get(url=url)
        res2 = requests.get(url=url2) 
        print("condition response:",res.text)  # 返回请求结果
        print("sentinel response:",res2.text)  # 返回请求结果
        print("------------------------------")

响应结果如下图

6.关联流控规则

链路流控

在一个应用中,对同一个资源有多条不同的访问路径时,如果需要对访问路径限流,则可以选用链路流控。如下图:

7.链路流控示意图

query 和 query2 都能访问到 resource, 如果想要对api/query2进行流控,则此时可以选择链路流控的方式。具体配置如下

8.配置链路流控规则

流控效果

快速失败

在前面的示例中,所有的流控效果都是快速失败,快速失败是sentinel默认的流控效果,即到达我们的设置的阈值之后就失败。

Warm Up

这种方式实现了预热的效果,即在设定的预热时间内,阈值从起始阈值逐渐提升到我们设定的阈值,起始阈值的值为设定的 单机阈值 / 冷加载因子sentinel默认的冷加载因子为 3。

9.Warm Up配置

以上图的配置,则流控效果在 10s100 / 3 = 33 缓慢提升到 100。

内部降级逻辑

降级方案

流控规则和流控效果是作用在外部流量的,而对自身服务而言,当服务调用出现足够多的异常时,为保证服务的稳定性,可采取服务熔断策略,服务熔断是多次异常调用的累积结果

在上面的示例代码中,我们在使用@SentinelResource注解时,配置了blockHandler、 fallback这两个属性, 这两个属性的值都是编写降级逻辑的,但是稍有不同。

blockHandler 只能处理服务抛出的异常时BlockException的情况,BlockExceptionSentinel组件配置的流控规则起作用时抛出的异常,即被当请求被流控规则拦截时,抛出的异常。

    public String consumerSentinelResource_Blocked(BlockException blockException){
        String s = new Date().toLocaleString() + "BlockException: 服务被降级";
        return s;
    }

在编写blockHandler的方法时,需要在参数列表的最后添加一个BlockException类型的参数,否则降级逻辑不会起作用。

fallback使用场景是当调用的方法抛出了除BlockException类型的其他运行时异常,如代码中分子为 0 抛出的java.lang.ArithmeticException: / by zero

fallback适用于编写通用的降级逻辑,fallback方法的编写不需要添加额外参数,和 controller 中的方法形参保持一致即可。

熔断策略

sentinel中,定义了三种熔断策略:

异常比例

在统计时长指定的时间内,异常调用比例超过设置的比例阈值,且请求数满足设置的最小请求数,则进行服务熔断,直接进入降级逻辑。如果请求数没有满足设置的最小请求数,则即使高于这个比例也不会熔断。如最小请求数是 10,比例为 0.5,即使前 9 次都失败了,也不会熔断。

异常数

在统计时长指定的时间内,异常调用比例大于设置的请求数,且请求数满足设置的最小请求数,则进行服务熔断,直接进入降级逻辑。这里大于指的是加入设置的异常数是3,则熔断发生在第四次失败调用之后。

慢调用比例

在统计时间窗口内,请求响应的时间大于了设置的 最大RT 时间的请求数所占全部请求数的比例超过了设置的比例阈值,且总请求数大于等于最小请求数,则触发熔断规则。

最大RT是判断慢请求的条件,不是触发熔断的条件。

熔断状态的转换

Sentinel 的熔断器有三个状态:关闭,全开,半开,在没有达到触发熔断的条件时,熔断器处于关闭状态,当达到熔断开始的条件时,熔断器出处于全开状态,当熔断时长结束时,熔断器不会立马关闭,而是处于半开状态,此时,下一个请求的状态决定了是关闭还是全开,如果下一个请求请求成功,则关闭熔断器,退出熔断状态,如果失败,则立马进入熔断状态,不需要再次满足设置的条件。

10.熔断状态转换示意图

需要说明的是:开源的Sentinel组件的配置的规则并没有被持久化,因此当我们重启应用或者重启sentinel组件,都需要重新配置相关规则。

以上就是使用Sentinel实现流控和服务降级的代码示例的详细内容,更多关于Sentinel 流控和服务降级的资料请关注脚本之家其它相关文章!

相关文章

  • ThreadPoolExecutor参数的用法及说明

    ThreadPoolExecutor参数的用法及说明

    这篇文章主要介绍了ThreadPoolExecutor参数的用法及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • SpringBoot之使用枚举参数案例详解

    SpringBoot之使用枚举参数案例详解

    这篇文章主要介绍了SpringBoot之使用枚举参数案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • SpringBoot自定义转换器应用实例讲解

    SpringBoot自定义转换器应用实例讲解

    SpringBoot在响应客户端请求时,将提交的数据封装成对象时,使用了内置的转换器,SpringBoot 也支持自定义转换器,这个内置转换器在 debug的时候,可以看到,提供了124个内置转换器
    2022-08-08
  • 基于Spring Boot的Logback日志轮转配置详解

    基于Spring Boot的Logback日志轮转配置详解

    本篇文章主要介绍了基于Spring Boot的Logback日志轮转配置详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • SpringBoot中集成串口通信的项目实践

    SpringBoot中集成串口通信的项目实践

    本文主要介绍了SpringBoot中集成串口通信,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • Springboot集成Quartz实现定时任务代码实例

    Springboot集成Quartz实现定时任务代码实例

    这篇文章主要介绍了Springboot集成Quartz实现定时任务代码实例,任务是有可能并发执行的,若Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题,而JobDetail & Job方式,Scheduler都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问问题
    2023-09-09
  • Java的HashTable源码解读

    Java的HashTable源码解读

    这篇文章主要介绍了Java的HashTable源码解读,HashTable继承了Dictionary类,提供了一些字典相关的基本功能如添加、删除、判空、获取元素数量等,需要的朋友可以参考下
    2023-12-12
  • 简单探索 Java 中的惰性计算

    简单探索 Java 中的惰性计算

    这篇文章主要介绍了简单探索 Java 中的惰性计算,惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素,无需预先计算它们,这带来了一些好处。,需要的朋友可以参考下
    2019-06-06
  • java Thread 多线程

    java Thread 多线程

    本篇文章小编为大家介绍,java Thread 多线程。需要的朋友参考下
    2013-04-04
  • java生成excel并导出到对应位置的方式

    java生成excel并导出到对应位置的方式

    这篇文章主要介绍了java生成excel并导出到对应位置的方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01

最新评论