【Spring】Spring Cloud Gateway 网关架构深度解析:路由、过滤器、限流与 Sentinel 集成

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:QPS
  • redis_rate_limiter_denied:限流拒绝数

3. 常见问题解决方案

问题 1:限流不生效

  • 检查:Redis 连接是否正常
  • 确认:KeyResolver 是否返回非空值
  • 验证requestedTokens <= burstCapacity

问题 2:分布式环境下令牌不同步

  • 解决 :确保所有 Gateway 实例使用同一 Redis Cluster
  • 验证:Lua 脚本版本一致性

问题 3:性能瓶颈

  • 优化:本地缓存令牌状态(牺牲一致性提升性能)
  • 兜底:异步限流检查

4. 限流设计原则

  1. 分层限流:网关层(IP/API)+ 服务层(资源/用户)
  2. 自适应调整:根据系统负载动态调整阈值
  3. 监控告警:Prometheus + Grafana 实时监控
  4. 用户体验:合理设置突发容量,避免误杀正常流量
  5. 压测验证:JMeter/Gatling 模拟高并发场景

七、一句话总结

Spring Cloud Gateway 是微服务架构的流量守门员,通过令牌桶算法实现灵活的限流策略,Sentinel 集成后形成"网关层粗粒度保护 + 服务层细粒度防护"的混合限流体系。记住:限流不是限制用户,而是保护系统为更多用户提供稳定服务。

相关推荐
China_Yanhy2 小时前
AWS Backup 核心操作与架构指南
架构·云计算·aws
独自破碎E2 小时前
Spring AI怎么实现结构化输出?
java·人工智能·spring
mit6.8242 小时前
内存碎片|c++内存池|lua gc
架构
Codebee2 小时前
Ooder-AIForm专用表单Skill解决方案
架构
刘一说2 小时前
Spring Cloud微服务中的API网关:从Zuul到Spring Cloud Gateway的全面进化
spring·spring cloud·微服务
码界奇点2 小时前
基于Spring与Netty的分布式配置管理系统设计与实现
java·分布式·spring·毕业设计·源代码管理
编程武士2 小时前
API优先战略:数字时代架构设计的核心基石
架构·api
熏鱼的小迷弟Liu4 小时前
【消息队列】RabbitMQ的基本架构?
面试·架构·rabbitmq