Spring Cloud中怎么使用Resilience4j RateLimiter对接口进行限流

在微服务架构中,限流是保护系统稳定性的重要手段之一。限流可以防止某个服务因流量过大而过载,影响整个系统的稳定性和性能。Resilience4j 提供了多种限流策略,其中 RateLimiter 是一种常用的限流机制。本文将详细介绍如何在 Spring Cloud 项目中使用 Resilience4j RateLimiter 对接口进行限流。

 1.Resilience4j 简介

Resilience4j 是一个轻量级的容错库,支持函数式编程设计。它提供了多种容错机制,包括熔断器(Circuit Breaker)、限流器(Rate Limiter)、重试(Retry)、舱壁(Bulkhead)等。相比于 Hystrix,Resilience4j 更加轻量级,并且在上篇文章中提到随着Hystrix停止维护,Resilence4j成了spring cloud官方主推的容错库。上篇文章我们介绍了熔断器,今天我们继续介绍它提供的限流器组件RateLimiter。

2. 原理解析

Resilience4j 的 RateLimiter 实现了基于时间窗口的限流策略。它主要采用令牌桶(Token Bucket)算法来控制请求速率。

令牌桶算法是一种常见的限流算法。它通过在固定的时间间隔生成令牌并将其存储在桶中,当请求到达时,从桶中获取令牌,如果桶中有足够的令牌,则请求通过,否则请求被限流。

下面是官网中关于RateLimiter的工作流程介绍,我们通过这张图来详细的了解一下,它的工作原理。

  •  纳秒时间轴:图中的横轴为系统时间单位是纳秒,表示从JVM启动到当前时间段。
  • cycle:上图中的cycle表示一个时间窗口周期。在每个时间窗口结束后,RateLimiter会刷新令牌桶。
  • permissions:图中的 permissions 表示当前时间窗口周期内可用的令牌数。在每个时间窗口周期开始时,令牌数被重置为配置的最大值(例如每秒 10 个令牌)。
  • 令牌生成:系统以固定速率生成令牌,并将令牌放入桶中。例如,每秒生成 10 个令牌。在每个时间窗口周期开始时,令牌数被重置为最大值。
  • 令牌获取:当一个请求到达时,需要从桶中获取一个令牌。如果桶中有足够的令牌,则请求通过(acquire),并从桶中扣减一个令牌。如果桶中没有令牌,则请求被限流或等待。
  • 令牌刷新:在每个时间窗口周期结束时,RateLimiter 会刷新令牌桶,重置可用的令牌数。

上面图中的两个线程Thread1发起请求,并成功获取令牌(acquire),然后持续运行。Thread2尝试获取令牌(reserve),但是令牌桶中没有足够的令牌,导致线程进入等待状态(park)。当新的时间窗口开始,刷新令牌桶后,Thread2成功获取到令牌并继续运行。

3. Spring Cloud项目中集成

3.1 在pom文件中添加相关的依赖
<!--resilience4j-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- 由于resilience4j需要AOP的包,所以必须导入AOP包 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
3.2 在application.yml中添加RateLimiter相关的配置
####resilience4j ratelimiter 限流的例子
# 以下配置将RateLimiter设置为每60秒允许5次请求,并且当请求超过限流时,不会有任何等待时间,直接返回失败。
resilience4j.ratelimiter:
  configs:
    default:
      registerHealthIndicator: false #是否注册为健康检查
      limitForPeriod: 5 #在一次刷新周期内,允许执行的最大请求数为5
      limitRefreshPeriod: 60s # 限流器每隔limitRefreshPeriod也就是60s刷新一次,将允许处理的最大请求数量重置为limitForPeriod本案例中为5
      timeoutDuration: 0 # 线程等待权限的默认等待时间,0就是不等待
      eventConsumerBufferSize: 100 # 配置了事件缓冲区的大小为100,用于记录和监控RateLimiter的行为
3.3 在需要限流的接口中通过注解开启限流

需要限流的接口通常是服务的下游,我们写一个简单的例子。

@RestController
public class PayController {

    private static final Logger log = LoggerFactory.getLogger(PayController.class);

