Skip to content

RequestRateLimiter GatewayFilter Factory

概述

RequestRateLimiter GatewayFilter Factory 是 Spring Cloud Gateway 提供的一个核心限流过滤器,用于控制通过网关的请求频率。当请求超过设定的限制时,过滤器会返回 HTTP 429 - Too Many Requests 状态码,有效保护下游服务免受流量冲击。

解决的业务问题

在微服务架构中,RequestRateLimiter 过滤器主要解决以下关键问题:

1. API 流量控制

  • 防止服务过载:限制单位时间内的请求数量,避免下游服务因流量过大而崩溃
  • 保障服务稳定性:通过合理的限流策略确保系统在高并发场景下的稳定运行
  • 资源合理分配:根据用户等级、API 重要性等维度进行差异化限流

2. 安全防护

  • 防止 DDoS 攻击:有效抵御恶意用户的大量请求攻击
  • 防止接口滥用:避免用户无节制地调用昂贵的 API 接口
  • 保护付费服务:确保付费用户享受到应有的服务质量

3. 商业价值保护

  • SaaS 服务分级:根据用户订阅等级提供不同的请求配额
  • API 货币化:为不同价格的 API 套餐设置相应的调用限制
  • 公平使用原则:确保所有用户都能公平地使用系统资源

工作原理

核心组件

1. KeyResolver 接口

KeyResolver 用于确定限流的维度,决定如何识别和区分不同的请求来源。

kotlin
// KeyResolver 接口定义
interface KeyResolver {
    fun resolve(exchange: ServerWebExchange): Mono<String>
}

2. 内置 KeyResolver 实现

kotlin
@Configuration
class KeyResolverConfig {

    /**
     * 基于用户ID的限流策略
     * 适用场景: 用户级别的API限流
     */
    @Bean
    fun userKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            // 从查询参数中获取用户ID
            val userId = exchange.request.queryParams.getFirst("userId")
            Mono.justOrEmpty(userId)
        }
    }

    /**
     * 基于IP地址的限流策略
     * 适用场景: 防止恶意IP攻击
     */
    @Bean
    fun ipKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            // 获取真实客户端IP
            val remoteAddress = exchange.request.remoteAddress?.address?.hostAddress
            Mono.justOrEmpty(remoteAddress)
        }
    }

    /**
     * 基于API路径的限流策略
     * 适用场景: 不同API接口的差异化限流
     */
    @Bean
    fun pathKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            // 基于请求路径进行限流
            val path = exchange.request.path.value()
            Mono.just(path)
        }
    }

    /**
     * 基于认证用户的限流策略
     * 适用场景: 需要用户认证的API
     */
    @Bean
    fun principalKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            // 从认证信息中获取用户名
            exchange.getPrincipal<Principal>()
                .cast(Principal::class.java)
                .map { it.name }
                .switchIfEmpty(Mono.empty())
        }
    }

    /**
     * 复合限流策略
     * 适用场景: 需要多维度限流控制
     */
    @Bean
    fun compositeKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            val request = exchange.request

            // 优先使用用户ID,其次使用IP
            val userId = request.headers.getFirst("X-User-Id")
            val clientIp = request.remoteAddress?.address?.hostAddress

            when {
                !userId.isNullOrEmpty() -> Mono.just("user:$userId")
                !clientIp.isNullOrEmpty() -> Mono.just("ip:$clientIp")
                else -> Mono.just("anonymous")
            }
        }
    }
}

Redis RateLimiter

Redis 实现基于令牌桶算法,是最常用的限流方案。

核心参数

参数说明默认值示例值
replenishRate每秒令牌补充速率10
burstCapacity令牌桶最大容量20
requestedTokens每个请求消耗的令牌数11

IMPORTANT

令牌桶算法原理:

  • replenishRate: 控制稳定的请求速率
  • burstCapacity: 允许短时间的突发流量
  • requestedTokens: 不同接口可以设置不同的"价格"

