SpringCloud Gateway自定义过滤器实现IP Hash路由

现状

公司转型微服务架构,将之前机器上所有已部署微服务拆分集群部署。微服务地址采用资源管理平台统一管理维护,包括微服务IP、集群数据等,未采用服务注册与发现组件。

需求

1、从资源管理平台获取服务器IP地址等相关参数;
2、相同源IP转发到相同服务器,采用IP Hash方式;

实现

SpringCloud Gateway支持自定义过滤器,通过继承RouteToRequestUrlFilter类来实现IP Hash。SpringCloud Gateway过滤器分为两类,Gateway Filter和Global Filter,前者是针对匹配命中的过滤,有两种方式来实现,实现GatewayFilter接口、继承AbstractGatewayFilterFactory类,后者是针对全局路由的过滤器,可以采用添加@Component注解的方式来注册。SpringCloud Gateway的全局过滤器如下图所示:

我们需要做的就是实现一个自定义的全局过滤器CustomRouteToRequestUrlFilter,在该过滤器中设置IP Hash后的真实URL地址。代码如下:

CustomRouteToRequestUrlFilter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component 
public class CustomRouteToRequestUrlFilter extends RouteToRequestUrlFilter {
private List<String> mUrlList = new ArrayList<String>() {
{
add("http://10.0.0.1");
add("http://10.0.0.2");
add("http://10.0.0.3");
}
};
@Override
public int getOrder() {
return 10001;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String address = request.getRemoteAddress().getAddress().getHostAddress();
int num = Math.abs(address.hashCode()) % mUrlList.size();
URI mergedUrl = URI.create(mUrlList.get(num));
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, mergedUrl);
return chain.filter(exchange);
}
}

以上代码可以进行优化,通过处理”x-forward-for”以获取真实IP地址。此处暂略。
WebFlux通过ServerWebExchange类来处理Http Request和Http Response。首先取得IP地址,然后将IP地址做Hash得到一个整型,再根据服务器数量求余,最后得到所选择的服务器。

以上代码需要注意的地方在于,需要设置Order为10001,大于RouteToRequestUrlFilter的返回值(10000),这样才能将优先级置于RouteToRequestUrlFilter之下。