Soul 源码解析(一):Soul网关里的负载均衡策略

负载均衡

类结构

  1. 我们定义了一个LoadBalance接口,接口里面定义了一个select方法,用来选择网关要将请求转发到哪个服务器;
  2. 我们定义了一个AbstractLoadBalance抽象类,抽象类主要实现了select方法,以及定义了一个doSelect方法(实现类通过重写doSelect完成各种负载均衡策略);
  3. 定义了三个不同策略的负载均衡策略来实现AbstractLoadBalance抽象类的doSelect方法,从而实现负载均衡的处理;
    在这里插入图片描述

Soul源码的负载均衡算法的目录位置如图所示,进入工程的下面目录即可找到Soul的负载均衡源码;
在这里插入图片描述

Soul网关支持的负载均衡策略

  1. Hash算法
  2. 随机 & 加权随机
  3. 轮询

下面我们一起看下随机&加权随机负载均衡的实现过程:

随机&加权随机

随机

我们可以看到,在实现类里面的random里面使用RANDOM.nextInt(upstreamList.size())来挑选一个服务器地址进行转发;

加权随机

在使用加权随机负载均衡时,我们会在Soul 的Admin控制台配置各个服务器的权重;
处理过程:

  1. 计算所有服务器的总权重;
  2. 判断所有服务器的请求是否一致,如果都一致,直接采用随机策略;
  3. 我们通过随机函数(RANDOM.nextInt(totalWeight))生成随机偏移量,参数为总的权重值;然后我们通过判断偏移量offset落在哪一个服务器权重区间来判断选择哪一个服务器进行请求转发;
package org.dromara.soul.plugin.divide.balance.spi;

import org.dromara.soul.common.dto.convert.DivideUpstream;
import org.dromara.soul.spi.Join;

import java.util.List;
import java.util.Random;

/**
 * random algorithm impl.
 *
 * @author xiaoyu(Myth)
 */
@Join
public class RandomLoadBalance extends AbstractLoadBalance {

    private static final Random RANDOM = new Random();

    @Override
    public DivideUpstream doSelect(final List<DivideUpstream> upstreamList, final String ip) {
        int totalWeight = calculateTotalWeight(upstreamList);
        boolean sameWeight = isAllUpStreamSameWeight(upstreamList);
        if (totalWeight > 0 && !sameWeight) {
            return random(totalWeight, upstreamList);
        }
        // If the weights are the same or the weights are 0 then random
        return random(upstreamList);
    }

    private boolean isAllUpStreamSameWeight(final List<DivideUpstream> upstreamList) {
        boolean sameWeight = true;
        int length = upstreamList.size();
        for (int i = 0; i < length; i++) {
            int weight = getWeight(upstreamList.get(i));
            if (i > 0 && weight != getWeight(upstreamList.get(i - 1))) {
                // Calculate whether the weight of ownership is the same
                sameWeight = false;
                break;
            }
        }
        return sameWeight;
    }

    private int calculateTotalWeight(final List<DivideUpstream> upstreamList) {
        // total weight
        int totalWeight = 0;
        for (DivideUpstream divideUpstream : upstreamList) {
            int weight = getWeight(divideUpstream);
            // Cumulative total weight
            totalWeight += weight;
        }
        return totalWeight;
    }

    private DivideUpstream random(final int totalWeight, final List<DivideUpstream> upstreamList) {
        // If the weights are not the same and the weights are greater than 0, then random by the total number of weights
        int offset = RANDOM.nextInt(totalWeight);
        // Determine which segment the random value falls on
        for (DivideUpstream divideUpstream : upstreamList) {
            offset -= getWeight(divideUpstream);
            if (offset < 0) {
                return divideUpstream;
            }
        }
        return upstreamList.get(0);
    }

    private DivideUpstream random(final List<DivideUpstream> upstreamList) {
        return upstreamList.get(RANDOM.nextInt(upstreamList.size()));
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35115942/article/details/112727492