负载均衡系列专题

01-负载均衡基础知识

02-一致性 hash 原理

03-一致性哈希算法 java 实现

04-负载均衡算法 java 实现

本节我们来看一下如何实现一负载均衡框架。

源码

核心接口定义

public interface ILoadBalance {

    /**
     * 选择下一个节点
     *
     * 返回下标
     * @param context 上下文
     * @return 结果
     * @since 0.0.1
     */
    IServer select(final ILoadBalanceContext context);

}

1. 随机策略

public class LoadBalanceRandom extends AbstractLoadBalance{

    public LoadBalanceRandom(List servers) {
        super(servers);
    }

    @Override
    protected IServer doSelect(ILoadBalanceContext context) {
        Random random = ThreadLocalRandom.current();
        int nextIndex = random.nextInt(servers.size());
        return servers.get(nextIndex);
    }

}

2. 轮训

public class LoadBalanceRoundRobbin extends AbstractLoadBalance {

    /**
     * 位移指针
     * @since 0.0.1
     */
    private final AtomicLong indexHolder = new AtomicLong();

    public LoadBalanceRoundRobbin(List servers) {
        super(servers);
    }

    @Override
    protected IServer doSelect(ILoadBalanceContext context) {
        long index = indexHolder.getAndIncrement();
        int actual = (int) (index % servers.size());
        return servers.get(actual);
    }

}

3. 有权重的轮训

这个需要对数据进行初始化处理,计算数组的最大公约数。

public class LoadBalanceWeightRoundRobbin extends AbstractLoadBalance {

    /**
     * 位移指针
     * @since 0.0.1
     */
    private final AtomicLong indexHolder = new AtomicLong();

    /**
     * 处理后的列表
     * @since 0.0.1
     */
    private final List actualList = new ArrayList<>();

    public LoadBalanceWeightRoundRobbin(List servers) {
        super(servers);

        // 初始化真实列表
        this.init(servers);
    }

    @Override
    protected IServer doSelect(ILoadBalanceContext context) {
        long index = indexHolder.getAndIncrement();

        // 基于真实的列表构建
        int actual = (int) (index % actualList.size());
        return actualList.get(actual);
    }

    /**
     * 初始化
     * @param serverList 服务列表
     * @since 0.0.1
     */
    private void init(final List serverList) {
        //1. 过滤掉权重为 0 的机器
        List notZeroServers = CollectionUtil.filterList(serverList, new IFilter() {
            @Override
            public boolean filter(IServer iServer) {
                return iServer.weight() <= 0;
            }
        });

        //2. 获取权重列表
        List weightList = CollectionUtil.toList(notZeroServers, new IHandler() {
            @Override
            public Integer handle(IServer iServer) {
                return iServer.weight();
            }
        });

        //3. 获取最大的权重
        int maxDivisor = MathUtil.ngcd(weightList);

        //4. 重新计算构建基于权重的列表
        for(IServer server : notZeroServers) {
            int weight = server.weight();

            int times = weight / maxDivisor;
            for(int i = 0; i < times; i++) {
                actualList.add(server);
            }
        }
    }

}

4. 普通哈希

public class LoadBalanceCommonHash extends AbstractLoadBalanceHash {

    public LoadBalanceCommonHash(List servers, IHash hash) {
        super(servers, hash);
    }

    @Override
    protected IServer doSelect(ILoadBalanceContext context) {
        final String hashKey = context.hashKey();

        int hashCode = Math.abs(hash.hash(hashKey));
        int index = servers.size() % hashCode;
        return servers.get(index);
    }

}

5. 一致性哈希

这里将我们前面实现的一致性哈希,与负载均衡结合。

public class LoadBalanceConsistentHash extends AbstractLoadBalanceHash {

    /**
     * 一致性 hash 实现
     * @since 0.0.1
     */
    private final IConsistentHashing consistentHashing;

    public LoadBalanceConsistentHash(List servers, IHash hash) {
        super(servers, hash);

        this.consistentHashing = ConsistentHashingBs
                .newInstance()
                .hash(hash)
                .nodes(servers)
                .build();
    }

    @Override
    protected IServer doSelect(ILoadBalanceContext context) {
        final String hashKey = context.hashKey();

        return consistentHashing.get(hashKey);
    }

}

后期 Road-Map

还有基于系统最小压力,最小连接的实现,暂时没有放在这里。

后续将加入对应的实现。

完整开源代码

其他还有一些引导类等辅助工具。

完整代码参见 load-balance

公众号