服务保护 Sentinel

服务保护 Sentinel

  • Sentinel 介绍
  • Sentinel 的下载使用
  • Sentinel 流控规则
    • 流控规则介绍
    • 流控规则演示
  • Sentinel 热点规则
  • Sentinel 隔离和熔断降级
    • Feign 整合 Sentinel
    • 线程隔离
    • 熔断降级
  • Sentinel 授权规则
  • Sentinel 系统规则
  • Sentinel 自定义异常
  • Sentinel 资源定义
    • url 默认资源
    • 抛出异常的方式定义资源
    • 返回布尔值方式定义资源
    • 注解方式定义资源
  • Sentinel 数据持久化
    • 原始模式
    • Pull 模式
    • Push模式

Sentinel 介绍

服务链:随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。在一次请求中,多个服务就构成了一条调用的服务链路。

雪崩问题:在微服务架构中,一个服务出现故障或者异常,导致其他服务也出现故障或者异常,从而形成连锁反应,导致整个系统崩溃的问题。

微服务雪崩问题的原因:

  • 服务雪崩:一个服务出现故障,导致其他服务也出现故障。
  • 资源耗尽:一个服务占用太多的资源,导致其他服务无法获取足够的资源而出现故障。
  • 并发量过高:一个服务并发量过高,导致系统负载过重而出现故障。

解决微服务雪崩问题的方式:

  • 超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待。
  • 仓壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。
  • 断路器模式:由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。
  • 流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。

Sentinel 是阿里巴巴微服务生态下的流量治理中心,可以实现流量控制、熔断降级、系统自适应保护等功能,从而解决服务雪崩的问题。

Sentinel 的核心思想是控制流量,它可以通过限流、熔断、降级等手段来控制流量,避免系统过载,从而保护系统的稳定性和可用性。具体来说,当系统流量超出预设阈值时,Sentinel 会自动触发熔断降级操作,停止对该服务的调用,从而避免服务链路中的其他服务受到影响,避免服务雪崩的发生。

Sentinel官网地址

Sentinel分为两个部分:
核心库(Java客户端):不依赖任何框架/库,能够运行于所有Java运行时环境,同时对Dubbo/ Spring Cloud等框架也有较好的支持。
控制台(Dashboard):基于Spring Boot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。

Sentinel 的核心概念

  • 资源(Resource):资源是 Sentinel 的关键概念,它可以是 Java 应用程序中的任何内容,例如由应用程序提供的服务,或由应用程序调用的其他应用提供的服务,甚至可以是一段代码。
  • 规则(Rule):围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。
  • 流量控制(FlowControl):通过限流来保护系统,当流量超出预设阈值时,Sentinel 会自动触发熔断降级操作。
  • 熔断降级(CircuitBreaker):当某个服务发生故障时,通过熔断降级来避免服务链路中的其他服务受到影响。
  • 系统保护(SystemProtection):通过系统保护来避免系统过载,从而保护系统的稳定性和可用性。

Sentinel 的下载使用

下载 Sentinel 控制台程序,

  • 下载地址
  • 运行命令:java -jar sentinel-dashboard-1.8.1.jar
  • 访问地址:http://localhost:8080/,登录账户:sentinel,登录密码:sentinel

请添加图片描述

微服务整合Sentinel
在pom文件中,新增依赖

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

在配置文件中新增 sentinel 相关的配置

spring:cloud:sentinel:transport:dashboard: http://localhost:8080

完成配置后,重启应用,访问微服务的任意端点,触发sentinel监控。
请添加图片描述

Sentinel 流控规则

簇点链路:就是项目内的调用链路,链路中被监控的每个接口就是一个资源。默认情况下 sentinel 会监控 SpringMVC 的每一个端点(Endpoint),因此 SpringMVC 的每一个端点(Endpoint)就是调用链路中的一个资源。流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后面的按钮来设置规则:
请添加图片描述
点击资源后的流控按钮,弹出如下表单,可以添加流控规则。
QPS(每秒查询率) :QPS 通常用于描述系统或应用程序在单位时间内能够处理的查询或请求量。通过设置QPS来进行流量控制。
线程数:通过并发的线程数量来进行流量控制。
请添加图片描述

流控规则介绍

