Sentinel从入门到应用

Posted 结构化思维wz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sentinel从入门到应用相关的知识,希望对你有一定的参考价值。

文章目录

面向分布式、多语言异构化服务架构的流量治理组件

官方文档:https://sentinelguard.io/zh-cn/

一、基本介绍

1.1 Sentinel简介

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

Sentinel 的开源生态:

Sentinel具有以下特征:

  • 丰富的应用场景:秒杀限流,消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等

Sentinel分为两个部分:

  • **核心库(Java 客户端)**不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

  • **控制台(Dashboard)**基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

    控制台支持实时监控

Sentinel 中的基本概念:

  • 资源

    资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。

    只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

  • 规则

    围绕资源的实时状态设定的规则,可以包括流量控制规则熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

1.2 限流与熔断降级

服务限流 :当系统资源不够,不足以应对大量请求,对系统按照预设的规则进行流量限制或功能限制

服务熔断:当调用目标服务的请求和调用大量超时或失败,服务调用方为避免造成长时间的阻塞造成影响其他服务,后续对该服务接口的调用不再经过进行请求,直接执行本地的默认方法

服务降级:为了保证核心业务在大量请求下能正常运行,根据实际业务情况及流量,对部分服务降低优先级,有策略的不处理或用简单的方式处理

1.3 Sentinel 功能与设计

