9.熔断和限流 - Alibaba Sentinel

1.熔断&限流

1.1熔断

服务熔断是指当某个服务⽆法正常为服务调⽤者提供服务时, ⽐如请求超时, 服务异常等, 为了防⽌整个系统出现雪崩效应, 暂时将出现故障的接⼝隔离出来, 断绝与外部接⼝的联系, 当触发熔断之后, 后续⼀段时间内该服务调⽤者的请求都会直接失败(⽆需等待到超时), 直到⽬标服务恢复正常.

1.2限流

限流,就是限制流量的意思

在互联⽹应⽤中, 限流可以确保服务器能够处理的请求数量在合理范围内, 避免因请求过多导致服务响应慢或失败.可以保证⽤⼾在⾼流量时段仍然能够获得快速响应, 提升⽤⼾体验.

2.Sentinel基本介绍

Sentinel 是由阿⾥巴巴开源的⼀个⾯向分布式、多语⾔异构化服务架构的流量治理组件. 主要以流量为切⼊点,从流量路由、流量控制、流量整形、熔断降级、系统⾃适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性.

2.1特性

  • 丰富的应⽤场景

阿⾥巴巴 10 年双⼗⼀积累的丰富流量场景,包括秒杀、双⼗⼀零点持续洪峰、热点商品探测、预热、消息队列削峰填⾕等多样化的场景

  • 易于使⽤, 快速接⼊

简单易⽤, 开源⽣态⼴泛, 针对 Dubbo、Spring Cloud、gRPC、Zuul、Reactor、Quarkus 等框架只需要引⼊适配模块即可快速接⼊.

  • 多样化的流量控制资源粒度、调⽤关系、指标类型、控制效果等多维度的流量控制
  • 可视化的监控和规则管理

Sentinel提供了简单易⽤的 Sentinel 控制台, 开发者可以在控制台中看到接⼊的应⽤流量, 以及配置限流规则等.

2.2组成

  • 核⼼库(Java 客⼾端) : 不依赖任何框架/库, 能够运⾏于所有 Java 运⾏时环境, 同时对 Dubbo / Spring Cloud 等框架也有较好的⽀持.
  • 控制台(Dashboard) 基于 Spring Boot 开发, 打包后可以直接运⾏, 不需要额外的 Tomcat 等应⽤容器.

2.3Sentinel Dashboard下载和部署

(1)下载

下载地址: https://github.com/alibaba/Sentinel/releases

(2)启动Sentinel Dashboard

yaml 复制代码
java -jar .\sentinel-dashboard-1.8.8.jar

(3)访问http://127.0.0.1:8080

默认⽤⼾名和密码都是: sentinel

(4)修改其他配置启动

powershell 复制代码
java -jar -Dserver.port=8100 -Dsentinel.dashboard.auth.username=admin -
Dsentinel.dashboard.auth.password=admin -
Dserver.servlet.session.timeout=1440m sentinel-dashboard.jar

3.Sentinel使用

使用Sentinel核心库实现限流

(1)添加依赖

xml 复制代码
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-core</artifactId>
</dependency>

(2)定义资源

资源是 Sentinel 的关键概念, 被Sentinel监控的每个接⼝就是⼀个资源. 它可以是 Java 应⽤程序中的任何内容, 例如, 由应⽤程序提供的服务, 或由应⽤程序调⽤的其它应⽤提供的服务, 甚⾄可以是⼀段代码。限流, 熔断等都是针对资源来设置的

java 复制代码
private static void test(int i) {
try(Entry entry = SphU.entry("resourceName")){
    //业务逻辑处理
    System.out.println("执⾏test⽅法"+ i);
} catch (BlockException e) {
    //处理限流时的逻辑
    System.out.println("触发限流.." +i );
}
}

通过使⽤Sentinel 中的 SphU.entry("resourceName") 定义⼀个资源, ⽅便后续配置流控规则. 它表⽰当请求进⼊test⽅法时, 需要进⾏限流判断, 如果抛出BlockException 异常, 则表⽰触发了限流.

(3)定义限流规则

java 复制代码
private static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("resourceName");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(10);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
}

(4)检验规则

java 复制代码
public static void main(String[] args) {
    initFlowRules();
    for (int i = 0; i < 20; i++) {
    test(i);
    }
}