选择高级选项,可以看到更多的流控设置规则。
在这里插入图片描述

  • 资源名:一般是我们的请求路径
  • 针对来源:是指来自于哪个应用
  • 阈值类型:分为QPS或线程数
  • 单机阈值:单个节点的QPS或线程数阈值
  • 是否集群:被请求的服务是否集群部署
  • 流控模式:
    • 直接,统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式
    • 关联,统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
    • 链路,统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流
  • 流控效果:(线程数阈值类型不存在此属性)
    • 快速失败,达到阈值后,新的请求会被立即拒绝并抛出 FlowException 异常。是默认的处理方式。
    • Warm Up,预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。
    • 排队等待,在QPS阈值到达后,让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。如果等待时间超出最大时长,则会被拒绝。可以适用于突发流量的请求。

流控规则演示

流控模式直接:

当请求的资源 QPS大于1的时候,就会直接失败。

请添加图片描述

请添加图片描述
流控模式关联:

请添加图片描述
当 /write 资源访问量触发阈值时,就会对 /read 资源限流,避免影响 /write 资源。

流控模式链路:
链路模式:只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值。
请求链路:/test1 —> /test2
请添加图片描述
只统计从/test1 进入/test2 的请求,当链路请求大于阈值,则快速失败。

流控效果快速失败:
快速失败方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。
请添加图片描述
流控效果Warm Up:
Warm Up 方式,即预热模式,是应对服务冷启动的一种方案。。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
请求阈值初始值是 threshold / coldFactor,持续指定时长后,逐渐提高到 threshold 值。而coldFactor的默认值是 3。

例如,设置QPS的 threshold 为10,预热时间为5秒,那么初始阈值就是 10 / 3 ,也就是3,然后在5秒后逐渐增长到10。
请添加图片描述
流控效果排队等待:
当请求超过 QPS 阈值时,快速失败和 warm up 会拒绝新的请求并抛出异常。而排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。

例如:QPS = 5,意味着每200ms处理一个队列中的请求;timeout = 2000,意味着预期等待超过2000ms的请求会被拒绝并抛出异常
请添加图片描述

Sentinel 热点规则

之前的限流是统计访问某个资源的所有请求,判断是否超过QPS阈值。而热点参数限流是分别统计参数值相同的请求,判断是否超过QPS阈值。

在这里插入图片描述
热点规则配置页,其中参数类型只支持基本的七种数据类型,热点参数限流对默认的SpringMVC资源无效,热点规则的资源名要使用 @SentinelResource 进行定义。

在这里插入图片描述
在代码中 使用 @SentinelResource 注解定义热点规则资源

@SentinelResource("hot")
@GetMapping("order/{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {// 根据id查询订单并返回return orderService.queryOrderById(orderId);
}

新增热点规则,hot 资源 的 0号 long类型参数限流,每1秒相同参数的QPS不能超过5,然后设置了两个参数例外项,如果参数值是1,则每1秒允许的QPS为10,如果参数值是2,则每1秒允许的QPS为15
在这里插入图片描述

Sentinel 隔离和熔断降级

Sentinel 隔离和熔断降级都是微服务架构中的保护措施,用于防止故障扩散和保证系统可用性。
Sentinel 隔离是通过线程池隔离和熔断降级,将故障控制在一个可控范围内,避免雪崩的现象。

线程池隔离:调用者在调用服务提供者时,给每个调用的请求分配独立线程池,出现故障时,最多消耗这个线程池内资源,避免把调用者的所有资源耗尽。

熔断降级:在调用方这边加入断路器,统计对服务提供者的调用,如果调用的失败比例过高,则熔断该业务,不允许访问该服务的提供者。

Sentinel 隔离和熔断降级都需要在调用方进行设置,因此需要在调用方发起远程调用时进行线程隔离、或者服务熔断。

Feign 整合 Sentinel

在微服务中服务的远程调用都是通过Feign来实现的,所以客户端保护必须整合Feign和Sentinel。

导入 OpenFeign 依赖和 Sentinel依赖

<!--feign客户端依赖-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--引入sentinel依赖-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

在配置文件中进行设置

spring:cloud:sentinel:transport:dashboard: http://localhost:8080
#开启feign对Sentinel的支持,默认为false
feign:sentinel:enabled: true

主启动类添加注解 @EnableFeignClients 激活 openFeign
使用openFeign 客户端进行远程调用,并编写调用失败后的降级逻辑。

UserClient 客户端,fallbackFactory 指定了调用失败后的处理降级逻辑的工厂类

@FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);
}

UserClientFallbackFactory 实现 FallbackFactory接口,指明要生成的客户端类。在 create 方法中重写客户端类的逻辑,在客户端类调用失败后,会使用工厂类生成新的客户端,并进行调用。

@Slf4j
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {@Overridepublic UserClient create(Throwable throwable) {return new UserClient() {@Overridepublic User findById(Long id) {log.error("查询用户异常", throwable);return new User();}};}
}

需要将 UserClientFallbackFactory 注入容器。

@Bean
public UserClientFallbackFactory userClientFallbackFactory(){return new UserClientFallbackFactory();
}

使用 UserClient 进行远程调用,如果远程调用失败,则会调用失败后的降级逻辑

@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {// 1.查询订单Order order = orderMapper.findById(orderId);// 2.用Feign远程调用User user = userClient.findById(order.getUserId());// 3.封装user到Orderorder.setUser(user);// 4.返回return order;
}

线程隔离

Sentinel 可以设置线程数来进行限流。
当调用某个 API 的线程数达到设定的阈值时,Sentinel 会进行限流,即拒绝继续提供服务。

线程隔离有两种方式实现:

  • 线程池隔离,给每个服务调用业务分配一个线程池,利用线程池本身实现隔离效果
  • 信号量隔离:不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求。(Sentinel默认采用)

请添加图片描述

在添加限流规则时,设置线程数的值。即可实现线程隔离
在这里插入图片描述

熔断降级

熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。

断路器的三个状态, closed, open, half-open。
在closed状态,服务可以正常访问,会统计服务的失败比例,达到阈值会进行 open状态,服务会不可用,在熔断时间结束后,会进入 half-open状态,尝试放行服务,请求成功会进入 closed,失败会进入open状态,继续进行熔断。
请添加图片描述
断路器熔断策略有三种:慢调用、异常比例、异常数

慢调用:业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。

解读:RT超过500ms的调用是慢调用,统计最近1000s内的请求,如果请求量超过5次,并且慢调用比例不低于0.5,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试。
请添加图片描述
异常比例或异常数:统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断。

解读:统计最近1000ms内的请求,如果请求量超过10次,并且异常比例不低于0.5,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试。
请添加图片描述
解读:统计最近1000ms内的请求,如果请求量超过10次,并且异常数不低于4,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试。
请添加图片描述

Sentinel 授权规则

授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式。

白名单:来源(origin)在白名单内的调用者允许访问
黑名单:来源(origin)在黑名单内的调用者不允许访问
请添加图片描述
获取请求来源方式
Sentinel 是通过 RequestOriginParser 接口的 parseOrigin 来获取请求的来源的。

public interface RequestOriginParser {// 从请求request对象中获取origin,获取方式自定义  String parseOrigin(HttpServletRequest request);
}

实现接口,获取 origin。

@Component
public class HeaderOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest request) {// 1.获取请求参数String origin = request.getParameter("origin");// 2.非空判断if (StringUtils.isEmpty(origin)) {origin = "blank";}return origin;}
}

定义白名单
请添加图片描述
在进行请求时,如果请求参数中携带 origin 参数,且值为 white,则可以进行正常访问。

定义黑名单请添加图片描述
在进行请求时,如果请求参数中携带 origin 参数,值为 black,则不能访问,未携带 origin 参数,或值不为 black,则可以进行访问。

Sentinel 系统规则

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

系统规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口 QPS 和线程数四个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

系统规则支持以下的阈值类型

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
    在这里插入图片描述

Sentinel 自定义异常

默认情况下,发生限流、降级、授权拦截时,都会抛出异常到调用方。
返回的错误是:“Blocked by Sentinel (flow limiting)”,这对调用方很不友好,可以自定义异常处理。

如果要自定义异常时的返回结果,需要实现 BlockExceptionHandler 接口:

public interface BlockExceptionHandler {/*     * 处理请求被限流、降级、授权拦截时抛出的异常:BlockException     */    void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception;
}

而 BlockException 包含很多个子类,分别对应不同的场景:

在这里插入图片描述
自定义异常类具体实现

@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {String msg = "未知异常";int status = 429;if (e instanceof FlowException) {msg = "请求被限流了";} else if (e instanceof ParamFlowException) {msg = "请求被热点参数限流";} else if (e instanceof DegradeException) {msg = "请求被降级了";} else if (e instanceof AuthorityException) {msg = "没有权限访问";status = 401;}response.setContentType("application/json;charset=utf-8");response.setStatus(status);response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}");}
}

