Spring Boot下按10TPS调用外部API的限流策略方案咨询
Spring Boot中API调用的限流方案(10TPS场景)
核心算法选择:令牌桶算法
令牌桶是这类场景的最优解:它每秒生成固定数量的令牌(这里是10个),每次API调用需要先获取令牌。如果某一秒的令牌没用完,会累积到令牌桶上限(可配置),后续可以一次性使用这些累积的令牌,避免像固定延迟那样浪费空闲配额,从而缩短整体TAT。
相比之下,漏桶算法是严格平滑输出,无法利用空闲额度,会拉长总耗时;而简单的时间窗口限流(比如每秒计数)容易出现“突刺”问题(比如每秒最后10ms发10次请求),可能触发API端的限流。
具体实现方案
方案一:Guava RateLimiter(快速集成)
Guava的RateLimiter是实现令牌桶的轻量方案,无需复杂配置,适合快速落地。
- 引入依赖
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.1.3-jre</version> </dependency>
- 配置RateLimiter实例
import com.google.common.util.concurrent.RateLimiter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RateLimiterConfig { @Bean public RateLimiter externalApiRateLimiter() { // 每秒生成10个令牌,支持突发请求(默认桶容量为10,可通过第二个参数调整) return RateLimiter.create(10.0); // 如果需要更大的突发容量,比如允许最多20个请求的突发: // return RateLimiter.create(10.0, 20); } }
- 限流调用API
import com.google.common.util.concurrent.RateLimiter; import org.springframework.stereotype.Component; import java.util.concurrent.CompletableFuture; @Component public class ApiCaller { private final RateLimiter rateLimiter; private final ExternalApiService externalApiService; public ApiCaller(RateLimiter rateLimiter, ExternalApiService externalApiService) { this.rateLimiter = rateLimiter; this.externalApiService = externalApiService; } public void executeBatchCalls() { int totalRequests = 50000; for (int i = 0; i < totalRequests; i++) { // 阻塞直到获取令牌,保证TPS不超过10 rateLimiter.acquire(); // 异步调用API,避免主线程阻塞,提升整体效率 CompletableFuture.runAsync(externalApiService::callExternalApi); } } }
方案二:Resilience4j RateLimiter(Spring生态推荐)
Resilience4j是Spring官方推荐的容错组件,限流模块功能更丰富,支持配置化、监控、事件监听等,适合生产环境。
- 引入依赖
<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> <version>2.1.0</version> </dependency>
- 配置文件(application.yml)
resilience4j: rate-limiter: instances: externalApiLimiter: limit-for-period: 10 # 每周期允许的请求数 limit-refresh-period: 1s # 周期长度(每秒刷新一次令牌) timeout-duration: 0 # 获取令牌的超时时间,0表示无限等待 register-health-indicator: true # 注册健康指标,方便监控
- 限流调用(两种方式)
注解式(简洁)
import io.github.resilience4j.ratelimiter.annotation.RateLimiter; import org.springframework.stereotype.Service; @Service public class ExternalApiService { @RateLimiter(name = "externalApiLimiter") public void callExternalApi() { // 实际调用外部API的逻辑 } }
编程式(更灵活)
import io.github.resilience4j.ratelimiter.RateLimiter; import io.github.resilience4j.ratelimiter.RateLimiterRegistry; import org.springframework.stereotype.Service; import java.util.concurrent.CompletableFuture; @Service public class ExternalApiService { private final RateLimiter rateLimiter; public ExternalApiService(RateLimiterRegistry rateLimiterRegistry) { this.rateLimiter = rateLimiterRegistry.rateLimiter("externalApiLimiter"); } public void callExternalApi() { // 装饰API调用逻辑,自动处理限流 Runnable decoratedRunnable = RateLimiter.decorateRunnable(rateLimiter, this::actualApiCall); // 异步执行 CompletableFuture.runAsync(decoratedRunnable); } private void actualApiCall() { // 实际调用外部API的代码 } }
优化建议
- 异步执行:结合
CompletableFuture异步调用API,避免主线程阻塞,充分利用CPU资源,同时令牌桶控制TPS,不会超出限制。 - 突发容量调整:如果外部API允许短时间的突发请求(比如允许1秒内最多20次),可以调整令牌桶的容量,比如Guava的
RateLimiter.create(10, 20),这样能更快处理累积的请求,缩短总耗时。 - 异常与重试:如果API调用失败,重试逻辑也要受限流控制,避免重试导致TPS超标。可以结合Resilience4j的重试组件,将重试和限流一起配置。
参考资料
- Guava官方文档中
RateLimiter章节(讲解令牌桶算法实现与使用细节) - Resilience4j官方文档中RateLimiter模块说明(配置、监控、扩展等)
- Spring官方文档中Resilience4j集成指南
内容的提问来源于stack exchange,提问作者Tojra
相关产品推荐
相关产品推荐