Sentinel定位是分布式系统的流量防卫兵。目前互联网应用基本上都使用微服务,微服务的稳定性是一个很重要的问题,而限流、熔断降级是微服务保持稳定的一个重要的手段。

  • 流量控制

    流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。**我们需要根据系统的处理能力对流量进行控制。**Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:

    流量控制有以下几个角度:

    • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
    • 运行指标,例如 QPS、线程池、系统负载等;
    • 控制的效果,例如直接限流、冷启动、排队等。

    Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

  • 熔断降级

    除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。

    Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。

    熔断降级设计理念

    在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。

    Hystrix 通过线程池的方式,来对依赖(在我们的概念中对应资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本,还需要预先给各个资源做线程池大小的分配。

    Sentinel 对这个问题采取了两种手段:

    • 通过并发线程数进行限制

    和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

    • 通过响应时间对资源进行降级

    除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。

  • 系统负载保护

    Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。

    针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

二、基本使用

2. 1 Hello World

引入依赖:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.5</version>
</dependency>
 public static void main(String[] args) 
        // 配置规则.
        initFlowRules();
        int x = 10000;
        while (x > 0) 
            // 1.5.0 版本开始可以直接利用 try-with-resources 特性
            try (Entry entry = SphU.entry("HelloWorld")) 
                // 被保护的逻辑
                System.out.println("hello world");
             catch (BlockException ex) 
                // 处理被流控的逻辑
                System.out.println("限流限流限流");
            
            x--;
        
    
    private static void initFlowRules()
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20.
        rule.setCount(20);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    

输出结果:

2.2 控制台

  1. 从官网下载控制台jar包

  2. 运行jar包

    java '-Dserver.port=8080' '-Dcsp.sentinel.dashboard.server=localhost:8080' '-Dproject.name=sentinel-dashboard' -jar sentinel-dashboard-1.8.5.jar  
    

    参数说明:

    # 指定控制台的端口为8480
    -Dserver.port=8480 
    # 指定要被哪个控制台监控(这里指定的是自己监控自己)
    -Dcsp.sentinel.dashboard.server=localhost:8480 
    # 指定实例名称(名称会在控制台左侧以菜单显示)
    -Dproject.name=sentinel-dashboard 
    # 设置登录的帐号为:sentinel 
    -Dsentinel.dashboard.auth.username=sentinel 
    # 设置登录的密码为:123456
    -Dsentinel.dashboard.auth.password=123456 
    
    

    如果使用docker部署:

    # 指定docker容器使用宿主机的网络(你也可以映射8858,8719这两个端口)
    --network=host    
    # 开启登录认证,在application.yml中你需要配置对应的用户名和密码
    auth.enabled="true"
    # 指定Sentinel控制台用户名,默认Sentinel
    sentinel.dashboard.auth.username=admin
    # 指定Sentinel控制台密码,默认Sentinel
    sentinel.dashboard.auth.password=admin
    # 用于指定 Spring Boot服务端session的过期时间,如7200表示7200 秒;60m表示60分钟,默认为30分钟;
    server.servlet.session.timeout=7200
    
    
  3. 访问http://localhost:8080,默认登录的用户名和密码都是sentinel

登录后页面:

2.2 快速入门

Sentinel适配了常见主流框架,包括Dubbo、Spring Boot、Spring WebFlux、gRPC、Zuul、Spring Cloud Gateway、RocketMQ、Web Servlet,对于需要限流的资源,支持用原生Java的try-catch 接入或者使用注解。

下面是一个结合控制台的限流实例:

1️⃣ 引入依赖:

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

2️⃣ 配置文件中指定控制台地址:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719

默认与控制台通信的端口为 8719

3️⃣ 创建一个测试用的Controller

    @GetMapping("getList")
    public List<User> getList()
        return userService.getUserList();
    

启动项目,可以在dashboard中机器列表中看到我们的服务,以及健康状态。

4️⃣ 用postman 连续发送请求观察实时监控

5️⃣ 配置限流策略

6️⃣ 使用postman再次进行测试

如果不是接口资源可以通过@SentinelResource来指定资源。

三、@SentinelResource详解

3.1 定义资源

Sentinel需要先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。

Sentinel提供多种定义资源的方式,分别是:

  • 主流框架的默认适配
  • 抛出异常的方式定义资源
  • 返回布尔值方式定义资源
  • 注解方式定义资源
  • 异步调用支持

想要详细了解每种方式可以自行查阅官网

3.2 @SentinelResource 注解

Sentinel提供了@SentinelResource注解用于定义资源,并提供可选的异常回退和Block回退。

异常回退指的是:@SentinelResource注解标注的方法发生Java异常时的回退处理;

Block回退指的是:当@SentinelResource资源访问不符合Sentinel控制台定义的规则时的回退(默认返回Blocked by Sentinel (flow limiting))。

属性说明必填与否使用要求
value用于指定资源的名称必填-
entryTypeentry 类型可选项(默认为 EntryType.OUT)-
blockHandler服务限流后会抛出 BlockException 异常,而 blockHandler 则是用来指定一个函数来处理 BlockException 异常的。 简单点说,该属性用于指定服务限流后的后续处理逻辑。可选项blockHandler 函数访问范围需要是 public返回类型需要与原方法相匹配;参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException;blockHandler 函数默认需要和原方法在同一个类中,若希望使用其他类的函数,则可以指定 blockHandler 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
blockHandlerClass若 blockHandler 函数与原方法不在同一个类中,则需要使用该属性指定 blockHandler 函数所在的类。可选项不能单独使用,必须与 blockHandler 属性配合使用;该属性指定的类中的 blockHandler 函数必须为 static 函数,否则无法解析。
fallback用于在抛出异常(包括 BlockException)时,提供 fallback 处理逻辑。 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。可选项返回值类型必须与原函数返回值类型一致方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常fallback 函数默认需要和原方法在同一个类中,若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
fallbackClass若 fallback 函数与原方法不在同一个类中,则需要使用该属性指定 blockHandler 函数所在的类。可选项不能单独使用,必须与 fallback 或 defaultFallback 属性配合使用该属性指定的类中的 fallback 函数必须为 static 函数,否则无法解析。
defaultFallback默认的 fallback 函数名称,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。 默认 fallback 函数可以针对所以类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。可选项返回值类型必须与原函数返回值类型一致方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常;defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。可选项-

注意:

  • 在 Sentinel 1.6.0 之前,fallback 函数只针对降级异常(DegradeException)进行处理,不能处理业务异常。
  • 注解方式埋点不支持 private 方法。
  • 特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandlerfallbackdefaultFallback,则被限流降级时会将 BlockException 直接抛出

3.3 代码示例

@RestController
public class BuyController 

    @GetMapping("buy/name/count")
    @SentinelResource(value = "buy", fallback = "buyFallback", blockHandler = "buyBlock")
    public String buy(@PathVariable String name, @PathVariable Integer count) 
        if (count >= 20) 
            throw new IllegalArgumentException("购买数量过多");
        
        if ("car".equalsIgnoreCase(name)) 
            throw new NullPointerException("已售罄");
        
        return "购买了"+count+"个"+name;
    

    // 异常回退
    public String buyFallback(@PathVariable String name, @PathVariable Integer count, Throwable throwable) 
        return String.format("【进入fallback方法】购买%d份%s失败,%s", count, name, throwable.getMessage());
    

    // sentinel回退
    public String buyBlock(@PathVariable String name, @PathVariable Integer count, BlockException e) 
        return String.format("【进入blockHandler方法】购买%d份%s失败,当前购买人数过多,请稍后再试", count, name);
    

在控制台配置流控规则后再进行测试发现:走了对应的回退方法。

在当前类中编写回退方法会使得代码变得冗余耦合度高,我们可以将回退方法抽取出来到指定类中。

public class BuyFallback 
    // 异常回退
    public static String buyFallback(@PathVariable String name, @PathVariable Integer count, Throwable throwable) 
        return String.format("【进入fallback方法】购买%d份%s失败,%s", count, name, throwable.getMessage());
    


public class BuyBlockHandler 
    
    // sentinel回退
    public static String buyBlock(@PathVariable String name, @PathVariable Integer count, BlockException e) 
        return String.format("【进入blockHandler方法】购买%d份%s失败,当前购买人数过多,请稍后再试", count, name);
    

然后注解中的值可以简化为:

@SentinelResource(value = "buy",
            fallback = "buyFallback",
            fallbackClass = BuyFallBack.class,
            blockHandler = "buyBlock",
            blockHandlerClass = BuyBlockHandler.class
    )

fallbackClassblockHandlerClass指定回退方法所在的类。

此外我们也可以当遇到某个类型的异常时,不进行回退。比如

    @SentinelResource(value = "buy",
            fallback = "buyFallback",
            fallbackClass = BuyFallBack.class,
            blockHandler = "buyBlock",
            blockHandlerClass = BuyBlockHandler.class,
            exceptionsToIgnore = NullPointerException.class
    )

exceptionsToIgnore指定,当遇到空指针异常时,不回退。

四、Sentinel的流控熔断降级规则

4.1 服务降级

  1. 什么是服务降级

    服务降级一般是指在服务器压力剧增的时候,根据实际业务使用情况以及流量,对一些服务和页面有策略的不处理或者用一种简单的方式进行处理,从而**释放服务器资源的资源以保证核心业务的正常高效运行。**说白了,就是尽可能的把系统资源让给优先级高的服务。

  2. 为什么需要服务降级

    服务器的资源是有限的,而请求是无限的。在用户使用即并发高峰期,会影响整体服务的性能,严重的话会导致宕机,以至于某些重要服务不可用。故高峰期为了保证核心功能服务的可用性,就需要对某些服务降级处理。可以理解为舍小保大

  3. 应用场景

    多用于微服务架构中,一般当整个微服务架构整体的负载超出了预设的上限阈值(和服务器的配置性能有关系),或者即将到来的流量预计会超过预设的阈值时(比如双11、6.18等活动或者秒杀活动)

  4. 服务降级策略

    • 拒绝服务
    • 关闭服务

4.2 服务熔断

1️⃣什么是服务熔断?

应对微服务雪崩效应的一种链路保护机制,类似股市、保险丝,可看作降级的特殊情况

2️⃣为什么需要服务熔断?

​ 微服务之间的数据交互是通过远程调用来完成的。服务A调用服务,服务B调用服务c,某一时间链路上对服务C的调用响应时间过长或者服务C不可用,随着时间的增长,对服务C的调用也越来越多,导致请求的堆积,然后服务C崩溃了,但是链路调用还在,对服务B的调用也在持续增多,然后服务B崩溃,随之A也崩溃,导致雪崩效应

服务熔断是应对雪崩效应的一种微服务链路保护机制。例如在高压电路中,如果某个地方的电压过高,熔断器就会熔断,对电路进行保护。同样,在微服务架构中,熔断机制也是起着类似的作用。当调用链路的某个微服务不可用或者响应时间太长时,会进行服务熔断,不再有该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路

服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用

在Spring Cloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。

4.3 服务降级与熔断的区别

  1. 触发原因不一样,服务熔断由链路上某个服务引起的,服务降级是从整体的负载考虑
  2. 管理目标层次不一样,服务熔断是一个框架层次的处理,服务降级是业务层次的处理
  3. 实现方式不一样,服务熔断一般是自我熔断恢复,服务降级相当于人工控制
  4. 触发原因不同,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑

4.4 流量控制

Sentinel除了提供服务的熔断与降级以外,还提供了流量控制来保证服务的高可用流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果

4.5 流控规则

FlowSlot 会根据预设的规则,结合前面 NodeSelectorSlotClusterBuilderSlotStatisticSlot 统计出来的实时信息进行流量控制。

限流的直接表现是在执行 Entry nodeA = SphU.entry(resourceName) 的时候抛出 FlowException 异常。FlowExceptionBlockException 的子类,您可以捕捉 BlockException 来自定义被限流之后的处理逻辑。

同一个资源可以创建多条限流规则。FlowSlot 会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。

一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:

  • resource:资源名,即限流规则的作用对象
  • count: 限流阈值
  • grade: 限流阈值类型(QPS 或并发线程数)
  • limitApp: 流控针对的调用来源,若为 default 则不区分调用来源
  • strategy: 调用关系限流策略
  • controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)

