集羣與負載均衡的算法與實現

前言:

     負載均衡是爲了解決併發情況下,多個請求訪問,把請求通過提前約定好的規則轉發給各個server。其中有好幾個種經典的算法。在用java代碼編寫這幾種算法之前,先來了解一下負載均衡這個概念。

1.概念

    負載均衡,英文名稱爲Load Balance,指由多臺服務器以對稱的方式組成一個服務器集合,每臺服務器都具有等價的地位,都可以單獨對外提供服務而無須其他服務器的輔助。通過某種負載分擔技術,將外部發送來的請求均勻分配到對稱結構中的某一臺服務器上,而接收到請求的服務器獨立地迴應客戶的請求。負載均衡能夠平均分配客戶請求到服務器陣列,藉此提供快速獲取重要數據,解決大量併發訪問服務問題,這種集羣技術可以用最少的投資獲得接近於大型主機的性能。

2.幾種負載均衡算法簡介

主要的負載均衡算法是圖中這些,在代碼實現之前,我們先簡單回顧一下他們的概念。

輪詢法:

   輪詢算法按順序把每個新的連接請求分配給下一個服務器,最終把所有請求平分給所有的服務器。既是每一次把來自用戶的請求輪流分配給內部中的服務器,從1開始,直到N(內部服務器個數),然後重新開始循環。算法的優點是其簡潔性,它無需記錄當前所有連接的狀態,所以它是一種無狀態調度。

   優點:絕對公平

   缺點:無法根據服務器性能去分配,無法合理利用服務器資源。

加權輪詢法:

    該算法中,每個機器接受的連接數量是按權重比例分配的。這是對普通輪詢算法的改進,比如你可以設定:第三臺機器的處理能力是第一臺機器的兩倍,那麼負載均衡器會把兩倍的連接數量分配給第3臺機器。加權輪詢分爲:簡單的輪詢、平滑的輪詢。

     什麼是平滑的輪詢,就是把每個不同的服務,平均分佈。在Nginx源碼中,實現了一種叫做平滑的加權輪詢(smooth weighted round-robin balancing)的算法,它生成的序列更加均勻。5個請求現在分散開來,不再是連續的。

隨機法:

    負載均衡方法隨機的把負載分配到各個可用的服務器上,通過隨機數生成算法選取一個服務器。畢竟隨機,,有效性受到了質疑。

加權隨機法:

     獲取帶有權重的隨機數字,隨機這種東西,不能看絕對,只能看相對。

IP_Hash算法:

    hash(object)%N算法,通過一種散列算法把請求分配到不同的服務器上。

Source Hashing(源地址Hash)

源地址散列調度算法是一種靜態映射算法,它通過一個散列(Hash)函數將一個源IP地址映射到一臺服務器,若該服務器是可用的並且沒有超負荷,將請求發送到該服務器,否則返回空。它採用的散列函數與目標地址散列調度算法的相同。它的算法流程與目標地址散列調度算法的基本相似,除了將請求的目標IP地址換成請求的源IP地址,所以這裏不一個一個敘述。

Destination hashing(目標地址Hash)

目標地址散列調度算法也是針對目標IP地址的負載均衡,它是一種靜態映射算法,通過一個散列(Hash)函數將一個目標IP地址映射到一臺服務器。目標地址散列調度算法先根據請求的目標IP地址,作爲散列鍵(Hash Key)從靜態分配的散列表找出對應的服務器,若該服務器是可用的且未超載,將請求發送到該服務器,否則返回空。

Least-Connection(最少連接)

最少連接調度算法是把新的連接請求分配到當前連接數最小的服務器,最小連接調度是一種動態調度短算法,它通過服務器當前所活躍的連接數來估計服務器的負載均衡,調度器需要記錄各個服務器已建立連接的數目,當一個請求被調度到某臺服務器,其連接數加1,當連接中止或超時,其連接數減一,在系統實現時,我們也引入當服務器的權值爲0時,表示該服務器不可用而不被調度。

3.Java代碼實現負載均衡五種算法
  1)、輪訓法

/**
 * Title:輪詢
 * Description:
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 15:49 2017/10/26
 */
package com.test.loadbalance;
 
 
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)、加權輪詢法

package com.test.loadbalance;
 
 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Title:
 * Description:加權輪詢
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 18:05 2017/10/26
 */
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).隨機法:

package com.test.loadbalance;
 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Title:
 * Description:隨機
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 18:25 2017/10/26
 */
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)、加權隨機:

package com.test.loadbalance;
 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Title:
 * Description:加權隨機
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 18:42 2017/10/26
 */
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算法:

package com.test.loadbalance;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Title:
 * Description:
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 18:35 2017/10/26
 */
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);
    }
 
}

轉載:https://blog.csdn.net/zhou2s_101216/article/details/78358354 ,僅當筆記用,謝謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章