出處: 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); } }