1. 为什么我们需要API限流上周我们的订单服务突然崩溃排查后发现是某个合作方疯狂调用查询接口每秒请求量突破5000次直接打垮了服务集群。这种场景下API限流就像高速路上的收费站必须控制车流速度才能保证系统畅通。SpringBoot生态中有多种成熟的限流方案今天我就结合生产实践分享三种最实用的实现方式。2. 主流限流方案对比选型2.1 令牌桶 vs 漏桶算法先看两个核心算法令牌桶系统以固定速率往桶里放令牌请求需要拿到令牌才能执行类似游乐园门票漏桶请求像水一样流入桶中以恒定速率流出处理像漏斗匀速过滤我们做过压测对比算法类型突发流量处理实现复杂度适用场景令牌桶允许短时突发中等需要弹性限流的API漏桶严格匀速简单需要绝对平滑的场景2.2 Guava RateLimiter实战// 每秒10个令牌的限流器 RateLimiter limiter RateLimiter.create(10.0); GetMapping(/order) public String createOrder() { if(!limiter.tryAcquire()) { throw new RuntimeException(手速太快啦稍后再试); } // 业务逻辑 }重要提示单机版RateLimiter在集群环境下需要配合Redis实现分布式限流2.3 RedisLua分布式方案这是我们的生产级配置-- KEYS[1]限流keyARGV[1]限流阈值ARGV[2]过期时间 local key KEYS[1] local limit tonumber(ARGV[1]) local expire tonumber(ARGV[2]) local current tonumber(redis.call(get, key) or 0) if current 1 limit then return 0 else redis.call(INCR, key) if current 0 then redis.call(EXPIRE, key, expire) end return 1 endJava调用示例// 每秒限流100次 String luaScript ...; // 上面的脚本 RedisScriptLong script RedisScript.of(luaScript, Long.class); Boolean allowed redisTemplate.execute(script, Collections.singletonList(api_limit:apiKey), 100, 1);3. SpringCloud Gateway全局限流3.1 网关层过滤器配置spring: cloud: gateway: routes: - id: order-service uri: lb://order-service predicates: - Path/api/order/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 50 # 每秒令牌数 redis-rate-limiter.burstCapacity: 100 # 令牌桶容量 key-resolver: #{ipKeyResolver}3.2 自定义限流维度Bean KeyResolver ipKeyResolver() { return exchange - { String ip exchange.getRequest() .getRemoteAddress().getAddress().getHostAddress(); return Mono.just(ip); // 按IP限流 }; }可以扩展为按用户ID、设备号等维度限流4. 生产环境避坑指南4.1 突发流量应对策略我们曾遇到秒杀活动导致限流失效最终采用分级限流方案网关层全局QPS限制服务层方法级细粒度限流线程池控制并发处理数4.2 监控指标埋点建议监控这些关键指标限流触发次数请求响应时间P99系统负载变化错误码429占比Prometheus配置示例- pattern: spring_cloud_gateway_requests_seconds_count{outcomeTHROTTLED,} name: api_throttled_requests4.3 动态调整技巧通过配置中心实现热更新RefreshScope Configuration public class RateLimitConfig { Value(${rate.limit.threshold}) private int threshold; // 动态创建限流器 }5. 高级场景解决方案5.1 热点参数限流比如对商品详情页实现普通商品1000QPS爆款商品5000QPSRateLimiter(value #{rateConfig.getLimit(#productId)}) public ProductDetail getDetail(String productId) { //... }5.2 灰度环境特殊策略在AB测试时我们对新老版本采用不同限流值if(featureToggle.isNewVersion(userId)){ rateLimiter RateLimiter.create(200); }else{ rateLimiter RateLimiter.create(100); }实际项目中我们组合使用这些方案后API可用性从99.5%提升到了99.99%。最后分享一个经验在网关层建议设置稍宽松的限流值具体的业务规则限制放在服务内部实现这样既能防刷又不会误伤正常请求。