【网关SCG】15 Spring Cloud Gateway请求匹配到多个路由如何选择?多个Predicate如何处理?

本文深入探讨Spring Cloud Gateway的请求处理流程,重点解析当请求匹配到多个路由时,如何依据Predicate进行选择。通过分析源码,揭示了RoutePredicateHandlerMapping如何进行路由匹配,包括获取所有路由、Predicate谓词匹配、Flux.next()的选择机制,以及路由验证和结果返回。文中还指出,即使有多个匹配路由,也会仅选择第一个,并且每个Route的多个Predicate会被拆分处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

至此微服务网关系列文章已出:

  1. 【云原生&微服务>SCG网关篇一】为什么要有网关、生产环境如何选择网关
  2. 云原生&微服务>SCG网关篇二】生产上那些灰度发布方式
  3. 【云原生&微服务>SCG网关篇三】Spring Cloud Gateway是什么、详细使用案例
  4. 云原生&微服务>SCG网关篇四】Spring Cloud Gateway内置的11种PredicateFactory如何使用
  5. 【云原生&微服务>SCG网关篇五】Spring Cloud Gateway自定义PredicateFactory
  6. 【云原生&微服务>SCG网关篇六】Spring Cloud Gateway内置的18种Filter使用姿势
  7. 【云原生&微服务>SCG网关篇七】Spring Cloud Gateway基于内置Filter实现限流、熔断、重试
  8. 【云原生&微服务>SCG网关篇八】Spring Cloud Gateway三种自定义Filter、GlobalFilter的方式
  9. 【云原生&微服务>SCG网关篇九】Spring Cloud Gateway集成Nacos详细案例
  10. 【云原生&微服务>SCG网关篇十】Spring Cloud Gateway集成Actuator、Zipkin详细案例
  11. 【云原生&微服务>SCG网关篇十一】Spring Cloud Gateway解决跨域问题
  12. 【云原生&微服务>SCG网关篇十二】Spring Cloud Gateway集成Sentinel API实现多种限流方式
  13. 源码深度剖析Spring Cloud Gateway如何处理一个请求
  14. Spring Cloud Gateway如何实现负载均衡?

聊了以下问题:

  1. 为什么要有网关?网关的作用是什么?
  2. 网关的分类?
  3. 网关的技术选型?
  4. 使用网关时常用的灰度发布方式有哪些?
  5. Spring Cloud Gateway是什么?详细使用案例?
  6. Spring Cloud Gateway内置的11种PredicateFactory
  7. 如何自定义PredicateFactory?
  8. Spring Cloud Gateway内置的18种常用的Filter
  9. Spring Cloud Gateway基于内置Filter实现限流、熔断、重试
  10. Spring Cloud Gateway三种自定义Filter、GlobalFilter的方式
  11. Spring Cloud Gateway集成Nacos案例
  12. Spring Cloud Gateway集成Actuator、Zipkin案例
  13. Spring Cloud Gareway如何解决CORS跨域问题
  14. Spring Cloud Gateway集成Sentinel API实现限流
  15. 从源码来看Spring Cloud Gateway如何处理一个请求?
  16. 从源码来看Spring Cloud Gateway如何实现负载均衡?

本文就基于源码深度剖析Spring Cloud Gateway如何处理一个请求的请求执行流程,继续来看如果请求匹配到多个路由怎么处理?

二、RoutePredicateHandlerMapping匹配路由

1、Gateway处理请求的流程

Spring Cloud Gateway对请求的处理流程见博文:源码深度剖析Spring Cloud Gateway如何处理一个请求

在这里插入图片描述

RoutePredicateHandlerMapping这个HandlerMapping会负责对请求进行路由匹配。

2、RoutePredicateHandlerMapping匹配路由

RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)方法会从我们application.yml文件中配置的所有路由中根据Predicate做路由匹配,找到当前请求对应的路由。

以如下application.yml配置文件中配置的路由信息为例:

spring:
  cloud:
    gateway:
      routes:
        - id: gateway-nacos-service-route-fail
          uri: lb://gateway-nacos-provider
          predicates:
            - Path=/nacos/**
            - Before=2024-01-01T00:00:00.000+08:00[Asia/Shanghai]
            - After=2023-01-01T00:00:00.000+08:00[Asia/Shanghai]
          filters:
            - PrefixPath=/saint
        - id: gateway-nacos-service-route
          uri: lb://gateway-nacos-provider
          predicates:
            - Path=/nacos/**
          filters:
            - StripPrefix=1

针对http://localhost:9999/nacos/路径过来的请求都会匹配到两个路由:gateway-nacos-service-route-fail、gateway-nacos-service-route。

1)获取所有路由

实例application.yml文件中一共给出了两个路由,所以lookupRoute()方法中也一共找到两个自定的路由。
在这里插入图片描述

获取到所有的路由之后,会对路由进行Predicate谓词匹配。即:进入到Route.getPredicate().apply方法。

2)多个Predicate谓词匹配

在源码中判断Route是否有效时,仅仅是通过route.getPredicate()方法获取到一个Predicate;

public AsyncPredicate<ServerWebExchange> getPredicate() {
    return this.predicate;
}

但是一个Route中可能包含多个Predicate;

Gateway使用AsyncPredicate接口的实现类AndAsyncPredicate来包装所有的Predicate;AndAsyncPredicate将所有的Predicate分为两部分:left 和 right,而每一部分的Predicate又都被AsyncPredicate包装;

在这里插入图片描述

就路由gateway-nacos-service-route-fail而言:

  • 其中有三个Predicate,分别为:Path、Before、After;
  • 最上层的AndAsyncPredicate中的left 为Path 和 Before 组合在一起的 AndAsyncPredicate(其中left为Path,right为Before)、right为After。

调用Predicate.apply()方法做谓词匹配时,会分别调用left 和 right 的apply()方法;
在这里插入图片描述

示例中的Route中有三个Predicate:

  • 第一次调用predicate.apply()方法时,left AsyncPredicate中有2个Predicate,用&&相连;right AsyncPredicate中有1个Predicate。
  • 在进入到left.apply()方法时,left AsyncPredicate中 1个Predicate、right AsyncPredicate中 1个Predicate;
  • 这里可以看做是针对left#apply()方法的一个递归操作,直到left中仅包含一个Predicate时,再往上返回。

也就是说,无论Route中包含多少个Predicate,包装后的 AsyncPredicate中 right Predicate中仅包含一个Predicate,其余的都是在left Predicate中(并且left的Predicate使用AndAsyncPredicate)。

3)Flux.next()

Flux.next()表示将 通量发出的第一项发射到新的单声道(Mono)中,即:仅会取第一个匹配的Route,第二个匹配的路由甚至都不会做Predicate谓词匹配。

在这里插入图片描述

大家可以按我的断点自己去调试一下看看效果。

4)校验路由

RoutePredicateHandlerMapping#validateRoute()方法负责校验谓词匹配到的路由,但是默认validateRoute()方法并没有实现;

在这里插入图片描述

开发人员可以在子类中重写它,比如:强制执行URL映射中表示的特定前提条件

5)返回结果

因为网关后面的微服务中没有/saint/nacos/路径的HTTP接口,所以网关层面选中gateway-nacos-service-route-fail之后,即使Filter执行链出错了,也不会继续返回重新找下一个Predicate谓词匹配的Route。
在这里插入图片描述

三、总结

按照application.yml文件中的定义route的顺序从上到下依次匹配(无论匹配到的Route的Filter是否可以通过、访问的地址是否有效,都不会继续往下匹配)

无论Route中包含多少个Predicate,包装后的 AsyncPredicate中 right Predicate中仅包含一个Predicate,其余的都是在left Predicate中;

  • left的Predicate使用AndAsyncPredicate,再对其中的Predicate用left、right递归拆分,直到left中仅有一个Predicate。
<think>好的,我现在需要回答用户关于如何在Spring Cloud Gateway中集成Alibaba Sentinel以实现流量控制和熔断的问题。首先,我需要回顾一下用户提供的参考资料,确保信息准确。 根据引用[1],Spring Cloud Gateway可以通过Sentinel进行网关限流,具体配置可以参考相关的文档。引用[2]和[3]提到了集成过程中可能遇到的问题,比如配置持久化和属性设置的问题,以及具体的整合步骤。 首先,用户需要搭建Sentinel控制台,这是管理规则的关键。然后,在Gateway项目中添加依赖,比如sentinel-spring-cloud-gateway-adapter。接下来配置路由和限流规则,这里需要注意application.yml中的配置是否正确,特别是关于dashboard和transport的部分。 另外,用户可能遇到的常见问题包括规则不生效,可能由于配置错误或属性如intervalSec设置不当,如引用[2]中提到的intervalSec被设置为1导致的问题。需要强调配置持久化到Nacos时的注意事项,确保重启后配置正确加载。 最后,生成相关问题时要覆盖配置步骤、优化、问题排查和应用场景,帮助用户全面理解。需要确保所有技术术语正确,比如熔断规则和流控规则的区别,以及如何通过注解或API进行自定义配置。</think>### Spring Cloud Gateway集成Alibaba Sentinel实现限流与熔断的实践 #### **1. 核心依赖配置** 在`pom.xml`中添加以下依赖: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency> ``` Sentinel的网关适配器是专门为Gateway设计的流量控制组件[^1]。 --- #### **2. Sentinel控制台部署** - **下载控制台**:从[官方仓库](https://github.com/alibaba/Sentinel/releases)获取Sentinel Dashboard的JAR包。 - **启动控制台**: ```bash java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -jar sentinel-dashboard.jar ``` 控制台默认账号密码为`sentinel/sentinel`[^3]。 --- #### **3. 网关服务配置** 在`application.yml`中配置Sentinel连接: ```yaml spring: cloud: sentinel: transport: dashboard: localhost:8080 # Sentinel控制台地址 port: 8719 # 客户端监控端口 eager: true # 立即初始化 scg: fallback: mode: response # 熔断响应模式 response-status: 429 # 触发限流时的HTTP状态码 response-body: "请求被限流" ``` 此配置确保网关启动时主动连接控制台并定义限流响应行为。 --- #### **4. 定义限流规则** 通过Sentinel控制台配置流控规则: - **资源名称**:对应Gateway路由ID(如`route_id`)。 - **阈值类型**:选择QPS或线程数。 - **阈值**:例如QPS=100表示每秒最多允许100次请求。 - **流控模式**:支持直接、关联、链路模式[^1]。 数学表达示例:若某接口需满足QPS不超过阈值$T$,则限流条件为: $$ \text{实际QPS} \leq T $$ --- #### **5. 熔断规则配置** 在控制台配置熔断策略: - **慢调用比例**:当请求响应时间超过阈值且比例达到设定值时触发熔断。 - **异常比例**:当异常请求比例超过阈值时触发。 - **最小请求数**:触发熔断的最小样本量。 熔断恢复条件可通过时间窗口参数控制,例如:若时间窗口$W=10s$,则熔断持续10秒后进入半开状态[^2]。 --- #### **6. 规则持久化(Nacos集成)** 为避免重启后规则丢失,将规则存储到Nacos: ```yaml spring: cloud: sentinel: datasource: ds: nacos: server-addr: localhost:8848 dataId: sentinel-gateway-rules groupId: DEFAULT_GROUP rule-type: gw-flow ``` 需确保`dataId`与Nacos中的配置一致,并验证`intervalSec`参数是否合理(避免值过小导致规则刷新异常)[^2]。 --- #### **7. 自定义异常处理** 通过实现`SentinelGatewayBlockExceptionHandler`接口,自定义限流/熔断响应: ```java @Component public class CustomBlockHandler implements SentinelGatewayBlockExceptionHandler { @Override public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable ex) { return ServerResponse.status(429) .body(BodyInserters.fromValue("{\"code\": 429, \"msg\": \"服务繁忙\"}")); } } ``` --- ### **常见问题排查** 1. **规则未生效**:检查控制台配置路由ID是否与Gateway定义一致。 2. **intervalSec异常**:确认持久化到Nacos的规则中`intervalSec`字段值合理(如60秒)。 3. **控制台无数据**:验证`spring.cloud.sentinel.transport.dashboard`配置正确,且防火墙未拦截8719端口。 ---
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃秃爱健身

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值