配置示例

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user_api_route
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10 # 每秒补充10个令牌
                redis-rate-limiter.burstCapacity: 20 # 令牌桶最大容量20
                redis-rate-limiter.requestedTokens: 1 # 每个请求消耗1个令牌
                key-resolver: "#{@userKeyResolver}" # 使用用户级别限流
kotlin
@Configuration
class RateLimiterGatewayConfig {

    @Bean
    fun rateLimiterRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("user_api_with_rate_limit") { r ->
                r.path("/api/users/**")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            // Redis 限流器配置
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = userKeyResolver()

                            // 设置限流参数
                            config.setReplenishRate(10)        // 每秒补充10个令牌
                            config.setBurstCapacity(20)        // 最大容量20个令牌
                            config.setRequestedTokens(1)       // 每请求消耗1个令牌
                        }
                    }
                    .uri("lb://user-service")
            }
            .build()
    }

    @Bean
    @Primary
    fun redisRateLimiter(
        redisTemplate: ReactiveStringRedisTemplate,
        applicationEventPublisher: ApplicationEventPublisher
    ): RedisRateLimiter {
        return RedisRateLimiter(redisTemplate, "request_rate_limiter", applicationEventPublisher)
    }
}

高级配置场景

yaml
spring:
  cloud:
    gateway:
      routes:
        # 免费用户 - 严格限流
        - id: free_user_api
          uri: lb://user-service
          predicates:
            - Path=/api/free/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 5 # 每秒5个请求
                redis-rate-limiter.burstCapacity: 10 # 最大突发10个
                key-resolver: "#{@userKeyResolver}"

        # VIP用户 - 宽松限流
        - id: vip_user_api
          uri: lb://user-service
          predicates:
            - Path=/api/vip/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100 # 每秒100个请求
                redis-rate-limiter.burstCapacity: 200 # 最大突发200个
                key-resolver: "#{@userKeyResolver}"

        # 文件上传 - 高成本操作
        - id: file_upload_api
          uri: lb://file-service
          predicates:
            - Path=/api/upload/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 2 # 每秒2个请求
                redis-rate-limiter.burstCapacity: 5 # 最大突发5个
                redis-rate-limiter.requestedTokens: 5 # 每个请求消耗5个令牌
                key-resolver: "#{@userKeyResolver}"
kotlin
@Configuration
class AdvancedRateLimiterConfig {

    /**
     * 多维度限流配置
     */
    @Bean
    fun multiDimensionRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            // API级别的基础限流
            .route("api_global_limit") { r ->
                r.path("/api/**")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = ipKeyResolver()    // IP级别限流
                            config.setReplenishRate(1000)          // 全局每秒1000个请求
                            config.setBurstCapacity(2000)
                        }
                    }
                    .uri("lb://api-service")
            }
            // 用户级别的精细限流
            .route("user_specific_limit") { r ->
                r.path("/api/users/**")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = userTierKeyResolver() // 用户等级限流
                            config.setReplenishRate(50)
                            config.setBurstCapacity(100)
                        }
                    }
                    .uri("lb://user-service")
            }
            .build()
    }

    /**
     * 基于用户等级的限流策略
     */
    @Bean
    fun userTierKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            val request = exchange.request
            val userId = request.headers.getFirst("X-User-Id")
            val userTier = request.headers.getFirst("X-User-Tier") ?: "free"

            when {
                !userId.isNullOrEmpty() -> Mono.just("user:$userTier:$userId")
                else -> {
                    val clientIp = request.remoteAddress?.address?.hostAddress
                    Mono.justOrEmpty(clientIp?.let { "ip:$it" })
                }
            }
        }
    }
}

Bucket4j RateLimiter

Bucket4j 是一个基于令牌桶算法的 Java 限流库,提供了更灵活的配置选项。

依赖配置

kotlin
// build.gradle.kts
dependencies {
    implementation("com.github.ben-manes.caffeine:caffeine")
    implementation("com.bucket4j:bucket4j_jdk17-core")
    implementation("com.bucket4j:bucket4j_jdk17-caffeine")
}

核心配置

kotlin
@Configuration
class Bucket4jRateLimiterConfig {

