对于作开发的同窗来讲,负载均衡算法已经不陌生了,今天一块儿来盘点一下分布式系统中都是有哪些负载均衡算法以及它的优缺点;算法
思想: 将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端每一台服务器,而不关心服务实际的链接数和当前系统的负载;
代码实现:后端
private List<String> list = new CopyOnWriteArrayList(); private volatile Integer pos = 0; { list.add("127.0.0.1"); list.add("127.0.0.2"); list.add("127.0.0.3"); } public String getServer() { if (null == list || list.size() <= 0) { return null; } String server = null; synchronized (pos) { if (pos >= list.size()) { pos = 0; } server = list.get(pos++); } return server; }
总结:服务器
这种算法简单,依次转发,每一个服务器的请求数量平均;
缺点:当集群中的服务器的性能有差异时,没法区别对待的状况下会形成资源浪费;负载均衡
思想: 经过系统随机函数,根据后端服务器列表大小值来随机选取其中一台进行访问;随着调用量的增大,效果接近轮询算法;
代码实现:dom
private List<String> list = new CopyOnWriteArrayList(); { list.add("127.0.0.1"); list.add("127.0.0.2"); list.add("127.0.0.3"); list.add("127.0.0.4"); } public String getServerRandom() { if (null == list || list.size() <= 0) { return null; } Random random = new Random(); String server = list.get(random.nextInt(list.size())); return server; }
总结:分布式
算法虽然简单,可是在大请求量的状况下才能保证均衡ide
思想: 源地址哈希的思想是获取客户端访问的ip地址,经过hash函数计算获得一个值,用该值从服务器列表中进行取模运算;当服务器列表不变时,同一ip老是请求到同一台服务器中;
代码实现:函数
private List<String> list = new CopyOnWriteArrayList(); { list.add("127.0.0.1"); list.add("127.0.0.2"); list.add("127.0.0.3"); list.add("127.0.0.4"); } public String getServerHash(String hostIp) { if (null == list || list.size() <= 0 || null == hostIp) { return null; } int code = hostIp.hashCode(); int serverPos = list.size() % code; return list.get(serverPos); }
思想: 与轮询算法相比,它加了权重,权重超高的服务,接收到有请求越多;
代码实现:性能
private ConcurrentMap<String, Integer> hosts = new ConcurrentHashMap<>(); private volatile Integer pos = 0; { hosts.put("127.0.0.1", 1); hosts.put("127.0.0.2", 2); hosts.put("127.0.0.3", 2); hosts.put("127.0.0.4", 1); } public String getServerRoundRobin() { List<String> list = new ArrayList<>(); for (Map.Entry<String, Integer> entry : hosts.entrySet()) { Integer value = entry.getValue(); for (int i = 0; i < value; i++) { list.add(entry.getKey()); } } String server = null; synchronized (pos) { if (pos >= list.size()) { pos = 0; } server = list.get(pos++); } return server; }
思想: 是在随机的基础上,加上权值;
代码实现:3d
private ConcurrentMap<String, Integer> hosts = new ConcurrentHashMap<>(); private volatile Integer pos = 0; { hosts.put("127.0.0.1", 1); hosts.put("127.0.0.2", 2); hosts.put("127.0.0.3", 2); hosts.put("127.0.0.4", 1); } public String getServerRandomWeight() { List<String> list = new ArrayList<>(); for (Map.Entry<String, Integer> entry : hosts.entrySet()) { Integer value = entry.getValue(); for (int i = 0; i < value; i++) { list.add(entry.getKey()); } } Random random = new Random(); String server = list.get(random.nextInt(list.size())); return server; }
上面两种实现加权的方式都是权重为几,就往list里面add几回,若是服务器数量之庞大,会致使list列表过大;有另一种实现加权的方式,把每台服务和权重划分为一段,权重越大,占的段长越长:
代码实现:
private Map<String, Integer> hosts = new ConcurrentHashMap<>(); private volatile Integer pos = 0; { hosts.put("127.0.0.1", 1); hosts.put("127.0.0.2", 2); hosts.put("127.0.0.3", 2); hosts.put("127.0.0.4", 1); } public String getServerRandomWeight2() { // 累加全部权重 int sum = 0; for (Map.Entry<String, Integer> entry : hosts.entrySet()) { sum += entry.getValue(); } Random random = new Random(); int index = random.nextInt(sum); for (Map.Entry<String, Integer> entry : hosts.entrySet()) { Integer value = entry.getValue(); if(value >= index){ return entry.getKey(); } index -= entry.getValue(); } return null; }
思想: 最小链接数法是根据服务器当前的链接状况进行负载均衡的,它会选择一台链接数最少的机器来提供服务;
代码实现:
// key:机器ip value:当前访问量 private Map<String, Integer> hosts = new ConcurrentHashMap<>(); private volatile Integer pos = 0; { hosts.put("127.0.0.1", 6); hosts.put("127.0.0.2", 2); hosts.put("127.0.0.3", 3); hosts.put("127.0.0.4", 8); } public String getServerLeastConnection() { // 寻找最小链接 int min = 0; String key = null; for (Map.Entry<String, Integer> entry : hosts.entrySet()) { if (entry.getValue() < min) { min = entry.getValue(); key = entry.getKey(); } } hosts.put(key, min + 1); return key; }
注:文中代码实现不适合真实场景,只是为了简单易懂理解算法思想;