Java Spring如何实现超量调用后封禁10分钟的API限流器?
解决方案:基于现有Java库扩展实现「限流+临时封禁」
你的需求核心是当5秒内调用超100次时触发10分钟封禁,可以基于你已熟悉的Bucket4j或Resilience4j扩展实现,核心思路是结合限流判断与封禁状态存储,以下是具体方案:
1. 核心逻辑拆分
- 先检查请求是否处于10分钟封禁期,若是直接拒绝
- 未封禁则执行5秒内100次的限流判断
- 限流触发时,标记该API进入封禁状态,有效期10分钟
2. 基于Bucket4j的实现示例
结合Guava Cache维护封禁状态(自动过期):
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import io.github.bucket4j.Bandwidth; import io.github.bucket4j.Bucket; import io.github.bucket4j.Refill; import java.time.Duration; import java.util.concurrent.TimeUnit; public class ApiRateLimiterWithBan { // 封禁状态缓存:key为API唯一标识(如接口路径/用户+接口),自动10分钟过期 private static final Cache<String, Boolean> banCache = CacheBuilder.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .build(); // Bucket4j限流规则:5秒内允许100次调用 private static final Bucket bucket = Bucket.builder() .addLimit(Bandwidth.classic(100, Refill.intervally(100, Duration.ofSeconds(5)))) .build(); public void processApiRequest(String apiIdentifier) { // 第一步:检查封禁状态 if (banCache.getIfPresent(apiIdentifier) != null) { throw new RuntimeException("API已被封禁,请10分钟后重试"); } // 第二步:执行限流判断 if (!bucket.tryConsume(1)) { // 第三步:触发封禁 banCache.put(apiIdentifier, Boolean.TRUE); throw new RuntimeException("调用次数超限,API已被封禁10分钟"); } // 执行API业务逻辑 executeBusinessLogic(); } private void executeBusinessLogic() { // 你的API核心业务代码 } }
3. 基于Resilience4j的实现示例
同样配合Guava Cache实现封禁逻辑:
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import io.github.resilience4j.ratelimiter.RateLimiter; import io.github.resilience4j.ratelimiter.RateLimiterConfig; import io.github.resilience4j.ratelimiter.RateLimiterRegistry; import java.time.Duration; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; public class Resilience4jWithBan { private static final Cache<String, Boolean> banCache = CacheBuilder.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .build(); private static final RateLimiter rateLimiter; static { // Resilience4j限流配置:5秒内100次调用 RateLimiterConfig config = RateLimiterConfig.custom() .limitRefreshPeriod(Duration.ofSeconds(5)) .limitForPeriod(100) .timeoutDuration(Duration.ofSeconds(0)) // 触发限流直接拒绝,不等待 .build(); RateLimiterRegistry registry = RateLimiterRegistry.of(config); rateLimiter = registry.rateLimiter("apiRateLimiter"); } public void processRequest(String apiIdentifier) { if (banCache.getIfPresent(apiIdentifier) != null) { throw new RuntimeException("API已被封禁,请10分钟后重试"); } // 装饰业务逻辑,加入限流控制 Supplier<Void> restrictedCall = RateLimiter.decorateSupplier(rateLimiter, () -> { executeBusinessLogic(); return null; }); try { restrictedCall.get(); } catch (Exception e) { // 限流触发,标记封禁 banCache.put(apiIdentifier, Boolean.TRUE); throw new RuntimeException("调用次数超限,API已被封禁10分钟"); } } private void executeBusinessLogic() { // 你的API核心业务代码 } }
4. 分布式场景适配
如果是多节点部署的分布式系统,需要将Guava Cache替换为分布式缓存(如Redis),确保封禁状态在所有节点间一致。
内容的提问来源于stack exchange,提问作者SoT
相关产品推荐
相关产品推荐

