Java 進(jìn)階之深入理解負(fù)載均衡的 5 種算法實(shí)現(xiàn)原理
前言
什么是負(fù)載均衡:
指由多臺(tái)服務(wù)器以對(duì)稱的方式組成一個(gè)服務(wù)器集合,每臺(tái)服務(wù)器都具有等價(jià)的地位,都可以單獨(dú)對(duì)外提供服務(wù)而無須其他服務(wù)器的輔助。通過某種 負(fù)載分擔(dān)技術(shù),將外部發(fā)送來的請(qǐng)求均勻分配到對(duì)稱結(jié)構(gòu)中的某一臺(tái)服務(wù)器上,而接收到請(qǐng)求的服務(wù)器獨(dú)立地回應(yīng)客戶的請(qǐng)求。負(fù)載均衡能夠平均分配客戶請(qǐng)求到服 務(wù)器陣列,借此提供快速獲取重要數(shù)據(jù),解決大量并發(fā)訪問服務(wù)問題,這種集群技術(shù)可以用最少的投資獲得接近于大型主機(jī)的性能;
今天我們就來說說;
一、負(fù)載均衡算法簡介
1、輪詢法
將請(qǐng)求按順序輪流地分配到后端服務(wù)器上,它均衡地對(duì)待后端的每一臺(tái)服務(wù)器,而不關(guān)心服務(wù)器實(shí)際的連接數(shù)和當(dāng)前的系統(tǒng)負(fù)載;
2、隨機(jī)法
通過系統(tǒng)的隨機(jī)算法,根據(jù)后端服務(wù)器的列表大小值來隨機(jī)選取其中的一臺(tái)服務(wù)器進(jìn)行訪問。由概率統(tǒng)計(jì)理論可以得知,隨著客戶端調(diào)用服務(wù)端的次數(shù)增多, 其實(shí)際效果越來越接近于平均分配調(diào)用量到后端的每一臺(tái)服務(wù)器,也就是輪詢的結(jié)果;
3、源地址哈希法
源地址哈希的思想是根據(jù)獲取客戶端的IP地址,通過哈希函數(shù)計(jì)算得到的一個(gè)數(shù)值,用該數(shù)值對(duì)服務(wù)器列表的大小進(jìn)行取模運(yùn)算,得到的結(jié)果便是客服端要訪問服務(wù)器的序號(hào)。采用源地址哈希法進(jìn)行負(fù)載均衡,同一IP地址的客戶端,當(dāng)后端服務(wù)器列表不變時(shí),它每次都會(huì)映射到同一臺(tái)后端服務(wù)器進(jìn)行訪問;
4、加權(quán)輪詢法
不同的后端服務(wù)器可能機(jī)器的配置和當(dāng)前系統(tǒng)的負(fù)載并不相同,因此它們的抗壓能力也不相同。給配置高、負(fù)載低的機(jī)器配置更高的權(quán)重,讓其處理更多的請(qǐng);而配置低、負(fù)載高的機(jī)器,給其分配較低的權(quán)重,降低其系統(tǒng)負(fù)載,加權(quán)輪詢能很好地處理這一問題,并將請(qǐng)求順序且按照權(quán)重分配到后端;
5、加權(quán)隨機(jī)法
與加權(quán)輪詢法一樣,加權(quán)隨機(jī)法也根據(jù)后端機(jī)器的配置,系統(tǒng)的負(fù)載分配不同的權(quán)重。不同的是,它是按照權(quán)重隨機(jī)請(qǐng)求后端服務(wù)器,而非順序;
二、代碼實(shí)現(xiàn)負(fù)載均衡五種算法
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,要循環(huán)list取出
- ArrayList<String> iplist=new ArrayList<String>();
- iplist.addAll(ipset);
- String serverName=null;
- // 4.定義一個(gè)循環(huán)的值,如果大于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.加權(quán)輪詢法
- 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();
- //定義一個(gè)list放所有server
- ArrayList<String> ipArrayList=new ArrayList<String>();
- //循環(huán)set,根據(jù)set中的可以去得知map中的value,給list中添加對(duì)應(yīng)數(shù)字的server數(shù)量
- 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.隨機(jī)法
- 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();
- //定義一個(gè)list放所有server
- ArrayList<String> ipArrayList=new ArrayList<String>();
- ipArrayList.addAll(ipSet);
- //循環(huán)隨機(jī)數(shù)
- Random random=new Random();
- //隨機(jī)數(shù)在list數(shù)量中取(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.加權(quán)隨機(jī)
- 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();
- //定義一個(gè)list放所有server
- ArrayList<String> ipArrayList=new ArrayList<String>();
- //循環(huán)set,根據(jù)set中的可以去得知map中的value,給list中添加對(duì)應(yīng)數(shù)字的server數(shù)量
- while (ipIterator.hasNext()){
- String serverName=ipIterator.next();
- Integer weight=ipServerMap.get(serverName);
- for (int i=0;i<weight;i++){
- ipArrayList.add(serverName);
- }
- }
- //循環(huán)隨機(jī)數(shù)
- Random random=new Random();
- //隨機(jī)數(shù)在list數(shù)量中?。?-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.源地址哈希法
- 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,要循環(huán)list取出
- ArrayList<String> iplist=new ArrayList<String>();
- iplist.addAll(ipset);
- //對(duì)ip的hashcode值取余數(shù),每次都一樣的
- 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);
- }
- }
總結(jié)
不進(jìn)則退,一起加油