負載均衡(LoadBalance),它的職責是將網絡請求,或者其他形式的負載“均攤”到不同的機器上。避免集群中部分服務器壓力過大,而另一些服務器比較空閑的情況。通過負載均衡,可以讓每台服務器獲取到適合自己處理能力的請求。
常見的負載均衡的實現方法有多種,如隨機、輪詢、hash一致性等。本文使用隨機法實現負載均衡。
隨機數法就是幾個數中隨機獲取一個數字,然后獲取這個數據對應的服務器。
/**
* 服務器類
*/
public class Server {
private String serverName;
public Server(String name) {
this.serverName = name;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
@Override
public String toString() {
return "Server{serverName:"+this.getServerName()+"}";
}
}
public class LoadBalance_Random {
//用來存放所有的服務器
static List<Server> ServerList = new ArrayList<Server>();
//隨機數生成器
private static final Random r = new Random();
//初始化 模擬集群中提供服務的服務器
static{
Server server1 = new Server("server1");
Server server2 = new Server("server2");
Server server3 = new Server("server3");
ServerList.add(server1);
ServerList.add(server2);
ServerList.add(server3);
}
public static void main(String[] args) {
//模擬10個請求來獲取對應的服務器
for(int i=0;i<10;i++){
Server server_random = doSelect(ServerList);
System.out.println(server_random);
}
}
/**
* 選擇服務器
* @param serverList
* @return
*/
private static Server doSelect(List<Server> serverList) {
Server server = null;
//服務器的個數
int serverNum = serverList.size();
//隨機獲取一個
int serverIndex = r.nextInt(serverNum);
server = serverList.get(serverIndex);
return server;
}
}
執行main方法測試,結果如下:

在每台服務器的配置性能等各方面都一樣時,使用這種隨機方法也是可取的,因為每台服務器獲取的要處理的請求的數據量的概率是一樣的。但是有時候,我們的服務器不一定都是相同的配置,每一台服務器的性能都有一定的差異性,導致服務器提供服務的能力的差異,比如上邊我們有3台服務器,Server1每秒可處理5個請求,Server2每秒只能處理3個請求,Server3每秒只能處理2個請求,此時如果我們有10個請求過來了,我們分別給3個Server3個請求處理,由於Server3只能處理2個請求,這時就會導致服務3不可用。
對這種不同服務能力的服務實現負載均衡,我們可以使用加權隨機法。對每個服務標記權重,提高處理能力強的服務器的權重,降低服務能力若的服務器的權重,即根據能力的大小分配對應比例的請求數。
修改上述代碼,給服務加權重
/**
* 服務器類
*/
public class Server {
private String serverName;
private int weight;//權重
public Server(String name, int weight) {
this.serverName = name;
this.weight = weight;
}
@Override
public String toString() {
return "Server{serverName:"+this.getServerName()+",weight:"+this.getWeight()+"}";
}
// 省略getter 和 setter方法
}
初始化時指定服務器的權重
//初始化 模擬集群中提供服務的服務器
static{
Server server1 = new Server("server1", 5);
Server server2 = new Server("server2", 3);
Server server3 = new Server("server3", 2);
ServerList.add(server1);
ServerList.add(server2);
ServerList.add(server3);
}
根據權重值獲取服務
private static Server doSelectWithWeight(List<Server> serverList) {
Server server = null;
int totalWeight = 0; //所有服務器的總權重
boolean isSame = true;//默認所有服務器的權重都相同
for(int i=0; i<serverList.size(); i++){
//獲取當前服務器得權重
int serverWeight = serverList.get(i).getWeight();
//權重累加
totalWeight = totalWeight + serverWeight;
//i = 0時默認還是權重都一樣
//從第二個開始檢測每個服務器得權重是不是都一樣,只需要與它得前一個服務得權重相比就可以了
if(isSame && i>0){
int preServerWeight = serverList.get(i-1).getWeight();
if(serverWeight != preServerWeight){//當前服務器權重和前一個服務器得權重不相同
isSame = false;
}
}
}
if(!isSame){//服務器得權重不是都一樣
//在總權重下獲取一個隨機數
int index = r.nextInt(totalWeight);
//
for(int i=0;i<serverList.size();i++){
int serverWeight = serverList.get(i).getWeight();
//判斷獲取得隨機數落在總權重得哪一個區間
//3台服務器得得權重分別為5 3 2 總和為10 [0到5)這個區間屬於服務器1 [5到8)這個區間屬於服務器2 【8到10)這個區間屬於服務器3
//如 獲取到得隨機數是6 6-5=1 大於0 說明不在服務器1得區間,遍歷 1-3= -2 小於0 說明它落在了服務器2所在得區間 就可以得對應服務器
index = index - serverWeight;
if(index < 0){
return serverList.get(i);
}
}
}else{
//所有服務器權重都一樣時,按照完全隨機法隨機獲取一個服務器
server = doSelect(serverList);
}
return server;
}
使用main方法測試
public static void main(String[] args) {
//模擬20個請求獲取對應的服務
for(int i=0;i<20;i++){
Server server_random_weight = doSelectWithWeight(ServerList);
System.out.println(server_random_weight);
}
}
測試結果如下

從測試結果圖中可以看到,權重大的獲取到的請求數多,相反權重小的獲取到的請求數越小。
