常見的負載均衡演算法

2021-08-08 20:00:52 字數 3726 閱讀 1658

前不久公司有個需求是任務需要按照權重分配來選擇,當時就想到負載均衡演算法裡的加權隨機法,因此對常見的負載均衡演算法做個總結。

輪詢就是將請求按順序輪流地分配到後端伺服器上,它均衡地對待後端每一台伺服器,而不關心伺服器實際的連線數和當前的系統負載。

// 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 當第...