负载均衡是分布式系统的常见功能,具有算法成熟,配置灵活,对系统性能有较大影响等特点。下面是目前比较流行的几种算法:
a.Nginx负载均衡算法
总体思路:
- 计算权重总和和找出最大权重,然后最大权重的被选择
- 被选择后最大权重减去权重总和,可以使得不会总选上最大权重,使得负载更加平滑。
- 自身权重加上和原始权重等比例的权重来模拟随机性。
private static ServerForTest chooseServer(List<ServerForTest> servers) {
double totalWeight = 0;
double maxWeight = Double.NEGATIVE_INFINITY;
ServerForTest chosen = null;
for (ServerForTest server : servers) {
server.setCurrentWeight(server.getWeight()
+ server.getCurrentWeight());
double currentWeight = server.getCurrentWeight();
totalWeight += currentWeight;
if (currentWeight > maxWeight) {
maxWeight = currentWeight;
chosen = server;
}
}
chosen.setCurrentWeight(chosen.getCurrentWeight() - totalWeight);
// System.out.println("chosen : " + chosen.getAddress());
return chosen;
}
b.一致性hash负载均衡算法
算法门槛较高,要对hash算法有较深的理解。一致性hash一般不能严格按照权重比例, 因为和虚拟节点hash之后的位置和每一个请求的hash之后的位置都有关系。如果不是动态增减服务器数目,一般不建议使用一致性hash的负载均衡策略。
// Redis一致性hash相关算法
// 构建hash环
private static void insertVirtualNode2(TreeMap<Long, ServerForTest> map,
int index, ServerForTest server) {
StringBuilder keyBuilder = new StringBuilder(64);
keyBuilder.append(server.getAddress() + "_" + index);
int count = Double.valueOf(allNodeNum * server.getRatio()).intValue();
// System.out.println("index = " + index + ",count = " + count);
for (int j = 0; j < count; j++) {
keyBuilder.append("_" + j);
long hash = MurmurHash.INSTANCE.hash(keyBuilder.toString());
map.put(hash, server);
}
}
// Redis一致性hash相关算法
// 一致性hash获取对应的key
private static ServerForTest forServer2(
TreeMap<Long, ServerForTest> nodeMap, Random random) {
long hash = MurmurHash.INSTANCE.hash(toKey(random));
SortedMap<Long, ServerForTest> tail = nodeMap.tailMap(hash);
if (tail.isEmpty()) {
return nodeMap.get(nodeMap.firstKey());
}
return tail.get(tail.firstKey());
}
c.轮询
分为顺序轮询和权重轮询,顺序轮询点意义是从第一个按顺序遍历到最后一个,到最后一个然后再重新开始遍历,不断循环。顺序轮询算法如下:
private static Map<String, AtomicInteger> chooseServerForTest(int times) {
List<ServerForTest> servers = new ArrayList<ServerForTest>(3);
ServerForTest server1 = new ServerForTest("www.baidu.com", 1);
servers.add(server1);
ServerForTest server2 = new ServerForTest("www.taobao.com", 3);
servers.add(server2);
ServerForTest server3 = new ServerForTest("www.qq.com", 6);
servers.add(server3);
Map<String, AtomicInteger> result = initialResult(servers);
int size = servers.size();
for (int i = 0; i < times; i++) {
ServerForTest server = servers.get(sequenceNum.getAndIncrement()
% size);
result.get(server.getAddress()).getAndIncrement();
}
return result;
}
d.加权随机
每次负载产生一个随机数,如果权重比随机数大,则被选择。
private static ServerForTest RandomLoadBalanceTest(
List<ServerForTest> servers, Random random) {
boolean sameWeight = true;
int size = servers.size();
double totalWeight = 0;
for (int i = 0; i < size; i++) {
totalWeight += servers.get(i).getWeight();
if (i != 0
&& Double.compare(servers.get(i).getWeight(),
servers.get(i - 1).getWeight()) != 0)
{
sameWeight = false;
}
}
ServerForTest serverGet = null;
if (!sameWeight && totalWeight > 0) {
double offset = random.nextDouble() * totalWeight;
for (ServerForTest server : servers) {
double currentWeight = server.getWeight();
if (currentWeight > offset) {
serverGet = server;
break;
} else {
offset -= currentWeight;
}
}
}
if (serverGet == null) {
serverGet = servers.get(random.nextInt(size));
}
return serverGet;
}
参考资料链接:
Nginx负载均衡算法
http://blog.sina.com.cn/s/blog_9c3ba23d01010rof.html
dubbo负载均衡算法
https://blog.youkuaiyun.com/qq_26562641/article/details/50392142