    /**
     * Caffeine 本地缓存代理管理器
     * 适用于单实例部署或测试环境
     */
    @Bean
    fun caffeineProxyManager(): AsyncProxyManager<String> {
        val builder = Caffeine.newBuilder()
            .maximumSize(100_000)                    // 最大缓存100,000个桶
            .expireAfterWrite(Duration.ofMinutes(10)) // 10分钟后过期

        return CaffeineProxyManager(builder, Duration.ofMinutes(1)).asAsync()
    }

    /**
     * Redis 分布式代理管理器
     * 适用于集群部署环境
     */
    @Bean
    fun redisProxyManager(
        @Qualifier("reactiveRedisTemplate") redisTemplate: ReactiveRedisTemplate<String, ByteArray>
    ): AsyncProxyManager<String> {
        return RedisProxyManager.builderFor(redisTemplate)
            .withKeyPrefix("rate_limit:")
            .build()
            .asAsync()
    }

    @Bean
    fun bucket4jRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("bucket4j_api_limit") { r ->
                r.path("/api/bucket4j/**")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = bucket4jRateLimiter()
                            config.keyResolver = userKeyResolver()
                        }
                    }
                    .uri("lb://api-service")
            }
            .build()
    }

    @Bean
    fun bucket4jRateLimiter(): RateLimiter<Any> {
        return Bucket4jRateLimiter()
    }
}
yaml
spring:
  cloud:
    gateway:
      routes:
        - id: bucket4j_rate_limited_route
          uri: https://example.org
          filters:
            - name: RequestRateLimiter
              args:
                bucket4j-rate-limiter.capacity: 20 # 桶容量
                bucket4j-rate-limiter.refillTokens: 10 # 补充令牌数
                bucket4j-rate-limiter.refillPeriod: 1s # 补充周期
                bucket4j-rate-limiter.requestedTokens: 1 # 每请求消耗令牌
                bucket4j-rate-limiter.refillStyle: GREEDY # 补充策略
                key-resolver: "#{@userKeyResolver}"

补充策略对比

策略说明适用场景
GREEDY尽快补充令牌一般 API 限流
INTERVALLY等待完整周期后补充严格的时间窗口限流
INTERVALLY_ALIGNED按指定时间对齐补充需要精确时间对齐的场景

实际业务场景示例

场景 1: 电商平台 API 网关

kotlin
@Configuration
class ECommerceRateLimiterConfig {

    @Bean
    fun ecommerceRateLimitRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            // 商品浏览 - 高频低成本
            .route("product_browse") { r ->
                r.path("/api/products/**")
                    .and().method(HttpMethod.GET)
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = userKeyResolver()
                            config.setReplenishRate(100)    // 每秒100个请求
                            config.setBurstCapacity(200)    // 允许突发200个
                        }
                    }
                    .uri("lb://product-service")
            }
            // 订单创建 - 重要业务操作
            .route("order_creation") { r ->
                r.path("/api/orders/**")
                    .and().method(HttpMethod.POST)
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = userKeyResolver()
                            config.setReplenishRate(10)     // 每秒10个订单
                            config.setBurstCapacity(20)     // 允许突发20个
                            config.setRequestedTokens(2)    // 每个订单消耗2个令牌
                        }
                    }
                    .uri("lb://order-service")
            }
            // 支付接口 - 高成本操作
            .route("payment_processing") { r ->
                r.path("/api/payments/**")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = userKeyResolver()
                            config.setReplenishRate(5)      // 每秒5个支付
                            config.setBurstCapacity(10)     // 允许突发10个
                            config.setRequestedTokens(5)    // 每个支付消耗5个令牌
                        }
                    }
                    .uri("lb://payment-service")
            }
            .build()
    }
}

场景 2: SaaS 平台分级限流

kotlin
@Configuration
class SaaSRateLimiterConfig {

