Spring Cloud Gateway(七):路由谓词工厂WeightRoutePredicateFactory
本文基于 spring cloud gateway 2.0.1 接上文
5、基于路由权重(weigth)的谓词工厂
Spring Cloud Gateway 提供了基于路由权重的断言工厂,配置时指定分组和权重值 即可。WeightRoutePredicateFactory 实现了路由权重的功能,按照路由权重选择 同一个分组中的路由。
spring:
cloud:
gateway:
locator:
enabled: true
routes:
-id: weight_route1
uri: http://www.baidu1.com
order: 6000
predicates:
-Weight= group3, 1
-Path=/ weight/**
filters:
-StripPrefix= 2
-id: weight_route2
uri: http://www.baidu2.com
order: 6000
predicates:
-Path=/ weight/**
-Weight= group3, 9
filters:
-StripPrefix=1
如上配置了两个对于 / weight/** 路径转发的路由定义,这两个路由是同一个权重分组,且 weight_ route1 权重为 1, weight_ route2 权重为9。 对于10个访问/ weight/** 路径的请求来说,将会有9个路由到 weight_ route2,1个路由到 weight_ route1。
5.1、WeightRoutePredicateFactory 权重算法实现过程
weight_ route1: group3, 1
weight_ route2: group3, 9
实现过程为:
1)构造 weights(group3)数组:weights=[ 1, 9]
2)normalize: weights= weights/ sum( weights)=[ 0. 1, 0. 9]
3)计算区间范围: ranges= weights. collect( 0,( s, w)-> s+ w)=[ 0, 0. 1, 1. 0]
4)生成 随机数: r= random()
5)搜索随机数所在的区间: i= integer s. t. r>= ranges[ i]&& r< ranges[ i+ 1]
6)选择相应的路由: routes[ i]
网关应用服务在启动时会发布 WeightDefinedEvent,在 WeightCalculatorWebFilter 过滤器中定义了该时间监听器,当接收到时间 WeightDefinedEvent 时,会自动添加 WeightConfig 到权重配置中。请求在经过 WeightCalculatorWebFilter 时会 生成 一个 随机数, 根据随机数所在的区间选择对应分组的路由。
// WeightRoutePredicateFactory.java
@Override
public Predicate<ServerWebExchange> apply(Config config) {
List<IpSubnetFilterRule> sources = convert(config.sources);
return exchange -> {
InetSocketAddress remoteAddress = config.remoteAddressResolver.resolve(exchange);
if (remoteAddress != null) {
String hostAddress = remoteAddress.getAddress().getHostAddress();
String host = exchange.getRequest().getURI().getHost();
if (log.isDebugEnabled() && !hostAddress.equals(host)) {
log.debug("Remote addresses didn't match " + hostAddress + " != " + host);
}
for (IpSubnetFilterRule source : sources) {
if (source.matches(remoteAddress)) {
return true;
}
}
}
return false;
};
}
当应用到配置的路由断言 WeightRoutePredicate 时,会根据 ServerWebExchange 中的 WEIGHT_ ATTR 值,判断当前的 routeId 与对应分组的 routeId 是否一致。