Sentinel 资源定义

资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。

使用 Sentinel 来进行资源保护,主要分为几个步骤:

  • 定义资源
  • 定义规则
  • 检验规则是否生效

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

url 默认资源

Sentinel 为 Spring Boot 程序提供了一个 starter 依赖,由于Sentinel starter 依赖默认情况下就会把所有的HTTP服务定义为资源,所以在 Spring Boot 中的 Controller 都可以受到Sentinel的保护,当然,还需要为Sentinel配置保护的规则。

可以在 application.yaml 中,通过配置关闭对微服务的默认保护。

spring:cloud:sentinel:transport:dashboard: http://localhost:8080#关闭sentinel对controller的url的保护,默认为 truefilter:enabled: false

抛出异常的方式定义资源

SphU 包含了 try-catch 风格的 API。用这种方式,当资源发生了限流之后会抛出 BlockException。这个时候可以捕捉异常,进行限流之后的逻辑处理。

示例代码如下:
1.5.0 版本开始可以利用 try-with-resources 特性

// 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
try (Entry entry = SphU.entry("resourceName")) {// 被保护的业务逻辑// do something here...
} catch (BlockException ex) {// 资源访问阻止,被限流或被降级// 在此处进行相应的处理操作
}

1.5.0 之前的版本的示例:

Entry entry = null;
// 务必保证finally会被执行
try {// 资源名可使用任意有业务语义的字符串entry = SphU.entry("自定义资源名");// 被保护的业务逻辑// do something...
} catch (BlockException e1) {// 资源访问阻止,被限流或被降级// 进行相应的处理操作
} finally {if (entry != null) {entry.exit();}
}

注意:SphU.entry(xxx) 需要与 entry.exit() 方法成对出现,匹配调用,否则会导致调用链记录异常,抛出 ErrorEntryFreeException 异常。

返回布尔值方式定义资源

SphO 提供 if-else 风格的 API。用这种方式,当资源发生了限流之后会返回 false,这个时候可以根据返回值,进行限流之后的逻辑处理。

示例代码如下:

  // 资源名可使用任意有业务语义的字符串if (SphO.entry("自定义资源名")) {// 务必保证finally会被执行try {/*** 被保护的业务逻辑*/} finally {SphO.exit();}} else {// 资源访问阻止,被限流或被降级// 进行相应的处理操作}

注解方式定义资源

Sentinel 支持通过 @SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理。

@SentinelResource 注解包含以下属性:

  • value:资源名称,必需项

  • entryType:entry 类型,可选项(默认为 EntryType.OUT)

  • blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。

    • blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。
    • blockHandler 函数默认需要和原方法在同一个类中。
    • 若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • fallback / fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
    fallback 函数签名和位置要求:

    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • fallback 函数默认需要和原方法在同一个类中。
    • 若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • defaultFallback(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所以类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。
    defaultFallback 函数签名要求:

    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • defaultFallback 函数默认需要和原方法在同一个类中。
    • 若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

注解方式埋点不支持 private 方法。

代码示例:
若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。

// 原方法调用被限流/降级/系统保护的时候调用
public class MyBlockHandler {public static String testC(@PathVariable("id") int id, BlockException blockException) {return "testC:" + id + ",限流了,msg:" + blockException.getMessage();}
}
// 原方法出现业务异常的时候调用
public class MyFallback {public static String testC(@PathVariable("id") int id, Throwable t) {return "testC:" + id + ",降级了,msg:" + t.getMessage();}
}@SentinelResource(value = "testC",blockHandler = "testC", blockHandlerClass = MyBlockHandler.class,//处理sentinel规则的兜底方法fallback = "testC", fallbackClass = MyFallback.class //处理当前控制器业务异常的熔断降级的兜底方法
)
@RequestMapping("/goods/testC/{id}")
public String testC(@PathVariable("id") int id) {//模拟业务正常if (id == 1) {return "server port:" + port + ",testC...";}//模拟业务出错if (id == 2) {int i = 1 / 0;}return "other ...";
}

Sentinel 数据持久化

Sentinel的控制台规则管理有三种模式:

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

原始模式

原始模式:控制台配置的规则直接推送到 Sentinel客户端,也就是我们的应用。然后保存在内存中,服务重启则丢失。
在这里插入图片描述

Pull 模式

pull模式:控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则。
在这里插入图片描述
需要指定数据源,将规则写入数据源中,实现定时更新数据源中的规则。
通常需要调用以下方法将数据源注册至指定的规则管理器中:

ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId, parser);
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());

