1. 为什么需要API网关的限流与熔断?
在微服务架构中,API网关作为所有请求的入口,其稳定性直接决定了整个系统的可用性。去年我们团队就经历过一次惨痛的教训:某个促销活动期间,由于未配置限流措施,突发流量直接击穿了订单服务,导致整个电商系统瘫痪了47分钟。这正是API网关需要具备限流和熔断能力的最典型场景。
限流(Rate Limiting)的本质是控制系统处理请求的速率,就像高速公路上的收费站通过控制车辆通行频率来避免拥堵。当QPS达到阈值时,新的请求会被立即拒绝或排队等待,防止后端服务过载。而熔断(Circuit Breaking)则类似于电路保险丝,当服务错误率超过阈值时自动切断请求链路,给故障服务恢复的时间。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Spring Cloud Gateway限流实战
2.1 基于Redis的令牌桶实现
Spring Cloud Gateway默认采用Redis + Lua脚本的方式实现令牌桶算法。这是我常用的配置模板:
yaml复制spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100 # 每秒补充的令牌数
redis-rate-limiter.burstCapacity: 200 # 令牌桶容量
key-resolver: "#{@ipKeyResolver}" # 按IP限流
关键参数说明:
replenishRate:相当于漏桶的出水速率,决定平均QPSburstCapacity:允许的瞬时最大流量,应对突发请求key-resolver:限流维度,支持按IP、用户、接口等
重要提示:生产环境一定要配置
burstCapacity大于replenishRate,否则会导致所有突发请求被拒绝。我们曾经因此损失了30%的秒杀订单。
2.2 自定义限流策略
当默认实现不满足需求时,可以通过实现RateLimiter接口定制限流逻辑。比如实现一个基于滑动窗口的限流器:
java复制public class SlidingWindowLimiter implements RateLimiter {
private final Map<String, Deque<Long>> requestLogs = new ConcurrentHashMap<>();
@Override
public Mono<Response> isAllowed(String routeId, String id) {
long now = System.currentTimeMillis();
Deque<Long> timestamps = requestLogs.computeIfAbsent(id, k -> new ConcurrentLinkedDeque<>());
// 移除1秒前的记录
while (!timestamps.isEmpty() && now - timestamps.peekFirst() > 1000) {
timestamps.pollFirst();
}
if (timestamps.size() < 100) { // 限流100QPS
timestamps.addLast(now);
return Mono.just(new Response(true, -1));
}
return Mono.just(new Response(false, -1));
}
}
3. 集成Sentinel实现熔断降级
3.1 网关层熔断配置
Sentinel 1.6.0+版本提供了对Spring Cloud Gateway的适配模块。首先添加依赖:
xml复制<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
然后配置熔断规则(以响应时间熔断为例):
java复制@PostConstruct
public void initRules() {
GatewayFlowRule rule = new GatewayFlowRule("order-service")
.setCount(50) // 阈值
.setIntervalSec(1) // 统计窗口
.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER) // 匀速排队
.setMaxQueueingTimeoutMs(500); // 排队超时时间
GatewayRuleManager.loadRules(Collections.singletonList(rule));
// 熔断规则:5秒内RT>500ms的请求比例超过50%则熔断10秒
DegradeRule degradeRule = new DegradeRule("order-service")
.setGrade(RuleConstant.DEGRADE_GRADE_RT)
.setCount(500)
.setTimeWindow(10)
.setRtSlowRequestAmount(5)
.setMinRequestAmount(10);
DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
}
3.2 熔断事件监听
通过实现SentinelGatewayCallback可以获取熔断事件通知:
java复制@Component
public class GatewayBlockHandler implements SentinelGatewayCallback {
@Override
public Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable ex) {
// 记录熔断日志
log.warn("Trigger circuit breaking: {}", exchange.getRequest().getURI(), ex);
// 返回友好提示
return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(
Map.of("code": 429, "message": "系统繁忙,请稍后重试")
));
}
}
4. 生产环境最佳实践
4.1 动态规则配置
结合Nacos实现规则热更新:
java复制@Configuration
public class RuleConfig {
@Bean
public Converter<String, List<FlowRule>> flowRuleParser() {
return source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {});
}
@Bean
public ConfigService nacosConfigService() throws Exception {
return ConfigFactory.createConfigService("nacos.address:8848");
}
@Bean
public DataSource<List<FlowRule>> nacosFlowRuleDataSource(
ConfigService configService,
Converter<String, List<FlowRule>> converter) {
return new NacosDataSource<>(
configService, "gateway-flow-rules", "DEFAULT_GROUP",
converter::convert
).get();
}
}
4.2 多维度限流策略
根据业务特点组合使用不同维度的限流:
| 维度 | 适用场景 | 实现方式 |
|---|---|---|
| 全局 | 保护基础设施 | KeyResolver.simpleKey("global") |
| 服务 | 防止单服务过载 | 按routeId限流 |
| 用户 | 防止恶意用户 | exchange -> Mono.just(exchange.getRequest().getHeaders().getFirst("userId")) |
| IP | 防止DDoS攻击 | @Bean KeyResolver ipKeyResolver() |
4.3 熔断恢复策略
采用渐进式恢复策略避免二次雪崩:
java复制DegradeRule rule = new DegradeRule()
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
.setCount(0.5) // 异常比例阈值
.setTimeWindow(10) // 基础熔断时长
.setMinRequestAmount(20) // 最小请求数
.setStatIntervalMs(60000) // 统计周期
.setSlowRatioThreshold(0.8) // 慢调用比例
.setRecoveryTimeoutMs(30000) // 完全恢复时长
.setMaxAllowedRtMs(2000); // 最大允许RT
5. 常见问题排查指南
5.1 限流失效问题
现象:配置了限流但未生效
排查步骤:
- 检查Redis连接是否正常
- 确认
KeyResolver返回非空值 - 查看
RedisRateLimiter的Lua脚本是否执行成功 - 检查过滤器顺序是否正确(限流过滤器应靠前)
5.2 熔断误触发
现象:正常请求被熔断
解决方案:
- 调整
minRequestAmount避免低流量期误判 - 设置
statIntervalMs延长统计窗口 - 使用
DegradeRule的recoveryTimeoutMs逐步恢复
5.3 性能优化建议
- Redis使用Pipeline批量执行Lua脚本
- Sentinel统计使用异步日志
- 网关实例数 >= (最大预期QPS / 单实例处理能力) * 2
- JVM参数建议:
bash复制
-Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=100
在实际项目中,我们通过这套方案将系统可用性从99.5%提升到了99.99%。特别是在大促期间,即使订单量增长300%,系统仍能保持稳定运行。记住:好的限流熔断策略应该像优秀的交通管制系统——既不会让车辆完全停滞,又能防止道路彻底瘫痪。