4.Spring Cloud集成Sentinel

(1)添加依赖

xml 复制代码
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

(2)配置Sentinel控制台

yaml 复制代码
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8100 #sentinel控制台地址

(3)访问任意接口,触发sentinel监控

访问http://127.0.0.1:8080/order/1

5.流量控制

5.1配置流控规则

配置阈值为1, 即每秒只允许1次请求, 超出的请求会被拦截并报错

5.2基于QPS/并发数的流量控制

(1)并发线程数

线程数限流⽤于保护业务线程数不被耗尽. ⽐如A调⽤B, ⽽B服务因为某种原因导致服务不稳定或者响应延迟, 那么对于A服务来说, 它的吞吐量会 下降, 也意味着占⽤更多的线程(线程阻塞之后⼀直末释放),极端情况下会造成线程池耗尽. 针对这种问 题, 业内有使⽤隔离的⽅案,⽐如通过不同业务逻辑使⽤不同线程池来隔离业务⾃⾝之间的资源争抢(线程池隔离), 或者使⽤信号量来控制同时请求的个数(信号量隔离)。

(2)QPS流量控制

当 QPS 超过某个阈值的时候, 则进⾏流量控制。流量控制的⼿段分为三种: 快速失败, Warm Up, 排队等待

5.3流控效果

(1)快速失败

快速失败, 也就是直接拒绝, 对应 RuleConstant.CONTROL_BEHAVIOR_DEFAULT . 该⽅式是默认的流量控制⽅式,当QPS超过任意规则的阈值后,新的请求就会被⽴即拒绝,拒绝⽅式为抛出FlowException 。

(2)Warm Up

Warm up, 对应 RuleConstant.CONTROL_BEHAVIOR_WARM_UP 。Warm Up 也叫预热模式. 阈值

⼀般是⼀个微服务能承受的最⼤QPS, 但是⼀个服务刚刚启动时, ⼀切资源尚未初始化, 如果直接将QPS

跑到最⼤值, 可能导致服务瞬间宕机. 该⽅式主要⽤于系统⻓期处于低⽔位的情况下,当流量突然增加时, 直接把系统拉升到⾼⽔位可能瞬间把系统压垮的, 通过"冷启动",让通过的流量缓慢增加,在⼀定时间内逐渐增加到阈值上限,给冷系统⼀个预热的时间,避免冷系统被压垮的情况.

单机阈值设置为10, Warm Up 模式, 预热时⻓为5s:可以理解为系统在5s后单机阈值逐渐增⻓到10

(3)排队等待

排队等待, 对应 RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER . 这种⽅式严格控制了请求通过的间隔时间,也即是让请求以均匀的速度通过. 可以理解为让所有请求进⼊⼀个队列中, 然后按照阈值允许的时间间隔依次执⾏. 后⾯的请求必须等待前⾯执⾏完成, 直到超时.

超时时间也就是请求等待时⻓.

⽐如阈值为1, 那么每秒执⾏⼀个请求. 超时时间为5s. 现在⼀下⼦来了10个请求, 那么: 第3个请求的 等待时⻓为: 100 * (3-1) = 2000ms ,第6个请求的 等待时⻓为: 100 * (6-1) = 5000ms ,也就是说, 同⼀时间发起10个请求, 那么会通过6个, 拒绝4个

5.4流控模式

在添加限流规则时, 点击⾼级选项, 可以发现流控模式分为三种: 直接, 关联, 链路

(1)根据调用方限流:直接

这是默认的流量控制⽅式. 当QPS超过任意规则的阈值后, 对当前资源直接限流.

default : 表⽰不区分调⽤者, 来⾃任何调⽤者的请求都将进⾏限流统计. 如果这个资源名的调⽤总和超过了这条规则定义的阈值,则触发限流

(2)根据调用链路入口限流:链路

统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

yaml 复制代码
          /order/wirte 		/order/read
                    \ 		/
                    \ 		/
                    \ 		/
                     order

构建链路:

Http接⼝是Sentinel默认监控的资源, 不需要额外配置

java 复制代码
@RequestMapping("/write")
public String write(){
    orderService.queryOrderInfo();
    return "写操作";
}
@RequestMapping("/read")
public String read(){
    orderService.queryOrderInfo();
    return "读操作";
}

