You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 18:40:33