负载均衡系列专题

01-负载均衡基础知识

02-一致性 hash 原理

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

04-负载均衡算法 java 实现

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

源码

核心接口定义

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
public interface ILoadBalance { /** * 选择下一个节点 * * 返回下标 * @param context 上下文 * @return 结果 * @since 0.0.1 */ IServer select(final ILoadBalanceContext context); }

1. 随机策略

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LoadBalanceRandom extends AbstractLoadBalance{ public LoadBalanceRandom(List<IServer> servers) { super(servers); } @Override protected IServer doSelect(ILoadBalanceContext context) { Random random = ThreadLocalRandom.current(); int nextIndex = random.nextInt(servers.size()); return servers.get(nextIndex); } }

2. 轮训

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class LoadBalanceRoundRobbin extends AbstractLoadBalance { /** * 位移指针 * @since 0.0.1 */ private final AtomicLong indexHolder = new AtomicLong(); public LoadBalanceRoundRobbin(List<IServer> servers) { super(servers); } @Override protected IServer doSelect(ILoadBalanceContext context) { long index = indexHolder.getAndIncrement(); int actual = (int) (index % servers.size()); return servers.get(actual); } }

3. 有权重的轮训

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

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class LoadBalanceWeightRoundRobbin extends AbstractLoadBalance { /** * 位移指针 * @since 0.0.1 */ private final AtomicLong indexHolder = new AtomicLong(); /** * 处理后的列表 * @since 0.0.1 */ private final List<IServer> actualList = new ArrayList<>(); public LoadBalanceWeightRoundRobbin(List<IServer> 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<IServer> serverList) { //1. 过滤掉权重为 0 的机器 List<IServer> notZeroServers = CollectionUtil.filterList(serverList, new IFilter<IServer>() { @Override public boolean filter(IServer iServer) { return iServer.weight() <= 0; } }); //2. 获取权重列表 List<Integer> weightList = CollectionUtil.toList(notZeroServers, new IHandler<IServer, Integer>() { @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. 普通哈希

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class LoadBalanceCommonHash extends AbstractLoadBalanceHash { public LoadBalanceCommonHash(List<IServer> 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. 一致性哈希

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

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class LoadBalanceConsistentHash extends AbstractLoadBalanceHash { /** * 一致性 hash 实现 * @since 0.0.1 */ private final IConsistentHashing<IServer> consistentHashing; public LoadBalanceConsistentHash(List<IServer> servers, IHash hash) { super(servers, hash); this.consistentHashing = ConsistentHashingBs .<IServer>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