上述两个接⼝调⽤共同⽅法queryOrderInfo, 这个不属于Sentinel默认监控的资源, 通过@SentinelResource 来定义资源

java 复制代码
@SentinelResource("queryOrderInfo")
public void queryOrderInfo(){
    System.out.println("查询订单详情");
}

观察簇点链路:

发现看不到 /order/write -> queryOrderInfo 这条链路

链路模式中, 是对不同来源的两个链路做监控. 但是sentinel默认会给进⼊SpringMVC的所有请求设置同⼀个root资源, 会导致链路模式失效. 我们需要关闭这种对SpringMVC的资源聚合,

yaml 复制代码
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8100 #sentinel控制台地址
      web-context-unify: false #关闭context整合

重启服务:

设置流控规则:

只针对⼊⼝资源为 /order/write 的请求进⾏限流

(3)具有关系的资源流量控制:关联

当两个资源之间具有资源争抢或者依赖关系的时候, 这两个资源便具有了关联. 关联限流就是 统计与当前资源相关的另⼀个资源, 触发阈值时, 对当前资源限流.

设置流控规则:

当 /order/wirte 资源访问量触发阈值时, 就会对 /order/read 资源限流,避免影响 /order/wirte 资源

6.热点参数限流

热点即经常访问的数据.

热点参数限流会统计传⼊参数中的热点参数, 并根据配置的限流阈值与模式, 对包含热点参数的资源调⽤进⾏限流. 热点参数限流可以看做是⼀种特殊的流量控制, 仅对包含热点参数的资源调⽤⽣效.

(1)定义资源

热点参数限流对默认的Spring MVC 资源⽆效,在资源上需要加 @SentinelResource

java 复制代码
@SentinelResource("/sentinel/id")
@RequestMapping("/{orderId}")
public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId){
    return orderService.selectOrderById(orderId);
}

(2)设置热点参数限流

对 /sentinel/id 这个资源的0号参数(第⼀个参数)做统计,每1秒相同参数值的请求数不能超过5

参数索引: 资源热点参数的索引, 从0开始.

(3)参数例外项

上述热点参数配置中, 所有的参数⼀视同仁, QPS都被限定为5, 但是在⼀些场景下, 我们希望可以对某些热点参数进⾏单独限流. 但是在⼀些场景下, 有⼀些热点商品, ⽐如排名⽐较靠前的, 访问次数⽐较多, 我们希望可以对这个热点 商品进⾏单独限流, 让他的阈值⾼⼀些或者低⼀些, 就需要使⽤到热点参数限流规则⾥⾯的⾼级选项了.

7.限流算法

7.1计数器算法

⾸先维护⼀个计数器, 在指定周期内, 累加访问次数, 当访问次数达到设定的阈值时, 触发限流策略, 当进⼊下⼀个时间周期时, 将访问次数清零. 这个时间周期, 就可以理解为⼀个窗⼝, 计数器记录这个窗⼝接收请求的次数

这种算法可以⽤在短信发送的频次限制上, ⽐如限制同⼀个⽤⼾⼀分钟之内触发短信发送的次数


这种算法存在⼀个临界问题, 如图所⽰, 在第⼀分钟的0:58和第⼆分钟的1:02这个时间段内, 分别发出了100个请求, 整体来看就会出现4秒内总的请求量达到200, 超出了设置的每分钟100的阈值

7.2滑动窗口算法

为了解决计数器算法带来的临界问题, 所以引⼊了滑动窗⼝算法. 滑动窗⼝是⼀种流量控制技术, 在TCP

⽹络通信协议中, 就采⽤了滑动窗⼝算法来解决⽹络拥塞的情况.

简单来说, 滑动窗⼝算法的原理是在固定窗⼝中分割出多个⼩时间窗⼝, 分别在每个⼩时间窗⼝中记录访问次数,然后根据时间将窗⼝往前滑动并删除过期的⼩时间窗⼝. 最终只需要统计滑动窗⼝范围内的所有小时间窗⼝总的计数即可.

Sentinel就是采⽤滑动窗⼝算法来实现限流的

7.3漏桶算法

漏桶算法⾯对限流, 就更加的柔和, 不存在直接的粗暴拒绝. 漏桶限流算法的主要作⽤是控制数据注⼊⽹络的速度, 平滑⽹络上的突发流量. 它的原理很简单, 可以认为就是注⽔漏⽔的过程, 往漏桶中以任意速率流⼊⽔, 以固定的速率流出⽔. 当⽔超过桶的容量时, 会被溢出, 也就是被丢弃. 因为桶容量是不变的, 保证了整体的速率.