    @Bean
    fun saasRateLimitRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            // 免费版用户
            .route("free_tier_api") { r ->
                r.path("/api/**")
                    .and().header("X-User-Tier", "free")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = userTierKeyResolver()
                            config.setReplenishRate(10)     // 每秒10个请求
                            config.setBurstCapacity(15)     // 最大突发15个
                        }
                    }
                    .uri("lb://api-service")
            }
            // 专业版用户
            .route("pro_tier_api") { r ->
                r.path("/api/**")
                    .and().header("X-User-Tier", "pro")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = userTierKeyResolver()
                            config.setReplenishRate(100)    // 每秒100个请求
                            config.setBurstCapacity(200)    // 最大突发200个
                        }
                    }
                    .uri("lb://api-service")
            }
            // 企业版用户
            .route("enterprise_tier_api") { r ->
                r.path("/api/**")
                    .and().header("X-User-Tier", "enterprise")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = userTierKeyResolver()
                            config.setReplenishRate(1000)   // 每秒1000个请求
                            config.setBurstCapacity(2000)   // 最大突发2000个
                        }
                    }
                    .uri("lb://api-service")
            }
            .build()
    }

    @Bean
    fun userTierKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            val userId = exchange.request.headers.getFirst("X-User-Id")
            val userTier = exchange.request.headers.getFirst("X-User-Tier") ?: "free"
            Mono.justOrEmpty(userId?.let { "tier:$userTier:user:$it" })
        }
    }
}

场景 3: 时间段差异化限流

kotlin
@Configuration
class TimeBasedRateLimiterConfig {

    @Bean
    fun timeBasedKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            val userId = exchange.request.headers.getFirst("X-User-Id")
            val hour = LocalTime.now().hour

            // 根据时间段调整限流策略
            val timeSlot = when (hour) {
                in 9..11, in 14..16 -> "peak"      // 高峰期
                in 12..13 -> "lunch"               // 午休期
                else -> "normal"                   // 正常期
            }

            Mono.justOrEmpty(userId?.let { "time:$timeSlot:user:$it" })
        }
    }

    @Bean
    fun timeBasedRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("time_based_api") { r ->
                r.path("/api/**")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            config.rateLimiter = timeBasedRateLimiter()
                            config.keyResolver = timeBasedKeyResolver()
                        }
                    }
                    .uri("lb://api-service")
            }
            .build()
    }

    @Bean
    fun timeBasedRateLimiter(): RateLimiter<Any> {
        return object : RateLimiter<Any> {
            private val redisRateLimiter = RedisRateLimiter(
                reactiveRedisTemplate(),
                "time_based_limiter",
                applicationEventPublisher()
            )

            override fun isAllowed(
                routeId: String,
                id: String
            ): Mono<Response> {
                val hour = LocalTime.now().hour

                // 根据时间段动态调整限流参数
                val (replenishRate, burstCapacity) = when (hour) {
                    in 9..11, in 14..16 -> Pair(50, 100)   // 高峰期收紧
                    in 12..13 -> Pair(200, 400)            // 午休期放宽
                    else -> Pair(100, 200)                 // 正常期标准
                }

                redisRateLimiter.config[routeId] = RedisRateLimiter.Config()
                    .setReplenishRate(replenishRate)
                    .setBurstCapacity(burstCapacity)

                return redisRateLimiter.isAllowed(routeId, id)
            }
        }
    }
}

自定义 RateLimiter

kotlin
@Component
class CustomRateLimiter : RateLimiter<String> {

    private val logger = LoggerFactory.getLogger(CustomRateLimiter::class.java)
    private val redisTemplate: ReactiveStringRedisTemplate = TODO("注入Redis模板")

    override fun isAllowed(routeId: String, id: String): Mono<Response> {
        return checkRateLimit(routeId, id)
            .doOnNext { response ->
                // 记录限流日志
                if (!response.isAllowed) {
                    logger.warn("Rate limit exceeded for route: $routeId, id: $id")
                }
            }
            .doOnError { error ->
                logger.error("Rate limit check failed for route: $routeId, id: $id", error)
            }
    }

