前言
最近项目上有一个场景需要对接两个第三方,进行两个第三方的能力比较,这个时候就需要将我们的流量做一个分流,根据配置确定分流的流量比例,也就是每次请求需要根据配置来选择一个第三方,然后把流量发送过去,于是就想到了Nginx的负载均衡算法,本身也是一种流量分配算法。
NGINX平滑加权轮询算法
算法涉及的几个概念
weight:
约定权重,在配置文件 or 初始化时指定的每个节点的权重
effectiveWeight:
有效权重,作用是节点异常,降低其权重,初始值为 weight,在通讯过程中发现节点异常,则-1;之后再次选取本节点,调用成功一次则+1,直达恢复到weight;
currentWeight:
节点当前权重,初始化为 0;
Java实现
当前实现的时候,不考虑effectiveWeight
定义节点:
@Data
public class Node {
/**
* 节点名称
*/
private String name;
/**
* 权重
*/
private int weight;
/**
* 当前权重
*/
private int currentWeight;
}
平滑加权轮询算法实现:
public class SmoothWeightPolling {
/**
* 所有负载均衡的节点集合
*/
private List<Node> nodeList;
/**
* 为了提高计算的性能,在初始化的时候就把总权重计算出来
*/
private int totalWeight;
public SmoothWeightPolling(List<Node> nodeList) {
if (null == nodeList || nodeList.isEmpty()) {
throw new IllegalArgumentException("nodeList is null or empty");
}
this.nodeList = nodeList;
for (Node node : nodeList) {
totalWeight = totalWeight + node.getWeight();
}
}
public Node getNode() {
Node maxCurrentWeightNode = null;
for (Node node : nodeList) {
//计算每个节点的currentWeight = currentWeight + Weight;
node.setCurrentWeight(node.getCurrentWeight() + node.getWeight());
if (null == maxCurrentWeightNode) {
maxCurrentWeightNode = node;
} else if (maxCurrentWeightNode.getCurrentWeight() < node.getCurrentWeight()) {
//选择所有节点中currentWeight最大的作为选中节点;
maxCurrentWeightNode = node;
}
}
//选中节点的currentWeight = currentWeight - totalWeight
maxCurrentWeightNode.setCurrentWeight(maxCurrentWeightNode.getCurrentWeight() - totalWeight);
return maxCurrentWeightNode;
}
public static void main(String[] args) {
List<Node> nodeList = new ArrayList<>();
Node node = new Node();
node.setName("a");
node.setWeight(4);
nodeList.add(node);
node = new Node();
node.setName("b");
node.setWeight(2);
nodeList.add(node);
node = new Node();
node.setName("c");
node.setWeight(1);
nodeList.add(node);
SmoothWeightPolling smoothWeightPolling = new SmoothWeightPolling(nodeList);
for (int i = 0; i < 7 ; i++) {
System.out.println("select node = " + smoothWeightPolling.getNode());
}
}
}
输出:
select node = Node(name=a, weight=4, currentWeight=-3)
select node = Node(name=b, weight=2, currentWeight=-3)
select node = Node(name=a, weight=4, currentWeight=-2)
select node = Node(name=c, weight=1, currentWeight=-3)
select node = Node(name=a, weight=4, currentWeight=-1)
select node = Node(name=b, weight=2, currentWeight=-2)
select node = Node(name=a, weight=4, currentWeight=0)