淘先锋技术网

首页 1 2 3 4 5 6 7

前言

最近项目上有一个场景需要对接两个第三方,进行两个第三方的能力比较,这个时候就需要将我们的流量做一个分流,根据配置确定分流的流量比例,也就是每次请求需要根据配置来选择一个第三方,然后把流量发送过去,于是就想到了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)