Soul API网关解析之divide插件(上)详解程序员

  • 关于divide插件
  • divide插件负载均衡实现
  • divide插件ip端口探活
  • 总结

关于divide插件

divide插件是进行http类型请求处理的插件。所有http类型的请求都是经过divide插件进行负载均衡运行的。

在前面文章中有介绍SoulWebHandler, 这里重申一下,当有相应的http请求时,在SoulWebHandler中会处理请求。同时也会根据不同的负载均衡算法,进行相应的转发请求。当然在soul-admin端,也会有相应的任务来检测缓存中是否有下线。

divide插件负载均衡

  • RandomLoadBalance:性能高,均衡性差一些
  • RoundRobinLoadBalance:性能相对于随机差一些,但均衡性好
  • 一致性Hash(基于MD5):由HashLoadBalance实现

配置路径:org.dromara.soul.plugin.divide.balance.spi.LoadBalance

配置内容:

hash=org.dromara.soul.plugin.divide.balance.spi.HashLoadBalance 
random=org.dromara.soul.plugin.divide.balance.spi.RandomLoadBalance 
roundRobin=org.dromara.soul.plugin.divide.balance.spi.RoundRobinLoadBalance 

负载均衡调用处理位置:

public class DividePlugin extends AbstractSoulPlugin {
 
@Override 
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
 
final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT); 
assert soulContext != null; 
final DivideRuleHandle ruleHandle = GsonUtils.getInstance().fromJson(rule.getHandle(), DivideRuleHandle.class); 
final List<DivideUpstream> upstreamList = UpstreamCacheManager.getInstance().findUpstreamListBySelectorId(selector.getId()); 
if (CollectionUtils.isEmpty(upstreamList)) {
 
log.error("divide upstream configuration error: {}", rule.toString()); 
Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null); 
return WebFluxResultUtils.result(exchange, error); 
} 
final String ip = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress(); 
// 根据传入的ruleHandler来选择相应的loadbalance,默认是hashLoadBalance 
DivideUpstream divideUpstream = LoadBalanceUtils.selector(upstreamList, ruleHandle.getLoadBalance(), ip); 
if (Objects.isNull(divideUpstream)) {
 
log.error("divide has no upstream"); 
Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null); 
return WebFluxResultUtils.result(exchange, error); 
} 
// set the http url 
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); 
} 
} 

在DividePlugin 类中的doExecute方法中根据相应的规则来获取相应的规则处理器,然后再根据所获得的规则处理器来获取相应的负载均衡策略。
这里可以看下LoadBalanceUtils.selector(upstreamList, ruleHandle.getLoadBalance(), ip)的调用,如下:

public class LoadBalanceUtils {
 
public static DivideUpstream selector(final List<DivideUpstream> upstreamList, final String algorithm, final String ip) {
 
// 获取loadBalance 
LoadBalance loadBalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getJoin(algorithm); 
// 重点 
return loadBalance.select(upstreamList, ip); 
} 

}我们继续看看loadBalance.select(upstreamList, ip)调用:

public abstract class AbstractLoadBalance implements LoadBalance {
 
/** 
* Do select divide upstream. 
* 
* @param upstreamList the upstream list 
* @param ip           the ip 
* @return the divide upstream 
*/ 
protected abstract DivideUpstream doSelect(List<DivideUpstream> upstreamList, String ip); 
@Override 
public DivideUpstream select(final List<DivideUpstream> upstreamList, final String ip) {
 
if (CollectionUtils.isEmpty(upstreamList)) {
 
return null; 
} 
if (upstreamList.size() == 1) {
 
return upstreamList.get(0); 
} 
return doSelect(upstreamList, ip); 
} 
// ........ 
} 

接着看看doSelect方法他的具体实现,这里就是我们前面所提到的几种负载均衡方式,如图:
图片

在AbstractLoadBalance类中有calculateWarmupWeight方法根据uptime、 warmup,、weight这三个参数来计算出路由权重。

private int getWeight(final long timestamp, final int warmup, final int weight) {
 
if (weight > 0 && timestamp > 0) {
 
int uptime = (int) (System.currentTimeMillis() - timestamp); 
if (uptime > 0 && uptime < warmup) {
 
return calculateWarmupWeight(uptime, warmup, weight); 
} 
} 
return weight; 
} 
private int calculateWarmupWeight(final int uptime, final int warmup, final int weight) {
 
int ww = (int) ((float) uptime / ((float) warmup / (float) weight)); 
return ww < 1 ? 1 : (ww > weight ? weight : ww); 
} 

总结

本篇简单的分析了关于divide插件和负载均衡方面进行了分析,同时也介绍了有几种负载均衡的方式。

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/1296.html

(0)
上一篇 2021年7月15日
下一篇 2021年7月15日

相关推荐

发表回复

登录后才能评论