若不希望手动注册数据源,可以借助 Sentinel 的 InitFunc SPI 扩展接口。只需要实现自己的 InitFunc 接口,在 init 方法中编写注册数据源的逻辑。

package com.test.init;
public class DataSourceInitFunc implements InitFunc {@Overridepublic void init() throws Exception {final String remoteAddress = "localhost";final String groupId = "Sentinel:Demo";final String dataId = "com.alibaba.csp.sentinel.demo.flow.rule";ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId,source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));FlowRuleManager.register2Property(flowRuleDataSource.getProperty());}
}

接着将对应的类名添加到位于资源目录(通常是 resource 目录)下的 META-INF/services 目录下的 com.alibaba.csp.sentinel.init.InitFunc 文件中,比如:

// 全限定类名
com.test.init.DataSourceInitFunc

当初次访问任意资源的时候,Sentinel 就可以自动去注册对应的数据源了。

实现本地文件数据源会定时轮询文件的变更,读取规则。

package cn.itcast.order.sentinel;public class FileDataSourceInit implements InitFunc {@Overridepublic void init() throws Exception {//可以根据需要指定规则文件的位置String ruleDir = System.getProperty("user.home") + "/sentinel/rules";String flowRulePath = ruleDir + "/flow-rule.json";String degradeRulePath = ruleDir + "/degrade-rule.json";String paramFlowRulePath = ruleDir + "/param-flow-rule.json";String systemRulePath = ruleDir + "/system-rule.json";String authorityRulePath = ruleDir + "/authority-rule.json";this.mkdirIfNotExits(ruleDir);this.createFileIfNotExits(flowRulePath);this.createFileIfNotExits(degradeRulePath);this.createFileIfNotExits(paramFlowRulePath);this.createFileIfNotExits(systemRulePath);this.createFileIfNotExits(authorityRulePath);// 流控规则:可读数据源ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(flowRulePath,flowRuleListParser);// 将可读数据源注册至FlowRuleManager// 这样当规则文件发生变化时,就会更新规则到内存FlowRuleManager.register2Property(flowRuleRDS.getProperty());// 流控规则:可写数据源WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(flowRulePath,this::encodeJson);// 将可写数据源注册至transport模块的WritableDataSourceRegistry中// 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);// 降级规则:可读数据源ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(degradeRulePath,degradeRuleListParser);DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());// 降级规则:可写数据源WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(degradeRulePath,this::encodeJson);WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);// 热点参数规则:可读数据源ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(paramFlowRulePath,paramFlowRuleListParser);ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());// 热点参数规则:可写数据源WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath,this::encodeJson);ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);// 系统规则:可读数据源ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(systemRulePath,systemRuleListParser);SystemRuleManager.register2Property(systemRuleRDS.getProperty());// 系统规则:可写数据源WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(systemRulePath,this::encodeJson);WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);// 授权规则:可读数据源ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(authorityRulePath,authorityRuleListParser);AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());// 授权规则:可写数据源WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(authorityRulePath,this::encodeJson);WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);}private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<FlowRule>>() {});private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<DegradeRule>>() {});private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<SystemRule>>() {});private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<AuthorityRule>>() {});private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<ParamFlowRule>>() {});private void mkdirIfNotExits(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.mkdirs();}}private void createFileIfNotExits(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {file.createNewFile();}}private <T> String encodeJson(T t) {return JSON.toJSONString(t);}
}

接着将对应的类名添加到位于资源目录(通常是 resource 目录)下的 META-INF/services 目录下的 com.alibaba.csp.sentinel.init.InitFunc 文件中,比如:

cn.itcast.order.sentinel.FileDataSourceInit

在控制台创建规则后,会自动写入到文件中。
在这里插入图片描述

Push模式

push模式:控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新。
在这里插入图片描述
基于Nacos配置中心控制台实现规则推送
配置中心控制台 → nacos 配置中心 → Sentinel数据源 → Sentinel

引入依赖

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

修改配置文件,设置 nacos 数据源地址

spring:application:name: orderservicecloud:nacos:server-addr: localhost:8848 # nacos服务地址sentinel:transport:dashboard: localhost:8080 # sentinel控制台地址filter:enabled: falseweb-context-unify: false # 关闭context整合datasource:  # 设置数据源ds1:nacos:server-addr: localhost:8848 # nacos地址dataId: orderservice-flow-rulesgroupId: SENTINEL_GROUPrule-type: flow # 还可以是:degrade、authority、param-flow

进入 nacos 控制台创建文件

请添加图片描述
重启应用,就可以在 Sentinel 控制台,看到对应的限流规则。
请添加图片描述
注意:在Nacos控制台上修改规则,可以同步到Sentinel Dashboard,但是在Sentinel Dashboard上修改规则后不能同步到 Nacos。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/3713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【力扣周赛】第 354 场周赛

文章目录 Q1&#xff1a;6889. 特殊元素平方和思路——简单模拟题竞赛时代码 Q2&#xff1a;6929. 数组的最大美丽值思路——差分数组&#xff0c;计算每个数字可能出现的次数竞赛时代码解法2——排序 双指针⭐解法3——排序 二分查找 Q3&#xff1a;6927. 合法分割的最小下标…

Linux 漏洞扫描

Linux 漏洞扫描程序会仔细检查基于 Linux 的系统&#xff0c;以减轻潜在的风险和漏洞。 什么是 Linux 漏洞扫描程序 Linux 漏洞扫描程序是一种专门的漏洞扫描工具&#xff0c;旨在识别基于 Linux 的系统中的安全漏洞和弱点,它会扫描配置错误、过时的软件版本和已知漏洞。 为…

pytorch学习--第一个模型(线性模型)

目标 我们想通过随机初始化的参数 ω , b \omega ,b ω,b能在迭代过程中使预测值和目标值能无限接近 y ω x b y\omega xb yωxb 定义数据 x torch.rand([60, 1])*10 y x*2 torch.randn(60,1)构建模型 利用pytorch中的nn.Module 想要构建模型时&#xff0c;继承这个类…

(四)「消息队列」之 RabbitMQ 路由(使用 .NET 客户端)

0、引言 先决条件 本教程假设 RabbitMQ 已安装并且正在 本地主机 的标准端口&#xff08;5672&#xff09;上运行。如果您使用了不同的主机、端口或凭证&#xff0c;则要求调整连接设置。 获取帮助 如果您在阅读本教程时遇到问题&#xff0c;可以通过邮件列表或者 RabbitMQ 社区…

Meta发布升级大模型LLaMA 2:开源可商用

论文地址&#xff1a;https://ai.meta.com/research/publications/llama-2-open-foundation-and-fine-tuned-chat-models/ Github地址&#xff1a;https://github.com/facebookresearch/llama LLaMA 2介绍 Meta之前发布自了半开源的大模型LLaMA&#xff0c;自从LLaMA发布以来…

C# WPF实现动画渐入暗黑明亮主题切换效果

C# WPF实现动画渐入暗黑明亮主题切换效果 效果图如下最近在Bilibili的桌面端看到一个黑白主题切换的效果感觉&#xff0c;挺有意思。于是我使用WPF尝试实现该效果。 主要的切换效果&#xff0c;基本实现不过还存在一些小瑕疵&#xff0c;比如字体等笔刷不能跟随动画进入进行切…

Docker简介

Docker简介 文章目录 Docker简介一、Docker1.什么是docker?2.容器引擎3.容器和虚拟机的区别4.namespace&#xff08;命名空间&#xff09;5.三大容器核心概念镜像容器仓库 二、Docker镜像操作1.搜索镜像2.获取镜像镜像加速下载 3.查看本地下载镜像4.获取镜像详细信息5.为本地镜…

SQL 上升的温度

197 上升的温度 SQL架构 表&#xff1a; Weather ---------------------- | Column Name | Type | ---------------------- | id | int | | recordDate | date | | temperature | int | ---------------------- id 是这个表的主键 该表包含特定日期的温度信息 编写一个 SQL …

事务@transactional执行产生重复数据

背景 系统设计之初&#xff0c;每次来新请求&#xff0c;业务层会先查询数据库&#xff0c;判断是否存在相同的id数据&#xff08;id是唯一标识产品的&#xff09;&#xff0c;有则返回当前数据库查到的数据&#xff0c;根据数据决定下一步动作&#xff0c;没有则认为是初次请…

销售自动化如何提高团队生产力?从这5个方面发力

任何用于减少人工劳动和缩短销售流程相关任务时间的技术&#xff0c;都可定义为销售自动化。 对于忙碌的销售人员来说&#xff0c;流程自动化是真正的救星。它可以使他们的工作简化30%&#xff0c;让他们更专注于创收任务。这将显著提高团队的工作效率&#xff0c;并带来许多其…

滑动奇异频谱分析:数据驱动的非平稳信号分解工具(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

师承AI世界新星|7天获新加坡南洋理工大学访学邀请函

能够拜师在“人工智能10大新星”名下&#xff0c;必定可以学习到前沿技术&#xff0c;受益良多&#xff0c;本案例中的C老师无疑就是这个幸运儿。我们只用了7天时间就取得了这位AI新星导师的邀请函&#xff0c;最终C老师顺利获批CSC&#xff0c;如愿出国。 C老师背景&#xff1…

Leetcode刷题4

⼆叉树、BFS、堆、Top K、⼆叉搜索树、模拟、图算法 一、二叉树 二叉树的前序中序后序 二叉树节点定义 为了方便演示&#xff0c;我们先定义一个二叉树节点类。 class TreeNode:def __init__(self, val0, leftNone, rightNone):self.val valself.left leftself.right r…

Android ViewGroup onDraw为什么没调用

ViewGroup&#xff0c;它本身并没有任何可画的东西&#xff0c;它是一个透明的控件&#xff0c;因些并不会触发onDraw&#xff0c;但是你现在给LinearLayout设置一个背景色&#xff0c;其实这个背景色不管你设置成什么颜色&#xff0c;系统会认为&#xff0c;这个LinearLayout上…

[回馈]ASP.NET Core MVC开发实战之商城系统(开篇)

在编程方面&#xff0c;从来都是实践出真知&#xff0c;书读百遍其义自见&#xff0c;所以实战是最好的提升自己编程能力的方式。 前一段时间&#xff0c;写了一些实战系列文章&#xff0c;如&#xff1a; ASP.NET MVC开发学生信息管理系统VueAntdvAsp.net WebApi开发学生信息…

R语言的水文、水环境模型优化技术及快速率定方法与多模型案例实践

在水利、环境、生态、机械以及航天等领域中&#xff0c;数学模型已经成为一种常用的技术手段。同时&#xff0c;为了提高模型的性能&#xff0c;减小模型误用带来的风险&#xff1b;模型的优化技术也被广泛用于模型的使用过程。模型参数的快速优化技术不但涉及到优化本身而且涉…

Python中的break和continue语句应用举例

Python中的break和continue语句应用举例 在进行Python编程时候&#xff0c;有时需要&#xff0c;对循环中断或跳过某部分语句&#xff0c;此时常会用到break语句或continue语句。本文将通过实际例子阐述这两个语句的用法。 1.break语句 break语句是实现在某个地方中断循环&a…

Java设计模式之行为型-迭代器模式(UML类图+案例分析)

目录 一、基础概念 二、UML类图 三、角色设计 四、案例分析 五、总结 一、基础概念 迭代器模式是一种常用的设计模式&#xff0c;它主要用于遍历集合对象&#xff0c;提供一种方法顺序访问一个聚合对象中的各个元素&#xff0c;而又不暴露该对象的内部表示。 举个简单的…

5分钟给你破解这套10万赞的生产教程,访谈乔布斯的AI对话数字人视频是怎么做的

本期是赤辰第16期AI项目拆解栏目&#xff1b; 底部准备了7月粉丝福利&#xff0c;看完可以领取&#xff1b; 上周给粉丝们讲解AI动图说话月涨粉20万的案例并给出保姆式教程&#xff0c;粉丝反馈很热烈&#xff0c;都觉得AI强大&#xff0c;有些学员给自己账号做视频&#xff…

大数据与视频技术的融合趋势将带来怎样的场景应用?

视频技术和AI技术的融合是一种新兴的技术趋势&#xff0c;它将改变视频行业的运作方式。视频技术和AI技术的融合主要包括以下几个方面&#xff1a; 1&#xff09;人脸识别技术 人脸识别技术是AI技术的一个重要应用场景。它可以通过对视频中的人脸进行识别和分析&#xff0c;实…