前言
经过前面的学习,我们已经知道 soul 网关会接收 http 请求,然后交给 divide 插件去处理。
正文
我们先从 Divide 插件的参数开始,主要的参数就 4 个。
public class DividePlugin extends AbstractSoulPlugin {
@Override
protected Mono<Void> doExecute(final ServerWebExchange exchange,
final SoulPluginChain chain,
final SelectorData selector,
final RuleData rule) {
// 省略代码,先看参数
}
}
- exchange
这个参数是 ServerWebExchange 的实例,里面主要是 http 请求的 ServerHttpRequest 和 ServerHttpResponse,以及当前 exchange 携带的属性。
- chain
这是一系列的插件,包括了 Divide 插件、Dubbo 插件等等。这些插件使用了责任链的模式,从头到尾去匹配请求,然后针对性的处理。
- selector
这个在之前的文章里也提到过很多次了,「选择器」主要是为了匹配请求的 url 而提供的前缀。另外,还会有对应的上游服务器的 IP 和端口等信息。
- rule
这个参数同样也在前面的文章多次提到,「规则」的主要作用是存储了请求的完整 url,并且可以针对这个 url 接口设置负载均衡策略。
弄清楚了参数的意义,我们继续看程序是怎么去处理的。
结合之前的文章,我们知道这个 Divide 插件就是从「选择器」里面拿到上游服务器的列表,然后借助「规则」里面的负载均衡策略去选出一个合适的服务器,在此基础上拼接上「规则」的 url,最后交给 WebClientPlugin 插件去发起 http 请求并且返回给调用方。
我们先看是怎么拿到上游服务器列表数据的。
public final class UpstreamCacheManager {
private static final Map<String, List<DivideUpstream>> UPSTREAM_MAP_TEMP = Maps.newConcurrentMap();
public List<DivideUpstream> findUpstreamListBySelectorId(final String selectorId) {
return UPSTREAM_MAP_TEMP.get(selectorId);
}
}
从代码里可以看到这个过程就是简单的从内存里面根据「选择器」ID 去 Map 里取值,这个 Map 会在 soul 网关启动完成之后通过数据同步模块赋值,在之前的数据同步相关的文章已经介绍过了。
拿到了上游的服务器之后,就是根据「规则」里面的负载均衡策略去选择服务器了,目前提供了 3 种负载均衡策略。
public class LoadBalanceUtils {
public static DivideUpstream selector(final List<DivideUpstream> upstreamList, final String algorithm, final String ip) {
LoadBalance loadBalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getJoin(algorithm);
return loadBalance.select(upstreamList, ip);
}
}
hash 就是使用 hash 函数计算请求的 ip 地址;random 就是根据上游服务器列表计算出一个随机数去选择。
最后的 roundRobin 是轮训调度的方式,就比如第一次是列表里的第一个服务器,第二次就是列表的第二个服务器,挨个轮下去。
最后就是 url 的拼接过程,然后存粗到 exchange 里面,让之后的插件去执行请求并返回给调用端。
// 获取到服务器地址,存储到当前的 exchange
String domain = buildDomain(divideUpstream);
String realURL = buildRealURL(domain, soulContext, exchange);
exchange.getAttributes().put(Constants.HTTP_URL, realURL);
// set the http timeout
exchange.getAttributes().put(Constants.HTTP_TIME_OUT, ruleHandle.getTimeout());
exchange.getAttributes().put(Constants.HTTP_RETRY, ruleHandle.getRetry());
return chain.execute(exchange);
总结
Divide 插件是对 http 请求的正向代理,利用了责任链的模式,专门去处理 http 的请求。
主要的内容就是对「选择器」和「规则」的匹配和处理,目的是构建出一个完整的符合预期规则的 http 请求 url,然后交给下一个插件去处理 http 的返回值。