先將服務器放進數組或者列表當中,經過JDK的隨機算法,獲取一個在數組有效範圍內的下標,根據這個隨機下標訪問對應服務器。由機率統計理論能夠得知,隨着客戶端調用服務器的次數增多,其實際效果愈來愈接近於平均分配請求到服務器列表中的每一臺服務器。html
代碼:算法
public String random(){
String[] servers = {"server1", "server2", "server3"};
// 將系統的當前時間做爲種子獲取一個隨機器
Random generator = new Random(System.currentTimeMillis());
// 將服務器列表大小做爲上界傳入隨機生成器
int index = generator.nextInt(servers.length);
return servers[index];
}
複製代碼
若是服務器的處理性能有高低的話,這時候就須要加權隨機算法。加權隨機算法也很簡單,主要有兩種形式:數組
一種很簡單的形式是按照服務器的權重,增大服務器列表中的個數。好比服務器A的權重是7,服務器B的權重是3,那麼服務器列表中就添加7個A服務器,添加3個B服務器。這時候進行隨機算法的話,就會有加權的效果了。bash
代碼:服務器
public String weightRandomA(){
// 服務器列表
String[] servers = {"serverA", "serverB"};
// 權重
int[] weights = {7, 3};
List<String> weightServers = new ArrayList<>();
// 根據權重大小往新的權重服務器列表裏重複添加對應的服務器
for (int i = 0; i < servers.length; i++) {
for (int j = 0; j < weights[i]; j++) {
weightServers.add(servers[i]);
}
}
// 將系統的當前時間做爲種子獲取一個隨機器
Random generator = new Random(System.currentTimeMillis());
// 將服務器列表大小做爲上界傳入隨機生成器
int index = generator.nextInt(weightServers.size());
return weightServers.get(index);
}
複製代碼
可是,這邊也會出現一個問題,就是若是權重值很大的時候,權重服務器列表就會過大。另外一種形式是將全部權重值進行相加,而後根據這個總權重值爲隨機數上界,進行隨機抽取服務器。好比A服務器的權重是2,B服務器的權重是3,C服務器的權重是5。總的權重值是10。在10當中取隨機數。若是隨機數0到2之間的話,選擇A服務器,隨機數在3到5之間的話,選擇B服務器,隨機數在5到10之間的話,選擇C服務器。負載均衡
代碼:dom
public String weightRandomB(){
// 服務器列表
String[] servers = {"serverA", "serverB","serverC"};
// 權重
int[] weights = {2, 3, 5};
// 總權重
int totalWeight = 0;
// 計算總權重
for (int weight : weights) {
totalWeight += weight;
}
// 將系統的當前時間做爲種子獲取一個隨機器
Random generator = new Random(System.currentTimeMillis());
// 將總權重做爲上界傳入隨機生成器 獲取一個臨時隨機權重值
int randomWeight = generator.nextInt(totalWeight);
// 服務器列表下標
int index = 0;
// 遞減 隨機權重值 若是小於0的話,表明落入對應區間。根據獲得的下標尋找服務器。
for (int i = 0; i < weights.length; i++) {
randomWeight -= weights[i];
if (randomWeight <= 0) {
index = i;
break;
}
}
return servers[index];
}
複製代碼
隨機算法簡單可行,但不夠均衡,在極端狀況下會形成一臺服務器一直收到請求,另外一個服務器一直沒收到請求。因此這時候就須要輪詢算法。經過依次按順序調用服務器列表中的服務器便可。例如服務器列表中有ABC三臺服務器,一個自增數字,每次自增完取3的餘數,0的話取服務器A,1的話取服務器B,2的話取服務器C便可。性能
代碼:ui
public String roundRobin(){
String[] servers = {"serverA", "serverB", "serverC"};
// 用自增序列值 除 服務器列表的數量
int currentIndex = serialNumber % servers.length;
// 計算出這次服務器列表下標時,對自增序列+1
//(當前使用類變量,實際開發可用Atomic原子變量)
serialNumber++;
return servers[currentIndex];
}
複製代碼
若是考慮到不一樣服務器性能的話,就須要進行加權的輪詢算法。 例如A服務器的權重爲5,B服務器的權重爲3,C服務器的權重爲2。依次添加到服務器列表中,此時服務器列表爲[A,A,A,A,A,B,B,B,C,C]。依次輪詢列表中的服務器便可實現加權輪詢算法。url
代碼:
public String weightRoundRobinA() {
// 服務器列表
String[] servers = {"serverA", "serverB","serverC"};
// 權重
int[] weights = {5, 3, 2};
List<String> weightServers = new ArrayList<>();
// 根據權重大小往新的權重服務器列表裏重複添加對應的服務器
for (int i = 0; i < servers.length; i++) {
for (int j = 0; j < weights[i]; j++) {
weightServers.add(servers[i]);
}
}
// 用自增序列值 除 帶權重服務器列表的數量
int currentIndex = serialNumber % weightServers.size();
// 計算出這次服務器列表下標時,對自增序列+1
//(當前使用類變量,實際開發可用Atomic原子變量)
serialNumber++;
return weightServers.get(currentIndex);
}
複製代碼
這種算法在權重值很大的時候列表會很長,此時能夠取全部權重值的最大公約數,進行累加,落在對應的區間時則取對應的服務器便可。例如服務器A的權重是10,服務器B的權重是3,服務器C的權重是2。取公約數2,使用剛纔的算法,每次自增序列遞增公約數2便可。
上面的加權輪詢算法會致使連續的調用同一臺服務器,此時請求分發顯得很不均衡,老是須要按權重值連續調用完同一臺服務器以後纔會調用接下來的服務器。 這時候就須要平滑加權算法。 假設服務器A配置權重爲7,服務器B的配置權重爲2,服務器配置權重爲1。 總的權重值爲10。平滑加權輪詢的調度以下。每一個服務器的有效權重爲當前權重,與配置權重不一樣,有效權重是根據上一輪再計算出來的結果。每一輪選取權重最大的服務器進行請求。被選取的節點,當前有效權重減去總的權重值。下一輪開始前全部服務器的有效權重加上本身的配置權重。
輪次 | 服務器A | 服務器B | 服務器C | 當前選中服務器(當前權重最大者) |
---|---|---|---|---|
第一輪 | 7 | 2 | 1 | A(當前權重-總權重=-3) |
第二輪 | 4 | 2 | 2 | A(當前權重-總權重=-6) |
第三輪 | 1 | 6 | 3 | B(當前權重-總權重=-4) |
第四輪 | 8 | -2 | 4 | A(當前權重-總權重=-2) |
第五輪 | 5 | 0 | 5 | A(當前權重-總權重=-5) |
第六輪 | 2 | 2 | 6 | C(當前權重-總權重=-4) |
第七輪 | 9 | 4 | -3 | A(當前權重-總權重=-1) |
第八輪 | 6 | 6 | -2 | A(當前權重-總權重=-4) |
第九輪 | 3 | 8 | -1 | B(當前權重-總權重=-2) |
第十輪 | 10 | 0 | 1 | A(當前權重-總權重=0) |
這樣就不會出現連續重複的調用同一個服務器了。
代碼:
public String smoothWeightRouncRobin() {
// 服務器列表
String[] servers = {"serverA", "serverB","serverC"};
// 權重
int[] weights = {7, 2, 1};
// 總權重
int totalWeight = 0;
// 計算總權重
for (int weight : weights) {
totalWeight += weight;
}
int maxWeightIndex = 0;
// currentWeights是一個類變量,保存三個服務器的當前權重
// 尋找當前權重值最大的下標
for (int i = 0; i < currentWeights.length; i++) {
if (currentWeights[i] > currentWeights[maxWeightIndex]) {
maxWeightIndex = i;
}
}
// 當前權重最大者 要減去 總權重
currentWeights[maxWeightIndex] = currentWeights[maxWeightIndex] - totalWeight;
// 依次給每一個服務器加上它的配置權重
for (int i = 0; i < currentWeights.length; i++) {
currentWeights[i] = currentWeights[i] + weights[i];
}
return servers[maxWeightIndex];
}
複製代碼
可用ip地址或者請求的url進行哈希,請求分發到對應的服務器。
最小鏈接數法是根據服務器當前的鏈接狀況進行負載均衡的,當請求到來時,會選取當前鏈接數最少的一臺服務器來處理請求。