Spring Gateway 使用 Resilience4j 实现限流

朱治龙
2025-04-18 / 0 评论 / 0 阅读 / 正在检测是否收录...

背景说明

近期接触到公司一个使用 SpringGate Way 搭建的网关服务,为了保障下游服务,防止用户恶意刷接口造成系统过载崩溃等情况,需要在网关层面引入限流机制。

经过初步调研,不少大佬都推荐使用 Resilience4j 这款轻量级的 Java 容错库来做,但是网上能找到的实践层面的资料比较少,针对特定场景官网的文档也显得捉襟见肘,所以在边学习边实践过程种便有了这篇流水账式的文章。

初体验

1.添加依赖

公司项目使用 Maven 进行依赖管理,在工程的 pom.xml 的 dependencies 节点中添加如下依赖项:

        <dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-spring-cloud2</artifactId>
            <version>2.3.0</version>
        </dependency>

2.创建限流器工厂类

package com.paratera.aicloud.gateway.filter;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class Resilience4jRateLimiterGatewayFilterFactory extends
        AbstractGatewayFilterFactory<Resilience4jRateLimiterGatewayFilterFactory.Config> {

    private final RateLimiterRegistry rateLimiterRegistry;

    public Resilience4jRateLimiterGatewayFilterFactory(RateLimiterRegistry rateLimiterRegistry) {
        super(Config.class);
        this.rateLimiterRegistry = rateLimiterRegistry;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            RateLimiter rateLimiter = rateLimiterRegistry.rateLimiter(config.getName());

            return Mono.fromCallable(() -> {
                        boolean permitted = rateLimiter.acquirePermission();
                        if (!permitted) {
                            throw new RuntimeException("Rate limit exceeded");
                        }
                        return permitted;
                    }).then(chain.filter(exchange))
                    .onErrorResume(RuntimeException.class, e -> {
                        exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                        return exchange.getResponse().setComplete();
                    });
        };
    }

    public static class Config {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

3.添加限流相关配置

resilience4j:
  ratelimiter:
    instances:
      default:
        limitForPeriod: 50          # 每个周期允许的请求数
        limitRefreshPeriod: 5s      # 限流周期
        timeoutDuration: 5s      # 等待令牌的超时时间
        drainPermissionsOnResult: false # 周期结束后是否清空许可次数
        writableStackTraceEnabled: true # 是否生成堆栈跟踪, 可用于减少日志冗余
      limit50:
        limitForPeriod: 50
        limitRefreshPeriod: 300s
        timeoutDuration: 500ms
        writableStackTraceEnabled: false

4. 路由信息中关联限流配置

在 spring.cloud.gateway.routes 对应的实例节点中添加过滤器,示例如下:

spring:
  cloud:
    gateway:
      routes:
        - id: test-RateLimiter
          uri: http://localhost:8896
          predicates:
            - Path=/message/**
          filters:
            - StripPrefix=1
            - name: Resilience4jRateLimiter
              args:
                name: limit50

本示例核心配置信息如下:
限流相关配置信息

5. 验证

Apifox 自带的自动化测试功能可以很方面的进行并发测试,我们的测试配置如下:
限流测试配置
点击 运行 按钮后,得到如下图所示的测试结果,从结果来看式符合限流预期的:
限流测试结果
查看请求详情,可以看到请求周期内达到限流场景时,接口是响应的预期内的429状态码:

接口响应429状态码

Links

0

评论 (0)

取消