Skip to content

Commit ac1da1d

Browse files
committed
更新负载均衡示例
1 parent d153ca7 commit ac1da1d

File tree

6 files changed

+237
-274
lines changed

6 files changed

+237
-274
lines changed

codes/java-distributed/java-load-balance/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55

66
<groupId>io.github.dunwu.javatech</groupId>
7-
<artifactId>java-distributed-load-balance</artifactId>
7+
<artifactId>java-load-balance</artifactId>
88
<version>1.0.0</version>
99
<packaging>jar</packaging>
1010
<name>${project.artifactId}</name>

codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/ConsistentHashLoadBalance.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,42 @@ public class ConsistentHashLoadBalance<N extends Node> extends BaseLoadBalance<N
1616
@SuppressWarnings("unchecked")
1717
@Override
1818
protected N doSelect(List<N> nodes, String ip) {
19+
// 分片数,这里设为节点数的 4 倍
20+
Integer replicaNum = nodes.size() * 4;
1921
// 获取 nodes 原始的 hashcode
2022
int identityHashCode = System.identityHashCode(nodes);
23+
24+
// 如果 nodes 是一个新的 List 对象,意味着节点数量发生了变化
25+
// 此时 selector.identityHashCode != identityHashCode 条件成立
2126
ConsistentHashSelector<N> selector = (ConsistentHashSelector<N>) selectors.get(ip);
2227
if (selector == null || selector.identityHashCode != identityHashCode) {
23-
selectors.put(ip, new ConsistentHashSelector<>(nodes, identityHashCode, 1000));
28+
// 创建新的 ConsistentHashSelector
29+
selectors.put(ip, new ConsistentHashSelector<>(nodes, identityHashCode, replicaNum));
2430
selector = (ConsistentHashSelector<N>) selectors.get(ip);
2531
}
32+
// 调用 ConsistentHashSelector 的 select 方法选择 Node
2633
return selector.select(ip);
2734
}
2835