    private fun checkRateLimit(routeId: String, id: String): Mono<Response> {
        val key = "rate_limit:$routeId:$id"
        val windowSize = Duration.ofMinutes(1)
        val maxRequests = getMaxRequestsForRoute(routeId)

        return redisTemplate.opsForZSet()
            .removeRangeByScore(key, 0.0, (System.currentTimeMillis() - windowSize.toMillis()).toDouble())
            .then(redisTemplate.opsForZSet().count(key, 0.0, Double.MAX_VALUE))
            .flatMap { currentCount ->
                if (currentCount < maxRequests) {
                    // 允许请求,记录当前时间戳
                    val score = System.currentTimeMillis().toDouble()
                    redisTemplate.opsForZSet().add(key, score.toString(), score)
                        .then(redisTemplate.expire(key, windowSize))
                        .then(Mono.just(Response(true, mapOf(
                            "X-RateLimit-Remaining" to (maxRequests - currentCount - 1).toString(),
                            "X-RateLimit-Limit" to maxRequests.toString()
                        ))))
                } else {
                    // 拒绝请求
                    Mono.just(Response(false, mapOf(
                        "X-RateLimit-Remaining" to "0",
                        "X-RateLimit-Limit" to maxRequests.toString(),
                        "X-RateLimit-Retry-After" to windowSize.seconds.toString()
                    )))
                }
            }
    }

    private fun getMaxRequestsForRoute(routeId: String): Long {
        // 根据路由ID返回不同的限制
        return when (routeId) {
            "high_priority_route" -> 1000
            "normal_route" -> 100
            "low_priority_route" -> 10
            else -> 50
        }
    }
}

错误处理与监控

自定义错误响应

kotlin
@Component
class RateLimitExceptionHandler : ResponseEntityExceptionHandler() {

    @ExceptionHandler(RateLimitExceededException::class)
    fun handleRateLimit(ex: RateLimitExceededException): ResponseEntity<Map<String, Any>> {
        val response = mapOf(
            "timestamp" to Instant.now().toString(),
            "status" to 429,
            "error" to "Too Many Requests",
            "message" to "请求频率超过限制,请稍后重试",
            "code" to "RATE_LIMIT_EXCEEDED",
            "retryAfter" to ex.retryAfter,
            "limit" to ex.limit,
            "remaining" to 0
        )

        val headers = HttpHeaders().apply {
            set("X-RateLimit-Limit", ex.limit.toString())
            set("X-RateLimit-Remaining", "0")
            set("X-RateLimit-Retry-After", ex.retryAfter.toString())
        }

        return ResponseEntity.status(429).headers(headers).body(response)
    }
}

限流监控指标

kotlin
@Component
class RateLimitMetrics {

    private val meterRegistry = Metrics.globalRegistry

    private val rateLimitCounter = Counter.builder("gateway.rate.limit.requests")
        .description("Rate limited requests count")
        .register(meterRegistry)

    private val rateLimitGauge = Gauge.builder("gateway.rate.limit.current")
        .description("Current rate limit usage")
        .register(meterRegistry, this) { getCurrentUsage() }

    @EventListener
    fun handleRateLimitEvent(event: RateLimitEvent) {
        // 记录限流事件
        rateLimitCounter.increment(
            Tags.of(
                Tag.of("route", event.routeId),
                Tag.of("key", event.key),
                Tag.of("allowed", event.isAllowed.toString())
            )
        )

        // 记录详细日志
        if (!event.isAllowed) {
            MDC.put("routeId", event.routeId)
            MDC.put("key", event.key)
            MDC.put("limit", event.limit.toString())

            log.warn("Rate limit exceeded: route={}, key={}, limit={}",
                event.routeId, event.key, event.limit)

            MDC.clear()
        }
    }

    private fun getCurrentUsage(): Double {
        // 返回当前限流使用率
        return 0.0 // 实际实现中应该从Redis获取
    }

    companion object {
        private val log = LoggerFactory.getLogger(RateLimitMetrics::class.java)
    }
}

配置最佳实践

1. 合理设置限流参数

TIP

参数设置建议:

  • replenishRate: 基于 99%用户的正常使用频率
  • burstCapacity: 通常设置为 replenishRate 的 1.5-2 倍
  • requestedTokens: 根据接口成本调整,昂贵操作设置更高值

