sofa-rpc負載均衡之隨機算法分析(Random)

注意:咱們分析的sofa-rpc版本是5.4.0。java

                                             圖1 RandomLoadBanlancer的類繼承圖git

1.分析的核心重點

    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類型。算法

2.累加服務提供者的權重

    最開始的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; // 計算全部權重是否同樣
    }
}

3.以totalWeight爲上限的隨機數值逐個減去服務提供者的權重,從而得到服務提供者

    若是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;
        }
    }
}

4.若是全部服務提供者的權重都同樣,則隨機取任意一個服務提供者

    與步驟3並列的還有種狀況,即全部服務提供者的權重都相同,此時步驟2中獲得的isWeightSame爲true,因此進入下面的代碼段,即以服務提供者的個數爲上限,生成一個隨機數,假設爲i,以後以i爲下標,從服務提供者列表中取得服務提供者。spa

else {
    // 若是權重相同或權重爲0則均等隨機
    providerInfo = providerInfos.get(random.nextInt(size));
}

5.思考

    爲何會有步驟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中的代碼。繼承

相關文章
相關標籤/搜索