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

能否使用Resilience4j在Java中实现基于IP的限流器?

基于Resilience4j实现IP维度的限流方案

核心思路

Resilience4j的RateLimiter是实例级别的限流组件,要实现基于IP的限流,核心逻辑是为每个请求IP创建并维护独立的RateLimiter实例,以IP作为唯一标识区分不同的限流规则实例。

具体实现步骤

1. 定义基础限流配置

先统一配置通用限流规则,也可后续针对特定IP做差异化调整:

// 基础限流配置:每秒允许10次请求,超时等待500ms
RateLimiterConfig defaultConfig = RateLimiterConfig.custom()
    .limitForPeriod(10)
    .limitRefreshPeriod(Duration.ofSeconds(1))
    .timeoutDuration(Duration.ofMillis(500))
    .build();

2. 维护IP与限流器的映射

使用线程安全的缓存存储IP对应的限流器实例,避免重复创建:

private final ConcurrentHashMap<String, RateLimiter> ipRateLimiters = new ConcurrentHashMap<>();
private final RateLimiterConfig defaultConfig;

public IpRateLimiter(RateLimiterConfig defaultConfig) {
    this.defaultConfig = defaultConfig;
}

// 根据IP获取或创建对应的限流器
private RateLimiter getRateLimiterByIp(String ip) {
    return ipRateLimiters.computeIfAbsent(ip, key -> RateLimiter.of(key, defaultConfig));
}

3. 拦截请求并执行限流判断

在请求拦截器(如Spring HandlerInterceptor、Servlet Filter)中获取客户端IP,通过对应限流器判断是否允许请求:

// Spring MVC拦截器示例
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String clientIp = extractClientIp(request);
    RateLimiter rateLimiter = getRateLimiterByIp(clientIp);
    
    if (!rateLimiter.acquirePermission()) {
        response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        response.getWriter().write("Too many requests from your IP");
        return false;
    }
    return true;
}

// 处理反向代理场景,获取真实客户端IP
private String extractClientIp(HttpServletRequest request) {
    String ip = request.getHeader("X-Forwarded-For");
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getRemoteAddr();
    }
    // 多IP场景取第一个(反向代理链)
    if (ip != null && ip.contains(",")) {
        ip = ip.split(",")[0].trim();
    }
    return ip;
}

4. 可选:优化内存与动态配置

  • 定时清理过期实例:针对长时间无请求的IP,定时清理缓存中的限流器,避免内存泄漏:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> {
    long oneHourAgo = System.currentTimeMillis() - 3600000;
    ipRateLimiters.entrySet().removeIf(entry -> {
        RateLimiter.Metrics metrics = entry.getValue().getMetrics();
        return metrics.getAvailablePermissions() == entry.getValue().getRateLimiterConfig().getLimitForPeriod()
                && metrics.getLastPermissionGrantedTimestamp() < oneHourAgo;
    });
}, 1, 1, TimeUnit.HOURS);
  • 差异化配置:可扩展逻辑,从配置中心读取特定IP的限流规则,创建自定义的RateLimiter实例。

注意事项

  • IP准确性:服务部署在反向代理后,必须从X-Forwarded-For等请求头获取真实IP,避免误将代理IP作为客户端IP。
  • 线程安全:必须使用线程安全的集合存储限流器实例,防止并发场景下的创建冲突。
  • 内存控制:IP数量极大时,需结合定时清理机制限制缓存大小,避免OOM。

内容的提问来源于stack exchange,提问作者SIvaji

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 19:03:25