- 关于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