缺点:

  • ⽆法处理突发流量: 漏桶算法以固定的速率处理请求, 当流量突然增加时, ⽆法快速响应和处理这些请求. 超出漏桶容量的请求会被丢弃, 这可能导致⽤⼾体验下降.
  • 可能导致请求延迟: 由于漏桶的流出速率是固定的, 即使在流量较⼩的情况下, 请求也需要排队等待处理, 这可能导致请求的响应时间变⻓.

7.4令牌桶算法

令牌桶是⽹络流量整形和速率限制中最常使⽤的⼀种算法. 对于每⼀个请求, 都需要从令牌桶中获得⼀个令牌, 如果没有获得令牌, 则触发限流策略.

系统会以⼀个恒定速度往固定容量的令牌桶中放⼊令牌, 如果此时有客⼾端请求过来, 则需要先从令牌桶中拿到令牌以获得访问资格

8.熔断降级

现代微服务架构都是分布式的, 由⾮常多的服务组成. 不同服务之间相互调⽤, 组成复杂的调⽤链路. 复杂链路上的某⼀环不稳定, 就可能会层层级联, 最终导致整个链路都不可⽤. 因此我们需要对不稳定的弱依赖服务调⽤进⾏熔断, 暂时切断不稳定调⽤, 避免局部不稳定因素导致整体的雪崩.

  • 慢调⽤⽐例 ( SLOW_REQUEST_RATIO ):需要设置允许的慢调⽤ RT(即最⼤的响应时间), 请求的响应时间⼤于该值则统计为慢调⽤. 在指定时间内, 如果请求数量 > 设定的最⼩数量, 且慢调⽤⽐例 > 设定的阈值, 则触发熔断
  • 异常⽐例 ( ERROR_RATIO ):指定时间内, 请求数量 > 设置的最⼩数量, 且异常⽐例⼤于阈值, 则触发熔断
  • 异常数 ( ERROR_COUNT ): 指定时间内, 异常数⽬超过阈值后, 则触发熔断.

8.1状态机

熔断的思路是由断路器 (或者叫熔断器) 统计服务调⽤的慢请求⽐例, 异常⽐例等, 如果超过阈值, 则熔断该服务, 也就是拦截对该服务的请求, 当服务恢复时, 断路器会放⾏访问该服务的请求.

  • Closed: 关闭状态, 所有请求都会通过断路器, 并开始统计慢请求⽐例, 异常⽐例, 超过阈值则切换到open状态.
  • Open: 打开状态,服务调⽤被熔断. 这时所有访问被熔断服务的请求都会被拒绝.
  • Half-open: 半开状态, 当经过⼀段时间后, 断路器会从Open状态切换到Half-open状态, 这时会有⼀ 定数量的请求被放⼊, 根据这些请求的失败率来判断后续操作.

失败率低于阈值:切换到closed状态 ,失败率超过阈值:切换到open状态

8.2慢调用比例

慢调⽤⽐例: 需要设置允许的慢调⽤RT, 也就是最⼤响应时间.

当统计时⻓内请求数⽬ > 设置的最⼩请求数⽬, 并且慢调⽤的⽐例⼤于阈值, 则接下来的熔断时长内请求会⾃动被熔断. 经过熔断时⻓后熔断器会进⼊探测恢复状态(HALF-OPEN 状态), 若接下来的⼀个请求响应时间小于设置的慢调⽤ RT 则结束熔断, 若大于设置的慢调⽤ RT 则会再次被熔断.

上述配置表示: 超过50ms的调⽤是慢调用, 统计最近10000内的请求, 如果请求量超过5次, 并且慢调⽤比例不低于0.5, 则触发熔断. 熔断时⻓为5s, 然后进⼊half-open状态, 放⾏⼀次请求做测试.

8.3降级

当调⽤失败后, 业务直接报错, 给⽤⼾体验不太好, 应该返回⽤⼾⼀个友好提⽰或者默认结果, 这个就是降级.

(1)捕获异常

对资源代码进⾏异常捕获, 当发⽣熔断时, 返回空对象