结合控制台来看:

参数解释:

  • 资源名:Sentinel定义的资源名称,通常在代码中通过@SentinelResource进行埋点,名称唯一

  • 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,指定对哪个微服务进行限流 ,默认default(不区分来源,全部限制)

    • default :表示不区分调用者,来自任何调用者的请求都将进行限流统计。如果这个资源名的调用总和超过了这条规则定义的阈值,则触发限流(默认)
    • some_origin_name:表示针对特定的调用者,只有来自这个调用者的请求才会进行流量控制。例如 NodeA 配置了一条针对调用者caller1的规则,那么当且仅当来自 caller1NodeA 的请求才会触发流量控制。
    • other:表示针对除 some_origin_name 以外的其余调用方的流量进行流量控制。例如,资源NodeA配置了一条针对调用者 caller1 的限流规则,同时又配置了一条调用者为 other 的规则,那么任意来自非 caller1NodeA 的调用,都不能超过 other 这条规则定义的阈值。
  • 阈值类型:流量控制主要有两种统计类型,一种是统计并发线程数,另外一种则是统计 QPS

    • QPS:当 QPS 超过某个阈值的时候,则采取措施进行流量控制

    • 并发线程数控制:当调用该接口的线程数超过阈值时,进行限流

      **并发数控制用于保护业务线程池不被慢调用耗尽。**例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。

  • 单机阈值

    • 基于QPS:QPS的阈值,超过该阈值会进行流控
    • 基于线程数:线程的阈值,超过该阈值拒绝请求
  • 流控效果:当 QPS 超过某个阈值的时候,则采取措施进行流量控制,流量控制的效果包括以下几种:直接拒绝(快速失败)、Warm Up匀速排队(排队等待)

    • 快速失败:该方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException

    • Warm Up:即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮

    • 排队等待:该方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法

      该方式的作用如下图所示:

      这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求

      注意:匀速排队模式暂时不支持 QPS > 1000 的场景。

  • 流控模式

    • 直接:接口达到限流条件时,直接限流

    • 关联:当关联的资源达到阈值时,就限流自己

      当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_dbwrite_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategyRuleConstant.STRATEGY_RELATE 同时设置 refResourcewrite_db。这样当写库操作过于频繁时,读数据的请求会被限流

    • 只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就可以限流)[api级别的针对来源]

      Sentinel链路流控失效请参考Issues Sentinel 链路流控模式失效 #1213

