温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java API接口怎么限流

发布时间:2026-07-17 02:59:31 来源:亿速云 阅读:90 作者:小樊 栏目:编程语言

在 Java 中,API 接口限流(Rate Limiting)是非常常见的需求,目的是防止接口被恶意刷爆或保护系统稳定性。下面从常见限流算法实现方式主流框架实战示例几个层面给你一个完整说明。


一、常用限流算法

1️⃣ 固定窗口计数器(Fixed Window)

原理:每 N 秒允许 M 次请求
优点:实现简单
缺点:存在“突刺问题”(窗口边界瞬间打满)

[0s - 1s] 允许 100 次

2️⃣ 滑动窗口(Sliding Window)

原理:把时间切分成小格子,统计最近一段时间内的请求
优点:比固定窗口平滑
缺点:实现稍复杂


3️⃣ 漏桶算法(Leaky Bucket)

原理:请求进桶,固定速率流出
特点:流量很平滑,不适合突发流量


4️⃣ 令牌桶算法(Token Bucket)✅(最常用)

原理

  • 固定速率生成令牌
  • 有令牌才能访问接口
  • 可应对突发流量

生产环境首选


二、Java 中常见限流实现方式


方式一:Guava RateLimiter(单机限流)

依赖

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>32.1.3-jre</version>
</dependency>

示例

RateLimiter limiter = RateLimiter.create(5); // 每秒 5 个请求

@GetMapping("/test")
public String test() {
    if (!limiter.tryAcquire()) {
        return "被限流了";
    }
    return "success";
}

✅ 适合:

  • 单机
  • 非分布式系统

❌ 不适合分布式


方式二:Redis + Lua(分布式限流,推荐)

适用场景

  • 微服务
  • 多实例部署
  • 网关层

Redis 令牌桶 Lua 脚本

local key = KEYS[1]
local maxToken = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])

local bucket = redis.call("HMGET", key, "tokens", "timestamp")

local tokens = tonumber(bucket[1]) or maxToken
local lastTime = tonumber(bucket[2]) or now

local delta = math.max(0, now - lastTime)
tokens = math.min(maxToken, tokens + delta * rate)

if tokens < 1 then
    return 0
else
    tokens = tokens - 1
    redis.call("HMSET", key, "tokens", tokens, "timestamp", now)
    redis.call("EXPIRE", key, 10)
    return 1
end

Java 调用示例

Boolean allowed = redisTemplate.execute(
    redisScript,
    Collections.singletonList("rate_limit:api"),
    10, 1, System.currentTimeMillis() / 1000
);

if (!allowed) {
    throw new RuntimeException("请求过于频繁");
}

方式三:Spring AOP + 注解(优雅封装)

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    int limit() default 5;
    int seconds() default 1;
}

AOP 切面

@Aspect
@Component
public class RateLimitAspect {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Around("@annotation(rateLimit)")
    public Object check(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable {
        String key = "rate:" + pjp.getSignature().toLongString();
        Long count = redisTemplate.opsForValue().increment(key, 1);
        if (count == 1) {
            redisTemplate.expire(key, rateLimit.seconds(), TimeUnit.SECONDS);
        }

        if (count > rateLimit.limit()) {
            throw new RuntimeException("接口被限流");
        }
        return pjp.proceed();
    }
}

方式四:网关层限流(最佳方案)

Spring Cloud Gateway + Redis

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20

✅ 推荐用于:

  • 微服务架构
  • API 网关

三、不同场景选择建议

场景 推荐方案
单体应用 Guava RateLimiter
分布式系统 Redis + Lua
微服务 Gateway 限流
接口级控制 AOP + Redis
防止恶意刷接口 网关 + IP 限流

四、限流维度(常见)

  • ✅ 接口维度
  • ✅ 用户 ID
  • ✅ IP 地址
  • ✅ 应用级别
  • ✅ 全局限流

五、注意点

⚠️

  • 限流 ≠ 熔断
  • 返回码推荐 429 Too Many Requests
  • 避免误伤正常用户
  • 突发流量要合理设计 burst

如果你需要: ✅ 完整 Demo 项目
网关限流实战
IP 限流 + 黑名单

告诉我你的 具体场景(单体 / 微服务 / 网关 / Spring Boot 版本),我可以给你更精确的方案。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI