輪詢(Round Robin)法
輪詢調度算法的原理是每一次把來自用戶的請求輪流分配給內部中的服務器,從1開始,直到N(內部服務器個數),然後重新開始循環。算法的優點是其簡潔性,它無需記錄當前所有連接的狀態,所以它是一種無狀態調度。
其代碼實現大致如下:
import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import java.util.Set;/** * @author [email protected] * @date 二月 07, 2017 */class RoundRobin { private static Integer pos = 0; public static String getServer() { // 重建一個Map,避免服務器的上下線導致的併發問題 Map<String, Integer> serverMap = new HashMap<String, Integer>(); serverMap.putAll(IpMap.serverWeightMap); // 取得Ip地址List Set<String> keySet = serverMap.keySet(); ArrayList<String> keyList = new ArrayList<String>(); keyList.addAll(keySet); String server = null; synchronized (pos) { if (pos > keySet.size()) pos = 0; server = keyList.get(pos); pos ++; } return server; } }
由於serverWeightMap中的地址列表是動態的,隨時可能有機器上線、下線或者宕機,因此爲了避免可能出現的併發問題,方法內部要新建局部變量serverMap,現將serverMap中的內容複製到線程本地,以避免被多個線程修改。這樣可能會引入新的問題,複製以後serverWeightMap的修改無法反映給serverMap,也就是說這一輪選擇服務器的過程中,新增服務器或者下線服務器,負載均衡算法將無法獲知。新增無所謂,如果有服務器下線或者宕機,那麼可能會訪問到不存在的地址。因此,服務調用端需要有相應的容錯處理,比如重新發起一次server選擇並調用。
對於當前輪詢的位置變量pos,爲了保證服務器選擇的順序性,需要在操作時對其加鎖,使得同一時刻只能有一個線程可以修改pos的值,否則當pos變量被併發修改,則無法保證服務器選擇的順序性,甚至有可能導致keyList數組越界。
輪詢法的優點在於:試圖做到請求轉移的絕對均衡。
輪詢法的缺點在於:爲了做到請求轉移的絕對均衡,必須付出相當大的代價,因爲爲了保證pos變量修改的互斥性,需要引入重量級的悲觀鎖synchronized,這將會導致該段輪詢代碼的併發吞吐量發生明顯的下降。
隨機(Random)法
通過系統的隨機算法,根據後端服務器的列表大小值來隨機選取其中的一臺服務器進行訪問。由概率統計理論可以得知,隨着客戶端調用服務端的次數增多,
其實際效果越來越接近於平均分配調用量到後端的每一臺服務器,也就是輪詢的結果。
隨機法的代碼實現大致如下:
import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import java.util.Set;/** * @author [email protected] * @date 二月 07, 2017 */ class Random { public static String getServer() { // 重建一個Map,避免服務器的上下線導致的併發問題 Map<String, Integer> serverMap = new HashMap<String, Integer>(); serverMap.putAll(IpMap.serverWeightMap); // 取得Ip地址List Set<String> keySet = serverMap.keySet(); ArrayList<String> keyList = new ArrayList<String>(); keyList.addAll(keySet); java.util.Random random = new java.util.Random(); int randomPos = random.nextInt(keyList.size()); return keyList.get(randomPos); } }
整體代碼思路和輪詢法一致,先重建serverMap,再獲取到server列表。在選取server的時候,通過Random的nextInt方法取0~keyList.size()區間的一個隨機值,從而從服務器列表中隨機獲取到一臺服務器地址進行返回。基於概率統計的理論,吞吐量越大,隨機算法的效果越接近於輪詢算法的效果。