自主设计实现负载均衡框架

首先,什么 是负载均衡?
负载均衡(Load Balance)指将负载(工作任务)进行平衡,分摊到多个操作单元上进行运行。
我们来举个例子说明一下:假设有多台服务器,如果有成千上万个客户端请求连接同一个服务器,那么这台服务器就会因为负载压力过大而使得网络响应速率降低,甚至会崩溃,这时候我们就需要负载均衡一下,把这些客户端均衡给多个服务器,来提高响应速率。这也是要设计实现负载均衡框架的初衷。
基于上述说明,实现负载均衡的两种方式:
1.轮询方式:轮流向节点池中的每一个服务器发送请求;
2.随机方式:通过产生随机数,请求某一个服务器

下面我们看一下具体代码,INetNode接口(用来获得某个服务器的ip和port):

public interface INetNode {
	String getIp();
	int getPort();
}

DefaultNetNode类(INetNode的实现类):

public class DefaultNetNode implements INetNode {
	private String ip;
	private int port;
	
	public DefaultNetNode() {
	}
	
	public DefaultNetNode(String ip, int port) {
		this.ip = ip;
		this.port = port;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public void setPort(int port) {
		this.port = port;
	}

	@Override
	public String getIp() {
		return ip;
	}

	@Override
	public int getPort() {
		return port;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((ip == null) ? 0 : ip.hashCode());
		result = prime * result + port;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		DefaultNetNode other = (DefaultNetNode) obj;
		if (ip == null) {
			if (other.ip != null)
				return false;
		} else if (!ip.equals(other.ip))
			return false;
		if (port != other.port)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "[" + ip + ":" + port+ "]";
	}

}

接下来我们看另外一个接口,INetNodeBalance接口(完成增加,删除和获得一个服务器的功能):

public interface INetNodeBalance {
	void addNode(INetNode node);
	INetNode removeNode(INetNode node);
	INetNode getNode();
}

AbstractNetNodeBalance类(定义了一个Map用来存放服务器节点,这里以节点的hashcode为值,以该节点为键存到节点池中,为服务器的增加,删除和获得做准备):

public abstract class AbstractNetNodeBalance implements INetNodeBalance {
	protected final Map<Integer, INetNode>  nodePool;
	
	public AbstractNetNodeBalance() {
		nodePool = new ConcurrentHashMap<Integer, INetNode>();
	}

	@Override
	public void addNode(INetNode node) {
		if (node == null) {
			return;
		}
		int nodeHashCode = node.hashCode();
		if (nodePool.containsKey(nodeHashCode)) {
			return;
		}
		nodePool.put(nodeHashCode, node);
	}
	
	public boolean isNodePoolEmpty() {
		return nodePool.isEmpty();
	}

	@Override
	public INetNode removeNode(INetNode node) {
		if (node == null) {
			return null;
		}
		return nodePool.remove(node.hashCode());
	}

}

我们可以看出上述类是个抽象类,因为它的getNode()方法没有实现,我们后续需要用不同的负载均衡方式来获得服务器节点,所以需要该类的子类来完成不同方式的负载均衡,来实现getNode()方法。
下面就是轮询方式,将所有的服务器构成一个循环链,当增加服务器的时候,在链的结尾增加;当删除服务器的时候,删除指定的服务器节点;当获得一个服务器时,通过给一个currentNode指针来对这条链进行轮询,如果只有一个服务器,则获得该服务器,如果有多个服务器,那就进行遍历,保证每次均匀取得服务器。

public class PollingNetNode extends DefaultNetNode {
	private PollingNetNode next;
	private PollingNetNode pre;
	
	public PollingNetNode() {
		this.next = this;
		this.pre = this;
	}

	public PollingNetNode(String ip, int port) {
		super(ip, port);
		this.next = this;
		this.pre = this;
	}

	public PollingNetNode getNext() {
		return next;
	}

	public void setNext(PollingNetNode next) {
		this.next = next;
	}

	public PollingNetNode getPre() {
		return pre;
	}

	public void setPre(PollingNetNode pre) {
		this.pre = pre;
	}
	
}

public class PollingBalance extends AbstractNetNodeBalance {
	private PollingNetNode pollingNode;
	private PollingNetNode currentNode;
	
	public PollingBalance() {
		super();
	}

	@Override
	public synchronized void addNode(INetNode node) {
		PollingNetNode newNode = new PollingNetNode(node.getIp(), node.getPort());
		
		if (pollingNode == null) {
			pollingNode = newNode;
			currentNode = pollingNode;
			super.addNode(newNode);
			return;
		}
		newNode.setPre(pollingNode.getPre());
		newNode.setNext(pollingNode);
		pollingNode.setPre(newNode);
		newNode.getPre().setNext(newNode);
		
		super.addNode(node);
	}

	@Override
	public INetNode removeNode(INetNode node) {
		PollingNetNode target = new PollingNetNode(node.getIp(), node.getPort());
		target = (PollingNetNode) super.removeNode(target);
		
		if (target == null) {
			return null;
		}
		
		if (isNodePoolEmpty()) {
			pollingNode = null;
			currentNode = null;
			return pollingNode;
		}
		
		if (currentNode == target) {
			currentNode = currentNode.getNext();
		}
		
		if (pollingNode == target) {
			pollingNode = pollingNode.getNext();
		}
		
		target.getPre().setNext(target.getNext());
		target.getNext().setPre(target.getPre());
		target.setPre(target);
		target.setNext(target);
		
		return target;
	}

	@Override
	public synchronized INetNode getNode() {
		INetNode result = currentNode;
		if (currentNode != null) {
			currentNode = currentNode.getNext();
		}
		return result;
	}

}

下图所示,就是对这条双向循环链中节点的增加和删除过程,也就是上述代码增加和删除服务器节点的过程。
在这里插入图片描述
接下来我们看一下随机方式,构建一个nodeList,随机产生一个数对nodeList的长度取余,得到的结果作为下标,取得该下标下的服务器节点。

public class RandomBalance extends AbstractNetNodeBalance {
	private final List<INetNode> nodeList;
	
	public RandomBalance() {
		super();
		nodeList = new LinkedList<>();
	}

	@Override
	public void addNode(INetNode node) {
		super.addNode(node);
		if (node == null || nodeList.contains(node)) {
			return;
		}
		nodeList.add(node);
	}

	@Override
	public INetNode removeNode(INetNode node) {
		if (node == null || !nodeList.contains(node)) {
			return null;
		}
		nodeList.remove(node);
		return super.removeNode(node);
	}

	@Override
	public INetNode getNode() {
		if (isNodePoolEmpty()) {
			return null;
		}
		int index = ((int) (Math.random() * 10000)) % nodeList.size();
		return this.nodeList.get(index);
	}

}

搭建好了负载均衡框架,我们可以打包成jar包,方便以后使用。接下来我们要做的《简版服务发现》就要用到这个工具。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值