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插件和负载均衡方面进行了分析,同时也介绍了有几种负载均衡的方式。

おすすめ

転載: blog.csdn.net/zfy163520/article/details/113403523