出处: Java代码实现负载均衡五种算法
前言:
负载均衡是为了解决并发情况下,多个请求访问,把请求通过提前约定好的规则转发给各个server。其中有好几个种经典的算法。在用java代码编写这几种算法之前,先来了解一下负载均衡这个概念。
1.概念
负载,从字面意思可以分析,是指后端server可以承受的压力。这个一方面是服务器的性能,另一方面就是代码的质量了。
均衡,就是说把服务部署在多态server,如何调度这些资源。根据服务器性能不同,进行一个权衡。
当web访问量增加,服务器性能不同,更好的去利用服务器,我们需要负载均衡算法。
2.几种负载均衡算法简介
主要的负载均衡算法是图中这些,在代码实现之前,我们先简单回顾一下他们的概念。
轮询法:
轮询算法按顺序把每个新的连接请求分配给下一个服务器,最终把所有请求平分给所有的服务器。
优点:绝对公平
缺点:无法根据服务器性能去分配,无法合理利用服务器资源。
加权轮询法:
该算法中,每个机器接受的连接数量是按权重比例分配的。这是对普通轮询算法的改进,比如你可以设定:第三台机器的处理能力是第一台机器的两倍,那么负载均衡器会把两倍的连接数量分配给第3台机器。加权轮询分为:简单的轮询、平滑的轮询。
什么是平滑的轮询,就是把每个不同的服务,平均分布。在Nginx源码中,实现了一种叫做平滑的加权轮询(smooth weighted round-robin balancing)的算法,它生成的序列更加均匀。5个请求现在分散开来,不再是连续的。
随机法:
负载均衡方法随机的把负载分配到各个可用的服务器上,通过随机数生成算法选取一个服务器。毕竟随机,,有效性受到了质疑。
加权随机法:
获取带有权重的随机数字,随机这种东西,不能看绝对,只能看相对。
IP_Hash算法:
hash(object)%N算法,通过一种散列算法把请求分配到不同的服务器上。
3.Java代码实现负载均衡五种算法
1.轮询法:
import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class TestRoundRobin { // 1.定义map, key-ip,value-weight static Map<String,Integer> ipMap=new HashMap<>(); static { ipMap.put("192.168.13.1",1); ipMap.put("192.168.13.2",1); ipMap.put("192.168.13.3",1); } // Integer sum=0; Integer pos = 0; public String RoundRobin(){ Map<String,Integer> ipServerMap=new ConcurrentHashMap<>(); ipServerMap.putAll(ipMap); // 2.取出来key,放到set中 Set<String> ipset=ipServerMap.keySet(); // 3.set放到list,要循环list取出 ArrayList<String> iplist=new ArrayList<String>(); iplist.addAll(ipset); String serverName=null; // 4.定义一个循环的值,如果大于set就从0开始 synchronized(pos){ if (pos>=ipset.size()){ pos=0; } serverName=iplist.get(pos); //轮询+1 pos ++; } return serverName; } public static void main(String[] args) { TestRoundRobin testRoundRobin=new TestRoundRobin(); for (int i=0;i<10;i++){ String serverIp=testRoundRobin.RoundRobin(); System.out.println(serverIp); } } }
2.加权轮询法
import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class TestWeightRobin { // 1.map, key-ip,value-weight static Map<String,Integer> ipMap=new HashMap<>(); static { ipMap.put("192.168.13.1",1); ipMap.put("192.168.13.2",2); ipMap.put("192.168.13.3",4); } Integer pos=0; public String WeightRobin(){ Map<String,Integer> ipServerMap=new ConcurrentHashMap<>(); ipServerMap.putAll(ipMap); Set<String> ipSet=ipServerMap.keySet(); Iterator<String> ipIterator=ipSet.iterator(); //定义一个list放所有server ArrayList<String> ipArrayList=new ArrayList<String>(); //循环set,根据set中的可以去得知map中的value,给list中添加对应数字的server数量 while (ipIterator.hasNext()){ String serverName=ipIterator.next(); Integer weight=ipServerMap.get(serverName); for (int i = 0;i < weight ;i++){ ipArrayList.add(serverName); } } String serverName=null; if (pos>=ipArrayList.size()){ pos=0; } serverName=ipArrayList.get(pos); //轮询+1 pos ++; return serverName; } public static void main(String[] args) { TestWeightRobin testWeightRobin=new TestWeightRobin(); for (int i =0;i<10;i++){ String server=testWeightRobin.WeightRobin(); System.out.println(server); } } }
3.随机法:
import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class TestRandom { // 1.定义map, key-ip,value-weight static Map<String,Integer> ipMap=new HashMap<>(); static { ipMap.put("192.168.13.1",1); ipMap.put("192.168.13.2",2); ipMap.put("192.168.13.3",4); } public String Random() { Map<String,Integer> ipServerMap=new ConcurrentHashMap<>(); ipServerMap.putAll(ipMap); Set<String> ipSet=ipServerMap.keySet(); //定义一个list放所有server ArrayList<String> ipArrayList=new ArrayList<String>(); ipArrayList.addAll(ipSet); //循环随机数 Random random=new Random(); //随机数在list数量中取(1-list.size) int pos=random.nextInt(ipArrayList.size()); String serverNameReturn= ipArrayList.get(pos); return serverNameReturn; } public static void main(String[] args) { TestRandom testRandom=new TestRandom(); for (int i =0;i<10;i++){ String server=testRandom.Random(); System.out.println(server); } } }
4.加权随机:
import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class TestRobinRandom { // 1.定义map, key-ip,value-weight static Map<String,Integer> ipMap=new HashMap<>(); static { ipMap.put("192.168.13.1",1); ipMap.put("192.168.13.2",2); ipMap.put("192.168.13.3",4); } public String RobinRandom(){ Map<String,Integer> ipServerMap=new ConcurrentHashMap<>(); ipServerMap.putAll(ipMap); Set<String> ipSet=ipServerMap.keySet(); Iterator<String> ipIterator=ipSet.iterator(); //定义一个list放所有server ArrayList<String> ipArrayList=new ArrayList<String>(); //循环set,根据set中的可以去得知map中的value,给list中添加对应数字的server数量 while (ipIterator.hasNext()){ String serverName=ipIterator.next(); Integer weight=ipServerMap.get(serverName); for (int i=0;i<weight;i++){ ipArrayList.add(serverName); } } //循环随机数 Random random=new Random(); //随机数在list数量中取(1-list.size) int pos=random.nextInt(ipArrayList.size()); String serverNameReturn= ipArrayList.get(pos); return serverNameReturn; } public static void main(String[] args) { TestRobinRandom testRobinRandom=new TestRobinRandom(); for (int i =0;i<10;i++){ String server=testRobinRandom.RobinRandom(); System.out.println(server); } } }
5.IP_Hash算法:
import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class ipHash { // 1.定义map, key-ip,value-weight static Map<String,Integer> ipMap=new HashMap<>(); static { ipMap.put("192.168.13.1",1); ipMap.put("192.168.13.2",2); ipMap.put("192.168.13.3",4); } public String ipHash(String clientIP){ Map<String,Integer> ipServerMap=new ConcurrentHashMap<>(); ipServerMap.putAll(ipMap); // 2.取出来key,放到set中 Set<String> ipset=ipServerMap.keySet(); // 3.set放到list,要循环list取出 ArrayList<String> iplist=new ArrayList<String>(); iplist.addAll(ipset); //对ip的hashcode值取余数,每次都一样的 int hashCode=clientIP.hashCode(); int serverListsize=iplist.size(); int pos=hashCode%serverListsize; return iplist.get(pos); } public static void main(String[] args) { ipHash iphash=new ipHash(); String servername= iphash.ipHash("192.168.21.2"); System.out.println(servername); } }