你心头一紧,强撑着睡意打开电脑,发现罪魁祸首竟是一个刚刚上线的推广活动,带来的突发流量像洪水一样冲垮了你的服务……

这样的场景,是否让你感到后怕?事实上,缺乏有效的流量控制,再健壮的系统在突如其来的流量洪峰面前,也如同不设防的城池,一击即溃。

今天,我们就来聊聊如何为你的 Spring Boot 应用构筑一道坚固的防线——接口限流。


方式一:使用 Google Guava 的 RateLimiter (单机令牌桶)

适用场景:单服务实例限流,实现简单,平滑突发流量。

1. 添加依赖


 

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 创建自定义限流注解


 

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public@interface RateLimit {
// 每秒允许的请求数
doublevalue();
// 超时时间(默认不等待,立即返回)
longtimeout()default0;
// 超时时间单位
    TimeUnit timeUnit()default TimeUnit.MILLISECONDS;
}

3. 实现 AOP 切面


 

import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
publicclassRateLimitAspect {

privatestaticfinal ConcurrentHashMap<String, RateLimiter> RATE_LIMITERS = newConcurrentHashMap<>();

@Around("@annotation(rateLimit)")
public Object doAround(ProceedingJoinPoint joinPoint, RateLimit rateLimit)throws Throwable {
StringmethodName= joinPoint.getSignature().toLongString();
doublepermitsPerSecond= rateLimit.value();
longtimeout= rateLimit.timeout();
TimeUnittimeUnit= rateLimit.timeUnit();

// 获取或创建RateLimiter
RateLimiterrateLimiter= RATE_LIMITERS.computeIfAbsent(
            methodName, k -> RateLimiter.create(permitsPerSecond)
        );

boolean acquired;
if (timeout > 0) {
            acquired = rateLimiter.tryAcquire(timeout, timeUnit);
        } else {
            acquired = rateLimiter.tryAcquire();
        }

if (acquired) {
return joinPoint.proceed();
        } else {
thrownewRuntimeException("请求过于频繁,请稍后再试");
        }
    }
}

4. 在 Controller 中使用


 

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
publicclassTestController {

// QPS限制为2,最多等待500毫秒
@GetMapping("/test1")
@RateLimit(value = 2.0, timeout = 500, timeUnit = TimeUnit.MILLISECONDS)
public String test1() {
return"test1 success";
    }

// QPS限制为1,不等待立即返回
@GetMapping("/test2")
@RateLimit(value = 1.0)
public String test2() {
return"test2 success";
    }
}


方式二:使用 Spring Cloud Gateway 或 Netflix Zuul (网关层限流)

适用场景:微服务架构,在网关层统一限流。

1. 添加依赖


 

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2. 配置 Redis 和限流规则


 

spring:
redis:
host:localhost
port:6379
cloud:
gateway:
routes:
-id:user-service
uri:lb://user-service
predicates:
-Path=/api/users/**
filters:
-name:RequestRateLimiter
args:
redis-rate-limiter.replenishRate:10# 每秒允许的请求数
redis-rate-limiter.burstCapacity:20# 令牌桶容量
redis-rate-limiter.requestedTokens:1# 每个请求消耗的令牌数

3. 自定义限流Key(按用户限流)


 

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

@Configuration
publicclassRateLimitConfig {

@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
            exchange.getRequest()
                   .getHeaders()
                   .getFirst("Authorization") // 根据token限流
// 或者按IP限流: exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }
}


方式三:使用 Resilience4j (功能丰富的容错库)

适用场景:需要多种 resilience 模式(限流、熔断、重试等)的综合场景。

1. 添加依赖


 

<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 配置限流规则


 

resilience4j:
ratelimiter:
instances:
userService:
limitForPeriod:10# 时间窗口内允许的请求数
limitRefreshPeriod:1s# 时间窗口长度
timeoutDuration:0# 线程等待时间
allowHealthPermissions:false

3. 在方法上使用注解


 

import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
publicclassUserController {

@GetMapping("/users/{id}")
@RateLimiter(name = "userService", fallbackMethod = "rateLimitFallback")
public String getUser(@PathVariable String id) {
return"User " + id;
    }

// 降级方法
private String rateLimitFallback(String id, Exception e) {
return"请求过于频繁,请稍后再试";
    }
}


方式四:使用 Redisson + Lua (分布式限流)

适用场景:集群环境下的分布式限流。

1. 添加依赖


 

<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.17.0</version>
</dependency>

2. 创建分布式限流服务


 

import org.redisson.api.RRateLimiter;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

@Service
publicclassDistributedRateLimitService {

privatefinal RedissonClient redissonClient;

publicDistributedRateLimitService(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
    }

publicbooleantryAcquire(String key, long rate, long rateInterval) {
RRateLimiterrateLimiter= redissonClient.getRateLimiter(key);
// 设置速率:rate个请求/rateInterval秒
        rateLimiter.trySetRate(RateType.OVERALL, rate, rateInterval, RateIntervalUnit.SECONDS);
return rateLimiter.tryAcquire();
    }
}

3. 在 Controller 中使用


 

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
publicclassDistributedController {

privatefinal DistributedRateLimitService rateLimitService;

publicDistributedController(DistributedRateLimitService rateLimitService) {
this.rateLimitService = rateLimitService;
    }

@GetMapping("/distributed")
public String distributed() {
Stringkey="api:distributed:" + "user123"; // 按用户ID限流
if (rateLimitService.tryAcquire(key, 10, 60)) { // 60秒内最多10次
return"Success";
        } else {
thrownewRuntimeException("请求频率超限");
        }
    }
}


总结对比

方式

适用场景

优点

缺点

Guava RateLimiter

单机应用

简单易用,性能好

不支持分布式

Spring Cloud Gateway

微服务网关

统一入口限流,支持分布式

需要网关组件

Resilience4j

综合容错场景

功能丰富,集成多种模式

配置相对复杂

Redisson

分布式集群

真正的分布式限流

依赖Redis,有网络开销

选择建议:

  • 如果是单体应用,选择 Guava RateLimiter

  • 如果是微服务架构,选择 Spring Cloud Gateway

  • 如果需要完整的容错方案,选择 Resilience4j

  • 如果需要在业务代码中实现分布式限流,选择 Redisson

根据你的具体业务场景和技术架构,选择最适合的限流方式即可。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