Weight 路由断言工厂需要两个参数:组(group)和权重(int 类型),注意,权重按组计算。语法如下:
Weight=组,权重
例如,为 https://weighthigh.org 地址创建两个路由,都放在 group1 分组下,如下:
spring: cloud: gateway: routes: - id: weight_high uri: https://weighthigh.org predicates: - Weight=group1, 8 - id: weight_low uri: https://weightlow.org predicates: - Weight=group1, 2
该路由将把 ~80% 的流量转发到 weighthigh.org,把 ~20% 的流量转发到 weighlow.org。
为了验证权重断言,我们需要启动两个订单服务,如下图:
上图中,两个订单服务的端口分别为 8081 和 18081。那么,如何在 IDEA 中启动两个订单服务呢?首先,修改一下 bootstrap.yml 配置文件,支持端口通过 JVM 参数指定,如下:
server: port: ${port:8081}
然后,右键“OrderApplication”选择“Copy Configuration...”复制一个运行配置,如下图:
然后,再次右键新复制的配置,点击“Edit Configuration...”编辑运行配置,添加 VM 参数(端口)等信息,如下图:
将“Gateway 搭建网关服务”项目的配置文件 bootstrap.yml 内容使用如下配置替换:
server: # 网关端口 port: 9000 spring: application: # 服务名称 name: gateway-demo01 cloud: # nacos nacos: discovery: server-addr: localhost:8848 username: nacos password: nacos group: DEFAULT_GROUP # 网关路由配置 gateway: # 网关路由配置 routes: # 路由id,自定义,只要唯一集合 - id: service-order1 # 路由的目标地址,lb 就是负载均衡,后面跟服务名,需要集成 nacos 等服务注册中心 uri: http://localhost:18081 # 路由断言,也就是判断请求是否符合路由规则的条件 predicates: # Weight断言:根据权重转发请求 - Weight=group1,2 # 路由id,自定义,只要唯一集合 - id: service-order2 # 路由的目标地址,lb 就是负载均衡,后面跟服务名 # 需要集成 nacos 等服务注册中心 lb://service-order uri: http://localhost:8081 # 路由断言,也就是判断请求是否符合路由规则的条件 predicates: # Weight断言:根据权重转发请求 - Weight=group1,8
上面配置中配置了两个路由,分别是 service-order1 和 service-order2,其中 80% 的请求将发送给 service-order2,20% 的请求将发送给 service-order1。
此时,我们通过 Postman 工具向网关发送 10 次请求,如下图:
从上图可知,有两个请求发送到了 OrderApplication2 服务,有 8 个请求发送到 OrderApplication 服务。
下面是 Weight 路由断言工厂源码:
package org.springframework.cloud.gateway.handler.predicate; // ... public class WeightRoutePredicateFactory extends AbstractRoutePredicateFactory<WeightConfig> implements ApplicationEventPublisherAware { private static final Log log = LogFactory.getLog(WeightRoutePredicateFactory.class); public static final String GROUP_KEY = WeightConfig.CONFIG_PREFIX + ".group"; public static final String WEIGHT_KEY = WeightConfig.CONFIG_PREFIX + ".weight"; private ApplicationEventPublisher publisher; public WeightRoutePredicateFactory() { super(WeightConfig.class); } @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; } @Override public List<String> shortcutFieldOrder() { return Arrays.asList(GROUP_KEY, WEIGHT_KEY); } @Override public String shortcutFieldPrefix() { return WeightConfig.CONFIG_PREFIX; } @Override public void beforeApply(WeightConfig config) { if (publisher != null) { publisher.publishEvent(new WeightDefinedEvent(this, config)); } } @Override public Predicate<ServerWebExchange> apply(WeightConfig config) { return exchange -> { Map<String, String> weights = exchange.getAttributeOrDefault(WEIGHT_ATTR, Collections.emptyMap()); String routeId = exchange.getAttribute(GATEWAY_PREDICATE_ROUTE_ATTR); // 所有计算和与随机数的比较都在 WeightCalculatorWebFilter 中进行 // all calculations and comparison against random num happened in // WeightCalculatorWebFilter String group = config.getGroup(); if (weights.containsKey(group)) { String chosenRoute = weights.get(group); if (log.isTraceEnabled()) { log.trace("in group weight: "+ group + ", current route: " + routeId +", chosen route: " + chosenRoute); } return routeId.equals(chosenRoute); } return false; }; } }