之前说过 Gateway 的路由配置,常用的有两种方式:
这两者之间因为配置文件的方式修改起来比较灵活,然后通过 Stream+Bus 的方式刷新路由配置,所以大家使用的比较多。
但是如果我们在网关层需要类似于 Canary Release(金丝雀发布,也称灰度发布)这样的能力的话,那么以上两种配置路由的方式就都显得太笨拙了。
矿井中的金丝雀17 世纪,英国矿井工人发现,金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯,金丝雀也会停止歌唱;而当瓦斯含量超过一定限度时,虽然鲁钝的人类毫无察觉,金丝雀却早已毒发身亡。当时在采矿设备相对简陋的条件下,工人们每次下井都会带上一只金丝雀作为 “瓦斯检测指标”,以便在危险状况下紧急撤离。
Spring Cloud Gateway 中虽然已经提供了关于权重的断言,我们在配置文件中可以直接这样配置
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: service1_prod
uri: <http://localhost:8081>
predicates:
- Path=/test
- Weight=service1, 90
- id: service1_canary
uri: <http://localhost:8082>
predicates:
- Path=/test
- Weight=service1, 10

以实现 Canary Release 的能力,但是每次发布都配置一遍未免太过麻烦了。
出于“懒”的本性,我们当然希望在发布脚本里能在运行时直接动态修改service1_prod、service1_canary的权重,这样我们就不用手动修改还提心吊胆的担心改错了。
这其实就是“动态路由”了。
Spring Cloud Gateway 在去年 6 月份发布了 2.0 第一个 release 版本,其实已经自带动态路由了, 但是官方文档并没有讲如何动态配置。
不过我们翻看 Spring Cloud Gateway 源码,会发现类 org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint 中提供了网关配置的 RESTful 接口,默认是没有启用的。
在配置类 org.springframework.cloud.gateway.config.GatewayAutoConfiguration 中配置了 GatewayControllerEndpoint
@Configuration
@ConditionalOnClass(Health.class)
protected static class GatewayActuatorConfiguration {
@Bean
@ConditionalOnEnabledEndpoint
public GatewayControllerEndpoint gatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List<GlobalFilter> globalFilters,
List<GatewayFilterFactory> GatewayFilters, RouteDefinitionWriter routeDefinitionWriter,
RouteLocator routeLocator) {
return new GatewayControllerEndpoint(routeDefinitionLocator, globalFilters, GatewayFilters, routeDefinitionWriter, routeLocator);
}
}
也就是说在存在org.springframework.boot.actuate.health.Health时启用,我们想用自带的接口就需要添加 actuator 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
并且还要将 actuator 的端点暴露出来
management:
endpoints:
web:
exposure:
include: "*"
然后我们就能通过自带的GatewayControllerEndpoint的 RESTful API 修改运行时的路由了