Soul API閘道器解析之divide外掛(上)
阿新 • • 發佈:2021-01-30
- 關於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外掛和負載均衡方面進行了分析,同時也介紹了有幾種負載均衡的方式。