注意:咱們分析的sofa-rpc版本是5.4.0。java
圖1 RandomLoadBanlancer的類繼承圖git
RandomLoadBalancer的方法doSelect(SofaRequest,List<ProviderInfo>)是該算法的核心,下面咱們重點來分析該方法的實現。doSelect方法中的源碼以下,建議讀者本身從github上down源碼下來本身看源碼。github
ProviderInfo providerInfo = null; int size = providerInfos.size(); // 總個數 int totalWeight = 0; // 總權重 boolean isWeightSame = true; // 權重是否都同樣 for (int i = 0; i < size; i++) { int weight = getWeight(providerInfos.get(i)); totalWeight += weight; // 累計總權重 if (isWeightSame && i > 0 && weight != getWeight(providerInfos.get(i - 1))) { isWeightSame = false; // 計算全部權重是否同樣 } } if (totalWeight > 0 && !isWeightSame) { int offset = random.nextInt(totalWeight); for (int i = 0; i < size; i++) { offset -= getWeight(providerInfos.get(i)); if (offset < 0) { providerInfo = providerInfos.get(i); break; } } } else { // 若是權重相同或權重爲0則均等隨機 providerInfo = providerInfos.get(random.nextInt(size)); } return providerInfo;
doSelect(SofaRequest,List<ProviderInfo>)的第二個參數List<ProviderInfo>是服務提供者列表信息。ProvideInfo中含有服務提供者的信息,其中有個屬性是weight,表明權重,是int類型。算法
最開始的for循環,看下面的代碼段,循環服務提供者列表,將全部服務提供者的權重累加獲得totalWeight。在循環處理中,若是發現倆個服務提供者的權重不同就將isWeightSame設置爲false。假設服務提供者爲A、B、C、D四個,它們的權重分別是三、二、一、4,因此totalWeight是10;因爲ABCD的權重不相同,因此isWeightSame爲false。dom
for (int i = 0; i < size; i++) { int weight = getWeight(providerInfos.get(i)); totalWeight += weight; // 累計總權重 if (isWeightSame && i > 0 && weight != getWeight(providerInfos.get(i - 1))) { isWeightSame = false; // 計算全部權重是否同樣 } }
若是totalWeight的值大於0且isWeightSame的值爲false。則進入下面的代碼段中,首先以totalWeight爲上限,生成一個隨機正整數,即offset的值。循環服務提供者列表,用offset的值逐個減去每一個服務提供者的權重,若是此時offset的值小於0,則取當前的這個服務提供者。步驟2以後,獲得的totalWeight(值爲10)大於0,且四個服務提供者的權重不相同,因此isWeightSame爲false,因此進入下面代碼段中的邏輯。首先以totalWeight爲上限,生成一個隨機正整數,假設這個生成的隨機正整數爲8,即變量offset的值是8,那麼此時取D做爲服務提供者——8減去3,再減去2,再減去1,以後值爲2,不小於0,再減去4以後的值才小於0。ide
if (totalWeight > 0 && !isWeightSame) { int offset = random.nextInt(totalWeight); for (int i = 0; i < size; i++) { offset -= getWeight(providerInfos.get(i)); if (offset < 0) { providerInfo = providerInfos.get(i); break; } } }
與步驟3並列的還有種狀況,即全部服務提供者的權重都相同,此時步驟2中獲得的isWeightSame爲true,因此進入下面的代碼段,即以服務提供者的個數爲上限,生成一個隨機數,假設爲i,以後以i爲下標,從服務提供者列表中取得服務提供者。spa
else { // 若是權重相同或權重爲0則均等隨機 providerInfo = providerInfos.get(random.nextInt(size)); }
爲何會有步驟3中的考慮,爲何沒有像步驟4中那樣直接隨機從服務提供者列表中取一個?code
解答:Good question! 咱們以步驟2中的A、B、C、D爲例子來解答。如步驟4所示,隨機從服務提供者列表取一個,每個服務提供者被取到的機率是1/4,這種不必定是對的,要分狀況。由於A、B、C、D的權重不一致(分別是三、二、一、4),因此A被取到的機率應該是3/(3+2+1+4),B被取到的機率應該是2(3+2+1+4),C被取到的機率應該是1/(3+2+1+4),D被取到的機率應該是4(3+2+1+4)。因此咱們能夠看出在權重不一致的狀況下,直接隨機從服務提供者列表中取一個的算法是不對,這就是爲何會有步驟3中的代碼。繼承