1. 程式人生 > 其它 >Soul API閘道器解析之divide外掛(上)

Soul API閘道器解析之divide外掛(上)

技術標籤:閘道器java

  • 關於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外掛和負載均衡方面進行了分析,同時也介紹了有幾種負載均衡的方式。