首先来看看百度百科对于负载均衡的描述:
负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。(负载均衡) 我对于负载均衡的理解是,因为网络的一些原因,会使得众多服务器种某个服务器压力过于大,导致传输缓慢,我们可以提供一种方法,去均衡一下各个服务器之间的关系,使他们能够均衡的去完成网络传输,而不至于因为某些服务器的崩溃,使得整个系统变得延迟缓慢。下面,我们来进行一下负载均衡框架的实现,这将会对我以后的项目等产生很大的影响。

为了方便理解,先画个图表示:

随机负载均衡Java代码实现 java负载均衡是什么意思_随机负载均衡Java代码实现

图中可以看到客户端有很多的服务器可以选择,那如何进行选择,能保证各个服务器的连接数量相对均衡,就需要实现负载均衡。

这里有两种实现思路:

一: 将所有的服务器形成一条循环链,增加的时候,在链的末尾增加,删除的时候,将指定的服务器进行删除即可,取得一个服务器的时候,通过给一个currentNode指针来对这条链进行轮询,如果当前只有一个服务器,那就是这个服务器,如果有多个服务器,那就进行遍历,保证每次将这些服务器均匀取得。

来看具体代码:

首先我们需要一个INetNode来取得服务器的ip和port:

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

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 (!(obj instanceof DefaultNetNode))
			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 + "]";
	}

}

需要定义该框架的功能:增加,删除,取得服务器:

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

针对这个接口,我们需要进行扩展,给一个map来存放所有的服务器:

public abstract class AbstractNetNodeBalance implements INetNodeBalance {
	protected final Map<Integer, INetNode> nodePool;

	public AbstractNetNodeBalance() {
		this.nodePool = new ConcurrentHashMap<>();
	}
	
	@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());
	}
	
}

可以发现,这里用到了抽象类,为什么要给抽象类呢?很简单,因为我们接口定义了三个方法,而在AbstractNetNodeBalance 类中,只实现了两个,get方法还没有给出,因为get方法需要进行不同的负载均衡,所以,他应该由他的子类进行实现,不同的子类,它的负载均衡方法是不一样的。
下面看我的轮询方式:

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 void setNext(PollingNetNode next) {
		this.next = next;
	}

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

	public PollingNetNode getNext() {
		return this.next;
	}
	
	public PollingNetNode getPre() {
		return this.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(newNode);
	}

	@Override
	public synchronized 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 = target.getNext();
		}
		
		if (pollingNode == target) {
			pollingNode = target.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;
	}

}

对于上述的轮询,可以画个图来进行表示:

随机负载均衡Java代码实现 java负载均衡是什么意思_服务器_02

第二种实现思路,通过随机数的方式,也就是,产生一个随机数,对服务器的总个数进行取余,获得的那个下标就是所取的服务器。

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);
	}

}

上述是我自己实现的两个负载均衡思路,并且写成了接口,以后,我们想要进行负载均衡的时候,只需要提供一个set方法,set接口的实现类进去就可以直接调用负载均衡了。