前不久公司有個需求是任務需要按照權重分配來選擇,當時就想到負載均衡演算法裡的加權隨機法,因此對常見的負載均衡演算法做個總結。
輪詢就是將請求按順序輪流地分配到後端伺服器上,它均衡地對待後端每一台伺服器,而不關心伺服器實際的連線數和當前的系統負載。
// serverweightmap 表示伺服器位址和權重的對映
mapserverweightmap = new hashmap<>();
serverweightmap.put("192.168.1.100", 1);
serverweightmap.put("192.168.1.101", 1);
// 權重為 4
serverweightmap.put("192.168.1.102", 4);
serverweightmap.put("192.168.1.103", 1);
serverweightmap.put("192.168.1.104", 1);
// 權重為 3
serverweightmap.put("192.168.1.105", 3);
serverweightmap.put("192.168.1.106", 1);
// 權重為 2
serverweightmap.put("192.168.1.107", 2);
serverweightmap.put("192.168.1.108", 1);
serverweightmap.put("192.168.1.109", 1);
serverweightmap.put("192.168.1.110", 1);
public
static string testroundrobin()
server = keylist.get(pos);
pos++;
}return server;
}
由於 serverweightmap 中的位址列表是動態的,隨時可能有機器上線、下線或者宕機,因此為了避免可能出現的併發問題,如陣列越界,通過新建方法內的區域性變數 servermap,先將域變數複製到執行緒本地,避免對多個執行緒修改。這樣會引入新的問題,複製以後 serverweightmap 的修改將無法反應給 servermap,也就是說,在這一輪選擇伺服器的過程中,新增伺服器或者下線伺服器,負載均衡演算法中將無法獲知。新增比較好處理,而當伺服器下線或者宕機時,服務消費者將有可能訪問到不存在的位址。因此,在服務消費者的實現端需要考慮該問題,並且進行相應的容錯處理,比如重新發起一次呼叫。
對於當前輪詢的位置變數 pos,為了保證伺服器選擇的順序性,需要在操作時對其加上 synchronized 鎖,使得在同一時刻只有乙個執行緒能夠修改 pos 的值,否則當 pos 變數被併發修改時,則無法保證伺服器選擇的順序性,甚至有可能導致 keylist 陣列越界。
使用輪詢策略的目的在於,希望做到請求轉移的絕對平衡,但付出的效能代價也是相當大的。為了 pos 保證變數的互斥性,需要引入重量級的悲觀鎖 synchronized,將會導致該段輪詢**的併發吞吐量發生明顯的下降。
通過系統隨機函式,根據後端伺服器列表的大小值來隨機選取其中一台進行訪問。由概率統計理論可以得知,隨著呼叫量的增大,其實際效果越來越接近於平均分配流量到每一台後端伺服器,也就是輪詢的效果。
public
static string testrandom()
跟前面類似,為了避免可能的併發問題,需要將 serverweightmap 複製到 servermap 中。通過 random 的 nextint 方法,取到在 0~keylist.size() 區間的乙個隨機值,從而從伺服器列表中隨機獲取到一台伺服器位址,進行返回。基於概率統計的理論,吞吐量越大,隨機演算法的效果越接近於輪詢演算法的效果。因此,基本可以替代輪詢演算法。
源位址雜湊的思想是獲取客戶端訪問的 ip 位址值,通過雜湊函式計算得到乙個數值,用該數值對伺服器列表的大小進行取模運算,得到的結果邊是要訪問的伺服器的序號。採用雜湊法進行負載均衡,同一 ip 位址的客戶端,當後端伺服器列表不變時,它每次都會對映到同一台後端伺服器進行訪問。
public
static string testconsumerhash(string remoteip)
通過引數傳入的客戶端 remoteip 引數,取得它的雜湊值,對伺服器列表的大小取模,結果便是選用的伺服器在伺服器列表中的索引值。該演算法保證了相同的客戶端 ip 位址將會被「雜湊」到同一台後端伺服器,直到後端伺服器列表變更。根據此特性可以在服務消費者與服務提供者之間建立有狀態的 session 會話。
不同的後端伺服器可能機器的配置和當前系統的負載並不相同,因此它們的抗壓能力也不盡相同。給配置高、負載低的機器配置更高的權重,讓其處理更多的請求,而低配置、負載高的機器,則給其分配較低的權重,降低其系統負載,加權輪詢能很好地處理這一問題,並將請求順序且按照權重分配到後端。
public
static string testweightroundrobin()
}string server = null;
integer pos = 0;
synchronized (pos)
server += serverlist.get(pos);
pos++;
}return server;
}
與輪詢演算法類似,只是在獲取伺服器位址之前增加了一段權重計算的**,根據權重的大小,將位址重複地增加到伺服器位址列表中,權重越大,該伺服器每輪所獲得的請求數量越多。
與加權輪詢法類似,加權隨機法也根據後端伺服器不同的配置和負載情況,配置不同的權重。不同的是,它是按照權重來隨機選取伺服器的,而非順序。
/**
* 實現方法一
*/public
static string testweightrandom()
}random random = new random();
int randompos = random.nextint(serverlist.size());
string server = serverlist.get(randompos);
return server;
}/**
* 實現方法二
*/public
static string testweightrandom()
// 產生隨機數
long random = math.round(math.random() * weightsum);
long weight = 0;
for (string server : servermap.keyset())
}return servermap.keyset().iterator().next();
}
我們費盡心思來實現服務消費者請求次數分配的均衡,我們知道這樣做是沒錯的,可以為後端的多台伺服器平均分配工作量,最大程度地提高伺服器的利用率,但是,實際情況真的如此嗎?在實際情況中,請求次數的均衡真的能代表負載的均衡嗎?我們必須認真地思考這個問題。從演算法實施的角度來看,以後端伺服器的視角來觀察系統的負載,而非請求發起方來觀察。因此,我們得有其它的演算法來實現可供選擇,最小連線數法便屬於此類演算法。
最小連線數演算法比較靈活和智慧型,由於後端伺服器的配置不盡相同,對於請求的處理有快有慢,它正是根據後端伺服器當前的連線情況,動態地選取其中當前積壓連線數最小的一台伺服器來處理當前請求,盡可能地提高後端伺服器的利用效率,將負載合理地分流到每一台機器。由於最小連線數涉及伺服器連線數的彙總和感知,設計與實現比較繁瑣。
常見負載均衡演算法
隨著系統日益龐大 邏輯業務越來越複雜,系統架構由原來的單一系統到垂直系統,發展到現在的分布式系統。分布式系統中,可以做到公共業務模組的高可用,高容錯性,高擴充套件性,然而,當系統越來越複雜時,需要考慮的東西自然也越來越多,要求也越來越高,比如服務路由 負載均衡等。此文將針對負載均衡演算法進行講解,不...
常見負載均衡演算法
輪詢很容易實現,將請求按順序輪流分配到後台伺服器上,均衡的對待每一台伺服器,而不關心伺服器實際的連線數和當前的系統負載。這裡通過例項化乙個serviceweightmap的map變數來伺服器位址和權重的對映,以此來模擬輪詢演算法的實現,其中設定的權重值在以後的加權演算法中會使用到,這裡先不做過多介紹...
常見負載均衡演算法
輪詢法是負載均衡中最常用的演算法,它容易理解也容易實現。輪詢法是指負載均衡伺服器 load balancer 將客戶端請求按順序輪流分配到後端伺服器上,以達到負載均衡的目的。假設現在有6個客戶端請求,2台後端伺服器。當第乙個請求到達負載均衡伺服器時,負載均衡伺服器會將這個請求分派到後端伺服器1 當第...