2936
/**
30-
* @param <N>
37+
* 一致性哈希选择器
3138
*/
3239
private static final class ConsistentHashSelector<N extends Node> {
3340

3441
/**
35-
* 使用 TreeMap 存储 Node 虚拟节点
42+
* 存储虚拟节点
3643
*/
3744
private final TreeMap<Long, N> virtualNodes;
3845

3946
private final int identityHashCode;
4047

48+
/**
49+
* 构造器
50+
*
51+
* @param nodes 节点列表
52+
* @param identityHashCode hashcode
53+
* @param replicaNum 分片数
54+
*/
4155
ConsistentHashSelector(List<N> nodes, int identityHashCode, Integer replicaNum) {
4256
this.virtualNodes = new TreeMap<>();
4357
this.identityHashCode = identityHashCode;
@@ -64,15 +78,22 @@ private static final class ConsistentHashSelector<N extends Node> {
6478
}
6579

6680
public N select(String key) {
81+
// 对参数 key 进行 md5 运算
6782
byte[] digest = md5(key);
83+
// 取 digest 数组的前四个字节进行 hash 运算,再将 hash 值传给 selectForKey 方法,
84+
// 寻找合适的 Node
6885
return selectForKey(hash(digest, 0));
6986
}
7087

7188
private N selectForKey(long hash) {
89+
// 查找第一个大于或等于当前 hash 的节点
7290
Map.Entry<Long, N> entry = virtualNodes.ceilingEntry(hash);
91+
// 如果 hash 大于 Node 在哈希环上最大的位置,此时 entry = null,
92+
// 需要将 TreeMap 的头节点赋值给 entry
7393
if (entry == null) {
7494
entry = virtualNodes.firstEntry();
7595
}
96+
// 返回 Node
7697
return entry.getValue();
7798
}
7899

codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalanceDemo.java

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,56 @@
11
package io.github.dunwu.javatech;
22

3-
import cn.hutool.core.util.StrUtil;
4-
53
import java.util.*;
64

75
/**
6+
* 负载均衡算法测试例
7+
*
88
* @author peng.zhang
99
* @date 2021/1/19
1010
*/
1111
public class LoadBalanceDemo {
1212

1313
private static final Random random = new Random();
1414

15+
public static String randomIpv4() {
16+
int[][] range = { { 607649792, 608174079 }, // 36.56.0.0-36.63.255.255
17+
{ 1038614528, 1039007743 }, // 61.232.0.0-61.237.255.255
18+
{ 1783627776, 1784676351 }, // 106.80.0.0-106.95.255.255
19+
{ 2035023872, 2035154943 }, // 121.76.0.0-121.77.255.255
20+
{ 2078801920, 2079064063 }, // 123.232.0.0-123.235.255.255
21+
{ -1950089216, -1948778497 }, // 139.196.0.0-139.215.255.255
22+
{ -1425539072, -1425014785 }, // 171.8.0.0-171.15.255.255
23+
{ -1236271104, -1235419137 }, // 182.80.0.0-182.92.255.255
24+
{ -770113536, -768606209 }, // 210.25.0.0-210.47.255.255
25+
{ -569376768, -564133889 }, // 222.16.0.0-222.95.255.255
26+
};
27+
28+
Random rdint = new Random();
29+
int index = rdint.nextInt(10);
30+
String ip = num2ip(range[index][0]
31+
+ new Random().nextInt(range[index][1] - range[index][0]));
32+
return ip;
33+
}
34+
35+
private static String num2ip(final int ip) {
36+
int[] b = new int[4];
37+
String result = "";
38+
b[0] = (ip >> 24) & 0xff;
39+
b[1] = ((ip >> 16) & 0xff);
40+
b[2] = ((ip >> 8) & 0xff);
41+
b[3] = (ip & 0xff);
42+
result = Integer.toString(b[0]) + "." + Integer.toString(b[1]) + "."
43+
+ Integer.toString(b[2]) + "." + Integer.toString(b[3]);
44+
return result;
45+
}
46+
1547
/**
16-
* 生成 10 个不一样的 IP 地址
48+
* 生成 num 个随机 IP 地址
1749
*/
18-
private static List<String> init10IpList() {
50+
private static List<String> initRandomIpList(int num) {
1951
List<String> list = new ArrayList<>();
20-
for (int i = 1; i <= 10; i++) {
21-
list.add("127.0.0." + i);
52+
for (int i = 1; i <= num; i++) {
53+
list.add(randomIpv4());
2254
}
2355
return list;
2456
}
@@ -49,15 +81,16 @@ private static List<Node> initNodeList(Integer num, boolean sameWeight, boolean
4981
/**
5082
* 统计负载均衡命中次数,样本数为 10000 次访问
5183
*/
52-
private static Map<Node, Long> loadBalance10000(LoadBalance<Node> algorithm, List<Node> nodes) {
84+
private static Map<Node, Long> loadBalance10000(LoadBalance<Node> algorithm, List<Node> nodes,
85+
List<String> ipList) {
5386
Map<Node, Long> staticMap = new TreeMap<>();
5487

55-
List<String> ipList = init10IpList();
5688
int ipLength = ipList.size();
5789
for (int i = 0; i < 10000; i++) {
5890
String ip = ipList.get(random.nextInt(ipLength));
5991
Node node = algorithm.select(nodes, ip);
60-
System.out.println(StrUtil.format("ip = {}, node url = {}", ip, node.getUrl()));
92+
// 打印每一次负载均衡的选择结果
93+
// System.out.println(StrUtil.format("ip = {}, node url = {}", ip, node.getUrl()));
6194
if (staticMap.containsKey(node)) {
6295
Long value = staticMap.get(node);
6396
staticMap.put(node, ++value);
@@ -76,28 +109,34 @@ private static Map<Node, Long> loadBalance10000(LoadBalance<Node> algorithm, Lis
76109
}
77110

78111
public static void main(String[] args) {
112+
// 构造 100 个候选服务器节点
79113
List<Node> nodes = initNodeList(100, false, false);
114+
// 构造 100 个随机IP
115+
List<String> ipList = initRandomIpList(100);
116+
117+
// ============================================================================
118+
// 基于以上构造数据,对每种算法都 负载均衡选择 10000 次,然后统计方差、标准差,查看负载均衡效果。
119+
120+
System.out.println("======================= 随机负载均衡 =======================");
121+
loadBalance10000(new RandomLoadBalance<>(), nodes, ipList);
122+
123+
System.out.println("======================= 加权随机负载均衡 =======================");
124+
loadBalance10000(new WeightRandomLoadBalance<>(), nodes, ipList);
125+
126+
System.out.println("======================= 轮询负载均衡 =======================");
127+
loadBalance10000(new RoundRobinLoadBalance<>(), nodes, ipList);
128+
129+
System.out.println("======================= 加权轮询负载均衡 =======================");
130+
loadBalance10000(new WeightRoundRobinLoadBalance<>(), nodes, ipList);
131+
132+
System.out.println("======================= 源地址哈希负载均衡 =======================");
133+
loadBalance10000(new IpHashLoadBalance<>(), nodes, ipList);
80134

81-
// System.out.println("======================= 随机负载均衡 =======================");
82-
// loadBalance10000(new RandomLoadBalance<>(), nodes);
83-
//
84-
// System.out.println("======================= 加权随机负载均衡 =======================");
85-
// loadBalance10000(new WeightRandomLoadBalance<>(), nodes);
86-
//
87-
// System.out.println("======================= 轮询负载均衡 =======================");
88-
// loadBalance10000(new RoundRobinLoadBalance<>(), nodes);
89-
//
90-
// System.out.println("======================= 加权轮询负载均衡 =======================");
91-
// loadBalance10000(new WeightRoundRobinLoadBalance<>(), nodes);
92-
//
93-
// System.out.println("======================= 源地址哈希负载均衡 =======================");
94-
// loadBalance10000(new IpHashLoadBalance<>(), nodes);
95-
//
96-
// System.out.println("======================= 最小活跃数负载均衡 =======================");
97-
// loadBalance10000(new LeastActiveLoadBalance<>(), nodes);
135+
System.out.println("======================= 最小活跃数负载均衡 =======================");
136+
loadBalance10000(new LeastActiveLoadBalance<>(), nodes, ipList);
98137

99138
System.out.println("======================= 一致性哈希负载均衡 =======================");
100-
loadBalance10000(new ConsistentHashLoadBalance<>(), nodes);
139+
loadBalance10000(new ConsistentHashLoadBalance<>(), nodes, ipList);
101140
}
102141

103142
}

codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/StatisticsUtil.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ public class StatisticsUtil {
44

55
private StatisticsUtil() {}
66

7-
// 方差 s^2=[(x1-x)^2 +...(xn-x)^2]/n
7+
/**
8+
* 方差计算
9+
* 公式:s^2 = [(x1-x)^2 +...(xn-x)^2]/n
10+
*/
811
public static double variance(Long[] array) {
912
int m = array.length;
1013
double sum = 0;
@@ -19,18 +22,13 @@ public static double variance(Long[] array) {
1922
return value / m;
2023
}
2124

22-
// 标准差σ=sqrt(s^2)
25+
/**
26+
* 标准差
27+
* 公式 result = sqrt(s^2),即 sqrt(variance(array))
28+
*/
2329
public static double standardDeviation(Long[] array) {
2430
int m = array.length;
25-
double sum = 0;
26-
for (Long item : array) {// 求和
27-
sum += item;
28-
}
29-
double avg = sum / m;// 求平均值
30-
double value = 0;
31-
for (Long item : array) {// 求方差
32-
value += (item - avg) * (item - avg);
33-
}
31+
double value = variance(array);
3432
return Math.sqrt(value / m);
3533
}
3634

0 commit comments

Comments
 (0)