    @GetMapping("/pay/{id}")
    @RateLimiter(name = "pay-service",fallbackMethod = "payServiceFallback")
    public String pay(@PathVariable("id") Integer id){
        log.info("Pay For Order id: {}", id);
        if (id == 1) { // 模拟服务异常
            throw new RuntimeException("Pay Service Exception");
        }
        return "Pay Success";
    }
    // 限流后的降级处理方法
    public String payServiceFallback(Integer id,Throwable t)
    {
        log.info("Pay Service invoke failed for order ID: {}", id);
        log.error("Error: {}", t.getMessage());
        return "Pay service is currently overloaded. Please try again later!";
    }
}

上游我们再模拟一个服务,通过OpenFeign调用。

@RestController
public class OrderController {

    private static final Logger log = LoggerFactory.getLogger(OrderController.class);

    @Autowired
    private PayService payService;
    @GetMapping("/order/{id}")
    @CircuitBreaker(name = "paymentService", fallbackMethod = "fallback")//配置熔断器
    public String order(@PathVariable("id") Integer id){
        log.info("Order id: {}", id);
        log.info("Request Pay For Order id: {}", id);
        //通过open feign远程调用支付服务
        return payService.payOrder(id);
    }

    //fallback就是服务降级后的兜底处理方法
    public String fallback(Integer id,Throwable t) {
        log.info("Pay Service invoke failed for order ID: {}", id);
        log.error("Error: {}", t.getMessage());
        return "Pay Service Was Busy Now. Please try again later!";
    }
}

4. 运行和测试

将这两个服务启动起来,进行测试。

在60s内访问支付接口5次后开始限流

在浏览器中访问:http://localhost:8082/order/5

从日志中可以看出,在连续访问这个接口5次后,限流功能开启,这个接口不允许继续访问,并走到了降级的方法。等到下一个时间窗口时,会自动刷新令牌数量。

5. 总结

通过本文的示例,我们学习了如何在 Spring Cloud 项目中使用 Resilience4j RateLimiter 对接口进行限流。Resilience4j 的 RateLimiter 提供了一种简单而有效的方式来保护服务免受过载影响提高系统的稳定性和可靠性。结合 Feign Client 和熔断器,可以构建出高可用的微服务架构。

相关推荐

  1. Resilience4j 实现接口

    2024-07-20 18:38:03       26 阅读
  2. SpringBoot整合resilience4j实现接口

    2024-07-20 18:38:03       62 阅读
  3. 【PHP】使用RedisAPI进行

    2024-07-20 18:38:03       51 阅读
  4. springcloud4使用resilience4j实现服务流量治理

    2024-07-20 18:38:03       33 阅读
  5. SpringCloud + Redis 实现Api接口 防止恶意刷接口

    2024-07-20 18:38:03       53 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-20 18:38:03       123 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-20 18:38:03       131 阅读
  3. 在Django里面运行非项目文件

    2024-07-20 18:38:03       109 阅读
  4. Python语言-面向对象

    2024-07-20 18:38:03       117 阅读

热门阅读

  1. 代码随想录训练营【贪心算法篇】

    2024-07-20 18:38:03       27 阅读
  2. 脱机输入/输出就是允许CPU和IO设备并行

    2024-07-20 18:38:03       26 阅读
  3. Python语言的优势所在

    2024-07-20 18:38:03       22 阅读
  4. Xubuntu22.04 终端命令调用图形设置工具

    2024-07-20 18:38:03       22 阅读
  5. 远程连接VScode到云服务器 ECS

    2024-07-20 18:38:03       22 阅读
  6. SQL Server邮件通知:数据库通信的自动化利器

    2024-07-20 18:38:03       23 阅读
  7. Elasticsearch 统计订单销售高峰时间段

    2024-07-20 18:38:03       27 阅读
  8. Vue 自定义组件编写 案例实战

    2024-07-20 18:38:03       22 阅读
  9. 音视频环境搭建

    2024-07-20 18:38:03       25 阅读
  10. 编织文字的魔法:探索WebKit的CSS文本效果

    2024-07-20 18:38:03       31 阅读
  11. c++判断路径是否存在,判断文件夹是否存在

    2024-07-20 18:38:03       24 阅读