接上一篇博文:負載均衡算法–平滑加權輪詢法(Smooth Weight Round Robin)。接下來介紹源地址哈希法。
源地址哈希法是根據請求來源的地址,通過哈希函數計算得到的一個數值,用該數值對服務器列表的大小進行取模運算,得到的結果便是客服端要訪問服務器的序號。採用源地址哈希法進行負載均衡,同一源地址的請求,當服務器列表不變時,它每次都會映射到同一臺服務器進行訪問。
算法描述
假設有 N 臺服務器 S = {S0, S1, S2, …, Sn-1},算法可以描述爲:
1、通過指定的哈希函數,計算請求來源的地址的哈希值
2、對哈希值進行求餘,底數爲 N
3、將餘數作爲索引值,從 S 中獲取對應的服務器;
假定我們現在有如下四臺服務器:
服務器地址 | 權重 |
---|---|
192.168.1.1 | 1 |
192.168.1.2 | 2 |
192.168.1.3 | 3 |
192.168.1.4 | 4 |
源地址哈希法與權重沒有關係,只與源地址有關。
代碼實現
1、服務器管理類
package org.learn.loadbalance;
import java.util.Map;
import java.util.TreeMap;
/**
* @author zhibo
* @date 2019/5/16 16:25
*/
public class ServerManager {
public volatile static Map<String, Integer> serverMap = new TreeMap<>();
static {
serverMap.put("192.168.1.1", 1);
serverMap.put("192.168.1.2", 2);
serverMap.put("192.168.1.3", 3);
serverMap.put("192.168.1.4", 4);
}
}
2、源地址哈希類
package org.learn.loadbalance;
import java.util.ArrayList;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author zhibo
* @date 2019/5/16 16:28
*/
public class HashBalance {
public static String getServer(String sourceIp) {
if(sourceIp == null){
return "";
}
Set<String> serverSet = ServerManager.serverMap.keySet();
ArrayList<String> serverList = new ArrayList<>(serverSet);
Integer index = sourceIp.hashCode() % serverList.size();
return serverList.get(index);
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
String server = getServer("ip" + new Random().nextInt(1000));
System.out.println(server);
}
}
}
執行 main 方法輸出結果如下:
優點:
源地址哈希法可以保證,只要請求源地址不變,總會請求到相同的目標服務器。在早些時候進行 Web 開發時,是基於 Session 進行用戶鑑權的,用戶登錄後,會在登錄時的服務器A的 Session 中設置用戶信息,如果下一次請求被分配到服務器B上,那麼此時因 Session 中沒有用戶信息而報錯。在這種場景下一般會使用源地址哈希法進行負載均衡,保證用戶每次都可以訪問到 Session 信息。當然現在的一般不會使用 Session 進行鑑權了,大都採用 redis、memcached 等緩存服務來解決 Session 不共享的問題。
缺點:
源地址哈希法可以保證,只要請求源地址不變,總會請求到相同的目標服務器。這樣會帶來兩個問題:
1、由於用戶的活躍度不同,可能會有大量的活躍用戶被哈希到相同的服務器上,造成該服務器特別繁忙,大量的非活躍用戶被哈希到相同的服務器上,造成該服務器幾乎沒有請求,造成請求不均衡。
2、一旦某個服務器掛掉,那麼哈希到該服務器的所有源請求都會失敗,直到服務恢復或者服務器列表中去掉該服務器。
文章內容僅代表個人觀點,如有不正之處,歡迎批評指正,謝謝大家。