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/tech/aiops/1296.html

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

相关推荐

发表回复

登录后才能评论