(2)FallBackFactory

FallbackFactory 是⼀个在微服务架构中⽤于实现服务降级的接⼝, 当远程服务调⽤失败或超时, FallbackFactory 会根据提供的异常信息创建⼀个降级处理实例, 以替代原服务调⽤. 并且可以根据错误类型, 返回不同的降级响应

定义降级逻辑:

java 复制代码
@Slf4j
public class ProductFallbackFactory implements FallbackFactory<ProductApi> {
@Override
public ProductApi create(Throwable cause) {
    return new ProductApi() {
        @Override
        public ProductInfo getProductInfo(Integer productId) {
        log.error("查询信息异常");
        return new ProductInfo();
        }
        @Override
        public String p1(Integer id) {
        
        return "发⽣错误";
        }
    };
}
}

product-api上配置fallbackFactory:

java 复制代码
@FeignClient(value = "product-service",path = "/product", fallbackFactory =ProductFallbackFactory.class)
public interface ProductApi {
}
java 复制代码
public class DefaultFeignConfiguration {
@Bean
public ProductFallbackFactory productFallbackFactory(){
        return new ProductFallbackFactory();
    }
}

在调⽤⽅order-service上设置配置⽂件:

java 复制代码
@EnableFeignClients(clients = {ProductApi.class}, defaultConfiguration =DefaultFeignConfiguration.class)
@SpringBootApplication
public class OrderServiceApplication {
    public static void main(String[] args) {
    SpringApplication.run(OrderServiceApplication.class, args);
    }
}

在order-service修改配置, 开启 feign 对 Sentinel 功能:

yaml 复制代码
feign:
  sentinel:
    enabled: true # 开启feign对sentinel的⽀持

配置熔断规则:

8.4异常数

异常数 ( ERROR_COUNT ):统计单位时⻓内的异常数⽬, 超过阈值之后, 触发熔断. 经过熔断时⻓后熔断器会进⼊探测恢复状态(HALF-OPEN 状态),若接下来的⼀个请求成功完成(没有错误)则结束熔断,否则会再次被熔断.

配置熔断规则:

9.授权规则

微服务架构中, 许多系统包含敏感信息, 如个⼈⾝份信息, 财务数据, 商业机密等. 只有经过验证或者授权的⽤⼾才可以访问这些数据. ⽐如在医疗系统中, 只有授权的医⽣和护⼠可以查看患者的病历. 授权规则是对请求者的⾝份进⾏判断, 决定是否允许该请求访问特定资源
Sentinel提供了两种授权模式:⽩名单和⿊名单

  • ⽩名单:请求来源位于⽩名单内的调⽤者才允许访问.
  • ⿊名单:请求来源位于⿊名单内的调⽤者不允许访问,其余请求通过.

9.1服务端(被调用方)获取来源

Sentinel是通过 RequestOriginParser 这个接⼝的 parseOrigin 来获取请求的来源的. 在服务端中实现RequestOriginParser这个接⼝即可,定义请求来源放在Header中, key为origin(⾃定义)

java 复制代码
@Component
public class HeaderOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        // 1.获取请求头
        String origin = httpServletRequest.getHeader("origin");
        // 2.⾮空判断
        if (!StringUtils.hasLength(origin)) {
            origin = "default";
        }
        return origin;
    }
}

9.2客户端(调用方)设置来源

也就是gateway项⽬,可以通过AddRequestHeader Filter设置Header

java 复制代码
spring:
    cloud:
        gateway:
            default-filters:
              - AddRequestHeader=origin,gateway

9.3配置授权规则

以下配置表⽰, 来源为gateway的放⾏通过

9.4验证授权规则

10.定义异常返回结果

Sentinel提供了⼀个接⼝ BlockExceptionHandler , ⽤于⾃定义处理 BlockException 异常. 当请求被 Sentinel 限流、降级或授权拒绝时, 会抛出 BlockException . 通过实现 BlockExceptionHandler 接⼝, 可以定义统⼀的异常处理逻辑, 返回更友好的错误信息或执⾏特定的降级操作.

(1)自定义处理