4.6 熔断降级规则

慢调用比例 (SLOW_REQUEST_RATIO):

选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

  1. 异常比例 (ERROR_RATIO)

    当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

  2. 异常数 (ERROR_COUNT)

    当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。

@SentinelResource 注解会自动统计业务异常,无需手动调用。其他统计异常方式请参考官网:熔断降级

五、规则持久化与动态规则

Sentinel 的理念是开发者只需要关注资源的定义,当资源定义成功后可以动态增加各种流控降级规则。Sentinel 提供两种方式修改规则:

  • 通过 API 直接修改 (loadRules)、或者在代码中写死
  • 通过 DataSource 适配不同数据源修改

由于手动通过API定义规则是一种硬编码的方式,不够灵活,肯定不能应用于生产环境。

所以要引入DataSource,规则设置可以存储在数据源中,通过更新数据源中存储的规则,推送到Sentinel规则中心,客户端就可以实时获取最新的规则,根据最新的规则进行限流、降级。

推送模式说明优点缺点
原始模式API 将规则推送至客户端并直接更新到内存中,扩展写数据源简单,无任何依赖不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境
Pull 模式扩展写数据源, 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等简单,无任何依赖;规则持久化不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。
Push 模式扩展读数据源,规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。规则持久化;一致性;快速引入第三方依赖

3.2 拉模式

实现拉模式的数据源最简单的方式是继承 AutoRefreshDataSource 抽象类,然后实现 readSource() 方法,在该方法里从指定数据源读取字符串格式的配置数据。比如 基于文件的数据源

由此看出这是一个双向读写的过程,我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel 控制台推送规则。下图为控制台推送规则的流程图。

3.3 推模式

拉模式实时性不能保证,推模式就解决了这个问题。除此之外还可以持久化,也就是数据保存在数据源中,即使重启也不会丢失之前的配置,这也解决了原始模式存在内存中不能持久化的问题。

可以和Sentinel配合使用的数据源有很多种,比如ZooKeeper,Nacos,Apollo等等。这里演示使用Nacos的方式。

1️⃣ 准备Nacos环境

引入依赖:

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

在配置文件中配置数据源:

spring:
  application:
    name: wz-service
  cloud:
    sentinel:
      transport:
        #配置 Sentinel dashboard 地址
        dashboard: 192.168.199.128Sentinel :微服务哨兵

soul从入门到放弃12--sentinel插件

Alibaba Sentinel

Java面试基础知识,从入门到核心实战

Sentinel:万字详解微服务的哨兵机制,我跪了

熔断限流