Spring Cloud Gateway 网关架构深度解析:路由、过滤器、限流与 Sentinel 集成
Spring Cloud Gateway 作为 Spring Cloud 生态的 API 网关,承担着路由转发、负载均衡、权限校验、限流熔断 等核心职责。它基于 WebFlux + Netty 构建,提供响应式、可扩展的网关解决方案。
一、核心架构与定位
架构定位
Spring Cloud Gateway 作为微服务架构的流量入口 ,是保护后端服务的第一道防线。其核心功能包括:
- 路由(Route):将请求转发到目标服务
- 过滤(Filter):在请求/响应生命周期中执行自定义逻辑
- 限流(Rate Limiting):防止系统过载,保障服务可用性
二、路由(Route)详解
1. 路由配置模型
路由是网关的基本单元,由 ID、URI、断言(Predicates)、过滤器(Filters) 组成。
基础配置示例:
yaml
spring:
cloud:
gateway:
routes:
- id: order-service # 路由唯一标识
uri: lb://order-service # 目标服务(lb:// = 负载均衡)
predicates: # 断言条件(必须全部匹配)
- Path=/api/orders/** # 路径匹配
- Method=GET,POST # 请求方法匹配
- Header=X-Request-Id, \d+ # Header 正则匹配
filters: # 过滤器链
- StripPrefix=1 # 去掉第1级路径
- AddRequestHeader=X-Gateway, optimized
路由加载方式:
- 静态配置:YAML/Properties 文件
- 动态路由 :通过
RouteDefinitionRepository从数据库/Nacos 加载
动态路由实现:
java
@Bean
public RouteLocator dynamicRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route("dynamic_route", r -> r
.path("/dynamic/**")
.filters(f -> f.stripPrefix(1))
.uri("lb://dynamic-service")
).build();
}
2. 断言工厂(Predicate Factory)
断言用于匹配请求,Spring Cloud Gateway 内置 10+ 种断言。
| 断言类型 | 配置示例 | 说明 |
|---|---|---|
| Path | - Path=/api/orders/** |
路径通配匹配 |
| Method | - Method=GET,POST |
请求方法匹配 |
| Header | - Header=X-Request, \d+ |
Header 正则匹配 |
| Weight | - Weight=groupA, 80 |
权重路由(灰度) |
| Before/After | - Before=2025-01-01T00:00:00 |
时间窗口匹配 |
| RemoteAddr | - RemoteAddr=192.168.1.1/24 |
IP 段匹配 |
组合断言:
yaml
predicates:
- Path=/api/orders/**
- Method=GET
- Header=Authorization, Bearer.*
逻辑:所有断言都匹配才路由
3. 路由优化最佳实践
实践 1:精准匹配优先
yaml
# ❌ 错误:过度泛化
- Path=/**
# ✅ 正确:精确路径
- Path=/api/orders/**
# ✅ 更优:方法 + 路径
- Path=/api/orders/{id}
- Method=GET
实践 2:路由分层设计
graph LR
A[网关] --> B[业务路由组]
A --> C[管理路由组]
B --> D[订单服务]
B --> E[支付服务]
C --> F[健康检查]
优势:路由分组管理,便于权限控制和限流策略差异化
实践 3:权重路由(灰度发布)
yaml
- id: order-service-v1
uri: lb://order-v1
predicates:
- Path=/api/orders/**
- Weight=order-group, 80 # 80% 流量
- id: order-service-v2
uri: lb://order-v2
predicates:
- Path=/api/orders/**
- Weight=order-group, 20 # 20% 流量
三、过滤器(Filter)详解
1. 过滤器类型
| 类型 | 作用域 | 配置方式 | 典型场景 |
|---|---|---|---|
| GlobalFilter | 全局 | @Component |
认证、日志、跨域 |
| GatewayFilter | 路由级 | YAML/DSL | 限流、加解密、Header 操作 |
| Ordered | 顺序 | @Order 注解 |
控制执行顺序 |
2. 过滤器执行顺序(过滤器链)
优先级 :Route Filter > Global Filter > Default Filter
执行顺序控制:
java
@Bean
@Order(-1) // 数值越小优先级越高(HIGHEST_PRECEDENCE = Integer.MIN_VALUE)
public GlobalFilter essentialFilter() {
return (exchange, chain) -> {
// 在路由处理前执行
ServerHttpRequest modified = exchange.getRequest()
.mutate()
.header("X-Gateway", "optimized")
.build();
return chain.filter(exchange.mutate().request(modified).build());
};
}
过滤器链可视化:
响应 缓存过滤器 限流过滤器 认证过滤器 请求 响应 缓存过滤器 限流过滤器 认证过滤器 请求 1.身份验证 2.流量控制 3.响应缓存 返回结果
3. 全局过滤器(GlobalFilter)
内置全局过滤器:
- NettyRoutingFilter:路由转发
- LoadBalancerClientFilter:负载均衡
- ForwardRoutingFilter:本地转发
自定义全局过滤器:
java
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100; // 高优先级,先执行认证
}
}
4. 网关过滤器(GatewayFilter)
常用网关过滤器:
yaml
filters:
- StripPrefix=1 # 去掉第1级路径(/api/orders → /orders)
- AddRequestHeader=X-Gateway, optimized
- AddRequestParameter=debug, true
- CircuitBreaker=myCircuitBreaker # 集成 Resilience4j 熔断
- RequestRateLimiter=10,20,redis # 限流(10=速率, 20=容量)
- Retry=3,404,500ms # 重试3次,状态码404,间隔500ms
四、限流(Rate Limiting)深度实现
1. 限流核心价值
- 防止系统过载:保护后端服务不被突发流量冲垮
- 公平资源分配:确保每个用户/服务获得合理配额
- 提升用户体验:通过限流避免级联故障,保障核心功能可用性
2. 限流算法对比
| 算法 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 固定窗口 | 按时间窗口计数 | 简单 | 临界问题(窗口边界突发) | 简单场景 |
| 滑动窗口 | Redis ZSet 实现平滑窗口 | 平滑限流 | 内存占用高 | 精确限流 |
| 漏桶算法 | 恒定速率处理 | 绝对平滑 | 不支持突发 | 严格限速 |
| 令牌桶 | 桶存令牌,匀速填充 | 支持突发 | 实现稍复杂 | 通用场景 |
Spring Cloud Gateway 内置算法 :令牌桶算法
3. Redis 分布式限流实现(生产推荐)
令牌桶算法核心:
java
public class RedisRateLimiter extends AbstractRateLimiter<RedisRateLimiter.Config> {
@Override
public Mono<Response> isAllowed(String routeId, String id) {
Config routeConfig = getConfig().get(routeId);
int replenishRate = routeConfig.getReplenishRate(); // 每秒填充速率
int burstCapacity = routeConfig.getBurstCapacity(); // 桶容量
return redisTemplate.execute(script, keys,
replenishRate,
burstCapacity,
Instant.now().getEpochSecond(),
1); // 请求1个令牌
}
}
Lua 脚本(原子性保障):
lua
-- KEYS[1]: rate_limiter.{key}
-- ARGV[1]: replenishRate
-- ARGV[2]: burstCapacity
-- ARGV[3]: timestamp
-- ARGV[4]: requestedTokens
local current = redis.call('get', KEYS[1])
if current == false then
current = 0
else
current = tonumber(current)
end
-- 计算当前令牌数(考虑时间流逝填充)
local fill_time = 1 / ARGV[1] -- 生成一个令牌的时间
local tokens_to_add = math.floor((ARGV[3] - current) / fill_time)
local new_tokens = math.min(ARGV[2], current + tokens_to_add)
-- 判断是否允许请求
if new_tokens >= ARGV[4] then
redis.call('set', KEYS[1], new_tokens - ARGV[4])
return 1 -- 允许
else
return 0 -- 拒绝
end
配置示例:
yaml
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100 # 每秒100个请求
redis-rate-limiter.burstCapacity: 200 # 突发容量200
redis-rate-limiter.requestedTokens: 1 # 每次请求消耗1个令牌
key-resolver: "#{@userKeyResolver}" # 按用户限流
KeyResolver(限流维度):
java
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getQueryParams().getFirst("userId") != null
? exchange.getRequest().getQueryParams().getFirst("userId")
: "anonymous"
);
}
4. 限流最佳实践
实践 1:突发容量设置
yaml
# replenishRate <= burstCapacity,避免正常流量被误杀
replenishRate: 100
burstCapacity: 200 # 建议 = replenishRate * 2
实践 2:多维度限流
java
// 按 IP + 用户 + API 组合限流
@Bean
public KeyResolver compositeKeyResolver() {
return exchange -> {
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
String path = exchange.getRequest().getURI().getPath();
return Mono.just(ip + ":" + userId + ":" + path);
};
}
实践 3:Redis 集群
- 生产环境使用 Redis Cluster,避免单点故障
- 配置
spring.redis.cluster.nodes
五、Sentinel 集成(混合限流方案)
1. 为什么需要 Sentinel?
Spring Cloud Gateway 限流适合网关层粗粒度 控制,但无法做到服务层细粒度 防护和熔断降级。
Sentinel 优势:
- 多限流算法:令牌桶、漏桶、滑动窗口
- 熔断降级:基于响应时间、异常比例
- 热点防护:针对高频访问的参数限流
- 系统自适应:根据系统负载自动限流
2. Gateway + Sentinel 混合架构
架构设计:
┌─────────────────────────────────────┐
│ Spring Cloud Gateway │
│ ┌─────────────────────────────┐ │
│ │ Gateway 层限流(粗粒度) │ │
│ │ - 基于 IP/用户/API │ │
│ │ - 保护网关不被冲垮 │ │
│ └─────────────┬────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────┐ │
│ │ Sentinel 服务层限流(细) │ │
│ │ - 基于资源名 │ │
│ │ - 熔断降级 │ │
│ │ - 热点防护 │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
3. Sentinel 集成实现
依赖配置:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
Sentinel 限流规则:
java
@Component
public class SentinelRateLimiter {
@PostConstruct
public void initRules() {
// 订单创建接口限流(每秒 50 个)
FlowRule orderRule = new FlowRule("createOrder");
orderRule.setCount(50);
orderRule.setGrade(FlowRuleConstant.FLOW_GRADE_QPS);
orderRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
// 热点参数限流(单个商品每秒 10 次查询)
ParamFlowRule hotRule = new ParamFlowRule("getProduct");
hotRule.setParamIdx(0); // 第0个参数(商品ID)
hotRule.setCount(10);
FlowRuleManager.loadRules(Collections.singletonList(orderRule));
ParamFlowRuleManager.loadRules(Collections.singletonList(hotRule));
}
}
Gateway 路由配置 Sentinel 过滤器:
yaml
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
filters:
- name: SentinelGatewayFilter # Sentinel 网关过滤器
args:
resource-mode: 0 # 0=按 route ID, 1=按自定义资源名
4. 混合限流配置示例
yaml
# Gateway 层:粗粒度限流(保护网关)
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1000 # 网关层 1000 QPS
redis-rate-limiter.burstCapacity: 2000
# Sentinel 层:细粒度限流(保护服务)
@PostConstruct
public void initSentinelRules() {
// 服务层接口限流(更严格)
FlowRule rule = new FlowRule("createOrder");
rule.setCount(50); # 订单创建 50 QPS
FlowRuleManager.loadRules(Collections.singletonList(rule));
}
六、最佳实践与避坑指南
1. 性能优化
连接池优化:
yaml
spring:
cloud:
gateway:
httpclient:
pool:
max-connections: 500
acquire-timeout: 2000
本地缓存:
java
// 缓存限流令牌状态,减少 Redis 访问
@Bean
public CaffeineCache tokenCache() {
return new CaffeineCache("rate-limit-cache",
Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.SECONDS)
.maximumSize(10000)
.build()
);
}
2. 监控与告警
集成 Prometheus:
java
@Bean
public MeterRegistryCustomizer<MeterRegistry> metrics() {
return registry -> registry.config().commonTags(
"application", "gateway"
);
}
Grafana 监控指标:
gateway_requests_total:总请求数gateway_requests_per_second:QPSredis_rate_limiter_denied:限流拒绝数
3. 常见问题解决方案
问题 1:限流不生效
- 检查:Redis 连接是否正常
- 确认:KeyResolver 是否返回非空值
- 验证 :
requestedTokens <= burstCapacity
问题 2:分布式环境下令牌不同步
- 解决 :确保所有 Gateway 实例使用同一 Redis Cluster
- 验证:Lua 脚本版本一致性
问题 3:性能瓶颈
- 优化:本地缓存令牌状态(牺牲一致性提升性能)
- 兜底:异步限流检查
4. 限流设计原则
- 分层限流:网关层(IP/API)+ 服务层(资源/用户)
- 自适应调整:根据系统负载动态调整阈值
- 监控告警:Prometheus + Grafana 实时监控
- 用户体验:合理设置突发容量,避免误杀正常流量
- 压测验证:JMeter/Gatling 模拟高并发场景
七、一句话总结
Spring Cloud Gateway 是微服务架构的流量守门员,通过令牌桶算法实现灵活的限流策略,Sentinel 集成后形成"网关层粗粒度保护 + 服务层细粒度防护"的混合限流体系。记住:限流不是限制用户,而是保护系统为更多用户提供稳定服务。