java 复制代码
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setContentType("text/html; charset=utf-8");
        String msg = "Blocked by Sentinel (flow limiting)";
        int status = 429;
        PrintWriter out = response.getWriter();
        //限流异常
        if (e instanceof FlowException) {
            msg = "触发限流, 请联系服务⽅进⾏调整";
        } else if (e instanceof DegradeException) { //降级异常
            msg = "触发降级异常";
        } else if (e instanceof AuthorityException) { //授权异常
            msg = "没有权限访问, 请联系服务⽅进⾏调整";
            status = 401;
        }
            response.setStatus(status);
            out.print(msg);
            out.flush();
            out.close();
}
}

(2)使用注解

除了全局的 BlockExceptionHandler ,还可以在⽅法上使⽤ @SentinelResource 注解来指定特定的异常处理⽅法. 上⾯异常的处理, 相对⽐较统⼀, 如果我们希望给⼀些资源进⾏特殊的定义, 就可以使⽤ @SentinelResource 的 blockHandler/blockHandlerClass 属性.

java 复制代码
    @SentinelResource(value = "/sentinel/id", blockHandler ="handleException")
    @RequestMapping("/{orderId}")
    public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId){
        return orderService.selectOrderById(orderId);
    }
    public OrderInfo handleException(Integer orderId, BlockException e) {
            System.out.println("进⼊异常处理⽅法");
        if (e instanceof FlowException) {
                return new OrderInfo();
            }
        return new OrderInfo();
}

11.规则管理及推送

⽣产环境中, Sentinel需要规则持久化, sentinel-core 提供 API 和扩展接⼝来接收信息. 开发者需要根据⾃⼰的环境, 选取⼀个可靠的推送规则⽅式. 同时, 规则最好在控制台中集中管理.

11.1原始模式

如果不做任何修改,Dashboard 的推送规则⽅式是通过 API 将规则推送⾄客⼾端并直接更新到内存中

这种做法的好处是简单,⽆依赖;坏处是应⽤重启规则就会消失,仅⽤于简单测试,不能⽤于⽣产环境

11.2Pull模式

pull 模式的数据源(如本地⽂件、RDBMS 等)⼀般是可写⼊的. 使⽤时需要在客⼾端注册数据源:将对应的读数据源注册⾄对应的 RuleManager,将写数据源注册⾄ transport 的WritableDataSourceRegistry 中

(1)注册数据源

java 复制代码
public class FileDataSourceInit implements InitFunc {
@Override
public void init() throws Exception {
    String ruleDir = System.getProperty("user.home") +"/sentinel/rules/orderService";
    String flowRulePath = ruleDir + "/flow-rule.json";
    mkdirIfNotExist(ruleDir);
    createFileIfNotExist(flowRulePath);
    // 注册⼀个可读数据源,⽤来定时读取本地的json⽂件,更新到规则缓存中
    // 流控规则
    ReadableDataSource<String, List<FlowRule>> ds = newFileRefreshableDataSource<>(flowRulePath, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
    // 将可读数据源注册⾄FlowRuleManager
    // 这样当规则⽂件发⽣变化时,就会更新规则到内存
    FlowRuleManager.register2Property(ds.getProperty());
    WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(flowRulePath,this::encodeJson);
    // 将可写数据源注册⾄transport模块的WritableDataSourceRegistry中
    // 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写⼊到⽂件中
    WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
}
    private <T> String encodeJson(T t) {
            return JSON.toJSONString(t);
    }
    private void mkdirIfNotExist(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
}
}
    private void createFileIfNotExist(String filePath) throws IOException {
            File file = new File(filePath);
                if (!file.exists()) {
                    file.createNewFile();
}
}
}

(2)在resources下创建META-INF/services⽬录,并创建⽂件com.alibaba.csp.sentinel.init.InitFunc, 写本地数据源的路径

java 复制代码
com.bite.order.sentinel.FileDataSourceInit

(3)重启服务, 设置流控, 会发现流控规则同步到指定的⽂件中.

(4)修改配置文件

java 复制代码
[
{
    // 资源名
    "resource": "/test",
    // 针对来源,若为 default 则不区分调⽤来源
    "limitApp": "default",
    // 限流阈值类型(1:QPS;0:并发线程数)
    "grade": 1,
    // 阈值
    "count": 1,
    // 是否是集群模式
    "clusterMode": false,
    // 流控效果(0:快速失败;1:Warm Up(预热模式);2:排队等待)
    "controlBehavior": 0,
    // 流控模式(0:直接;1:关联;2:链路)
    "strategy": 0,
    // 预热时间(秒,预热模式需要此参数)
    "warmUpPeriodSec": 10,
    // 超时时间(排队等待模式需要此参数)
    "maxQueueingTimeMs": 500,
    // 关联资源、⼊⼝资源(关联、链路模式)
    "refResource": "rrr"
}
]

