Soul网关源码探秘《八》 - 负载均衡初探

前文分析 DividePlugin 插件时发现 Soul 网关的负载均衡策略有三种,分别为 Random、Hash、RoundRobin。今天做一个初步研究。

准备工作

依次运行soul-adminsoul-bootstrap项目。

之后分别以 8188,8189,8190 启动三个soul-examples-http项目。

soul-admin的配置中将三个项目的权重进行设置。
权重进行设置


源码分析

负载均衡的类图比较清晰:
负载均衡的类图
其中 LoadBalanceSPI 接口。AbstractLoadBalance是抽象类,实现了模版方法select,并定义了一个抽象方法doSelect供各子类去实现。

Random

设置负载均衡策略为 random,在以下代码中打上断点。

public class DividePlugin extends AbstractSoulPlugin {

    @Override
    protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
        // ...
        /** 从规则中设置的负载均衡算法来计算真实去转发的服务 */
        DivideUpstream divideUpstream = LoadBalanceUtils.selector(upstreamList, ruleHandle.getLoadBalance(), ip);
        // ...
    }
}

前进到AbstractLoadBalance的模版方法select

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);
    }

如果可选服务信息为空则直接返回,若只有一个可选服务,则直接返回这一条即可。其余情况进入所选负载均衡规则的子类进行后续处理。

接着进入RandomLoadBalance类的实现方法doSelect逻辑。

public DivideUpstream doSelect(final List<DivideUpstream> upstreamList, final String ip) {
        // 1. 根据总服务列表计算一个总的权重,第一次请求就是把三个项目权重相加,为401
        int totalWeight = calculateTotalWeight(upstreamList);
        // 2. 判断三个项目中的权重是否一样
        boolean sameWeight = isAllUpStreamSameWeight(upstreamList);
        // 3. 三个项目中的权重一样与否使用的是不同的 random 算法
        if (totalWeight > 0 && !sameWeight) {
            return random(totalWeight, upstreamList);
        }
        // If the weights are the same or the weights are 0 then random
        return random(upstreamList);
    }
    
    //   4. 三个项目中的权重一样时使用的 random 算法
private DivideUpstream random(final List<DivideUpstream> upstreamList) {
        // 5. 权重一样时,从服务列表里随机按照 index 去一个数据使用
        return upstreamList.get(RANDOM.nextInt(upstreamList.size()));
    }
    
    // 6. 三个项目中的权重不一样时使用的 random 算法
private DivideUpstream random(final int totalWeight, final List<DivideUpstream> upstreamList) {
        // 7. 根据总权重随机一个偏移量
        int offset = RANDOM.nextInt(totalWeight);
        // 8. 循环服务列表,用偏移量去减去各自权重,最终取第一个偏移量为负值的服务
        for (DivideUpstream divideUpstream : upstreamList) {
            offset -= getWeight(divideUpstream);
            if (offset < 0) {
                return divideUpstream;
            }
        }
        return upstreamList.get(0);
    }

先根据服务列表各自的权重生成一个总的权重。之后如果各个服务的权重是一样的,会随机在列表里选一个记录返回;若各个服务权重不一样,则会根据总权重随机一个偏移量,之后循环服务列表,每一次将偏移量和服务各自的权重相减。返回第一个使偏移量为负的服务。这种方式也能保证权重大的服务会更大概率被选中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rughru

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值