2. KeyResolver 选择策略

kotlin
@Configuration
class KeyResolverStrategy {

    /**
     * 生产环境推荐的复合策略
     */
    @Bean
    @Primary
    fun productionKeyResolver(): KeyResolver {
        return KeyResolver { exchange ->
            val request = exchange.request

            // 1. 优先使用认证用户ID
            exchange.getPrincipal<JwtAuthenticationToken>()
                .cast(JwtAuthenticationToken::class.java)
                .map { "user:${it.token.subject}" }
                .switchIfEmpty(
                    // 2. 其次使用API Key
                    Mono.justOrEmpty(request.headers.getFirst("X-API-Key"))
                        .map { "api:$it" }
                )
                .switchIfEmpty(
                    // 3. 最后使用IP地址
                    Mono.justOrEmpty(request.remoteAddress?.address?.hostAddress)
                        .map { "ip:$it" }
                )
                .switchIfEmpty(Mono.just("anonymous"))
        }
    }
}

3. 监控告警配置

yaml
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: metrics,health,info
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: gateway
      service: rate-limiter
# 告警规则示例 (Prometheus)
# rate_limit_exceeded_rate > 0.1 表示超过10%的请求被限流

4. 性能优化

WARNING

性能注意事项:

  • Redis 连接池要配置充足
  • 避免在 KeyResolver 中进行复杂计算
  • 考虑使用本地缓存减少 Redis 访问
  • 定期清理过期的限流数据

故障排查

常见问题与解决方案

Details

点击查看故障排查指南

问题 1: 所有请求都被限流

可能原因:

  • KeyResolver 返回空值或相同值
  • 限流参数设置过于严格
  • Redis 连接问题

排查步骤:

bash
# 1. 检查Redis连接
redis-cli ping

# 2. 查看限流数据
redis-cli keys "request_rate_limiter*"

# 3. 检查具体限流状态
redis-cli eval "return redis.call('hmget', KEYS[1], 'tokens', 'last_refill')" 1 request_rate_limiter.{user_123}.timestamp

问题 2: 限流不生效

可能原因:

  • 过滤器配置错误
  • KeyResolver 配置问题
  • 限流参数过大

解决方案:

kotlin
// 添加调试日志
@Bean
fun debugKeyResolver(): KeyResolver {
    return KeyResolver { exchange ->
        userKeyResolver().resolve(exchange)
            .doOnNext { key ->
                log.debug("Rate limit key resolved: $key")
            }
            .doOnEmpty {
                log.warn("Rate limit key is empty")
            }
    }
}

问题 3: 性能问题

优化方案:

kotlin
// 使用本地缓存优化
@Bean
fun cachedKeyResolver(): KeyResolver {
    val cache = Caffeine.newBuilder()
        .maximumSize(10000)
        .expireAfterWrite(Duration.ofMinutes(5))
        .build<String, String>()

    return KeyResolver { exchange ->
        val requestInfo = "${exchange.request.method}-${exchange.request.path}"
        val cachedKey = cache.getIfPresent(requestInfo)

        if (cachedKey != null) {
            Mono.just(cachedKey)
        } else {
            userKeyResolver().resolve(exchange)
                .doOnNext { key -> cache.put(requestInfo, key) }
        }
    }
}

总结

RequestRateLimiter 是 Spring Cloud Gateway 中非常重要的限流组件,通过合理的配置和使用,可以有效保护后端服务,提升系统的稳定性和可用性。

NOTE

关键要点:

  • 选择合适的 KeyResolver 策略是限流成功的关键
  • Redis RateLimiter 适合大多数生产环境
  • Bucket4j 提供更灵活的配置选项
  • 自定义 RateLimiter 可以实现复杂的业务逻辑
  • 完善的监控和告警机制不可或缺

在实际项目中,建议根据业务需求选择合适的限流策略,并结合监控数据持续优化限流参数,确保在保护系统的同时不影响正常用户的使用体验。