11.3Push模式

⽣产环境下⼀般更常⽤的是 push 模式的数据源. 对于 push 模式的数据源,如远程配置中⼼(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客⼾端进⾏,⽽应该经控制台统⼀进⾏管理,直接进⾏推送,数据源仅负责获取配置中⼼推送的配置并更新到本地。因此推送规则正确做法应该是 配置中⼼控制台/Sentinel 控制台 → 配置中⼼ → Sentinel 数据源 → Sentinel,⽽不是 经Sentinel 数据源推送⾄配置中⼼。

(1)Nacos官方支持

添加依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

注册数据源

java 复制代码
public class NacosDataSourceInit implements InitFunc {
    // nacos server ip
    private static final String remoteAddress = "47.108.157.13:8848";
    // nacos group
    private static final String groupId = "SENTINEL_GROUP";
    // nacos dataId
    private static final String dataId = "orderservice-flow-rules";
    @Override
    public void init() throws Exception {
        ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new
        NacosDataSource<>(remoteAddress, groupId, dataId,
                          source -> JSON.parseObject(source, new
                                                     TypeReference<List<FlowRule>>() {
                                                     }));
        FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
    }
}

配置数据源路径

在resources下创建META-INF/services⽬录,并创建⽂件:com.alibaba.csp.sentinel.init.InitFunc, 写本地数据源的路径

java 复制代码
com.bite.order.sentinel.NacosDataSourceInit

配置Nacos

11.4Sentinel集成Nacos持久化

上述我们发现, Nacos修改的内容会及时同步到Sentinel DashBoard, 但是Sentinel DashBoard更新的内容, 并不会同步到Nacos, 这在⽣产环境中, 也是不⽅便使⽤的. 所以我们需要修改Sentinel的源码, 让其⽀持双向通讯

(1)源码改造

java 复制代码
https://github.com/alibaba/Sentinel/releases

(2)修改pom文件

在sentinel-dashboard源码的pom⽂件中, nacos的依赖默认的scope是test, 只能在测试时使⽤

注掉 test

xml 复制代码
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-datasource-nacos</artifactId>
  <scope>test</scope>
</dependency>

(3)添加Nacos支持

sentinel-dashboard 的 test 包下, 已经编写了对nacos的⽀持,接下来把com.alibaba.csp.sentinel.dashboard.rule.nacos ⽂件复制到src/main/java/com.alibaba.csp.sentinel.dashboard.rule ⽬录下

(4)修改Nacos Config

在 sentinel-dashboard 的 application.properties 中添加nacos地址配置: IP地址改为⾃⼰nacos的地址

(5)配置Nacos数据源

开启 Controller 层操作 Nacos 的开关,代码位于: com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2

(6)修改前端

修改 src/main/webapp/resources/app/scripts/controllers/identity.js ,修改 FlowServiceV1 -> FlowServiceV2

搜索"/dashboard/flow/", 修改 /dashboard/flow/ -> /dashboard/v2/flow/

修改 identity.js ⽂件主要是在 Sentinel Dashboard上点击资源的"流控"按钮, 添加规则后将信息同步给 Nacos

相关推荐
fanly116 小时前
Surging AI Agent 完整产品介绍
微服务·microservice
吃饱了得干活2 天前
Spring Cloud Gateway 微服务网关:路由、断言、过滤器
java·spring cloud
蝎子莱莱爱打怪7 天前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试
SamDeepThinking8 天前
Java微服务练习方式
java·后端·微服务
米丘11 天前
微前端之 Web Components 完全指南
微服务·html
霸道流氓气质13 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
慧一居士14 天前
Feign的GET请求如何传递对象参数?
java·spring cloud
我登哥MVP14 天前
SpringCloud Alibaba 核心组件解析:服务链路追踪
java·spring boot·后端·spring·spring cloud·java-ee·maven
慧一居士14 天前
SpringCloud 微服务Feigin 用的完整调用端和被调用的示例
java·spring cloud
霸道流氓气质14 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化