Skip to content

Commit

Permalink
Optimize LeastActiveLoadBalance and add weight test case. (#2584)
Browse files Browse the repository at this point in the history
  • Loading branch information
carryxyh committed Sep 29, 2018
1 parent 0ac21f0 commit 28e1037
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 26 deletions.
Expand Up @@ -16,7 +16,6 @@
*/
package com.alibaba.dubbo.rpc.cluster.loadbalance;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
Expand All @@ -41,26 +40,26 @@ protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation
int leastActive = -1; // The least active value of all invokers
int leastCount = 0; // The number of invokers having the same least active value (leastActive)
int[] leastIndexs = new int[length]; // The index of invokers having the same least active value (leastActive)
int totalWeight = 0; // The sum of weights
int totalWeight = 0; // The sum of with warmup weights
int firstWeight = 0; // Initial value, used for comparision
boolean sameWeight = true; // Every invoker has the same weight value?
for (int i = 0; i < length; i++) {
Invoker<T> invoker = invokers.get(i);
int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); // Active number
int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT); // Weight
int afterWarmup = getWeight(invoker, invocation); // Weight
if (leastActive == -1 || active < leastActive) { // Restart, when find a invoker having smaller least active value.
leastActive = active; // Record the current least active value
leastCount = 1; // Reset leastCount, count again based on current leastCount
leastIndexs[0] = i; // Reset
totalWeight = weight; // Reset
firstWeight = weight; // Record the weight the first invoker
totalWeight = afterWarmup; // Reset
firstWeight = afterWarmup; // Record the weight the first invoker
sameWeight = true; // Reset, every invoker has the same weight value?
} else if (active == leastActive) { // If current invoker's active value equals with leaseActive, then accumulating.
leastIndexs[leastCount++] = i; // Record index number of this invoker
totalWeight += weight; // Add this invoker's weight to totalWeight.
totalWeight += afterWarmup; // Add this invoker's weight to totalWeight.
// If every invoker has the same weight?
if (sameWeight && i > 0
&& weight != firstWeight) {
&& afterWarmup != firstWeight) {
sameWeight = false;
}
}
Expand All @@ -72,7 +71,7 @@ protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation
}
if (!sameWeight && totalWeight > 0) {
// If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
int offsetWeight = random.nextInt(totalWeight);
int offsetWeight = random.nextInt(totalWeight) + 1;
// Return a invoker based on the random value.
for (int i = 0; i < leastCount; i++) {
int leastIndex = leastIndexs[i];
Expand Down
Expand Up @@ -21,9 +21,9 @@
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcInvocation;
import com.alibaba.dubbo.rpc.RpcStatus;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;

import junit.framework.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
Expand All @@ -40,7 +40,6 @@

/**
* RoundRobinLoadBalanceTest
*
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class LoadBalanceTest {
Expand All @@ -52,6 +51,11 @@ public class LoadBalanceTest {
Invoker<LoadBalanceTest> invoker4;
Invoker<LoadBalanceTest> invoker5;

RpcStatus weightTestRpcStatus1;
RpcStatus weightTestRpcStatus2;
RpcStatus weightTestRpcStatus3;
RpcInvocation weightTestInvocation;

/**
* @throws java.lang.Exception
*/
Expand Down Expand Up @@ -117,6 +121,81 @@ public void testRoundRobinLoadBalance_select() {
}
}

@Test
public void testSelectByWeightLeastActive() {
int sumInvoker1 = 0;
int sumInvoker2 = 0;
int loop = 10000;
LeastActiveLoadBalance lb = new LeastActiveLoadBalance();
for (int i = 0; i < loop; i++) {
Invoker selected = lb.select(weightInvokers, null, weightTestInvocation);
if (selected.getUrl().getProtocol().equals("test1")) {
sumInvoker1++;
}
if (selected.getUrl().getProtocol().equals("test2")) {
sumInvoker2++;
}
// never select invoker3 because it's active is more than invoker1 and invoker2
Assert.assertTrue("select is not the least active one", !selected.getUrl().getProtocol().equals("test3"));
}
// the sumInvoker1 : sumInvoker2 approximately equal to 1: 9
System.out.println(sumInvoker1);
System.out.println(sumInvoker2);
Assert.assertEquals("select failed!", sumInvoker1 + sumInvoker2, loop);
}

@Test
public void testSelectByWeightRandom() {
int sumInvoker1 = 0;
int sumInvoker2 = 0;
int sumInvoker3 = 0;
int loop = 10000;
RandomLoadBalance lb = new RandomLoadBalance();
for (int i = 0; i < loop; i++) {
Invoker selected = lb.select(weightInvokers, null, weightTestInvocation);
if (selected.getUrl().getProtocol().equals("test1")) {
sumInvoker1++;
}
if (selected.getUrl().getProtocol().equals("test2")) {
sumInvoker2++;
}
if (selected.getUrl().getProtocol().equals("test3")) {
sumInvoker3++;
}
}
// 1 : 9 : 6
System.out.println(sumInvoker1);
System.out.println(sumInvoker2);
System.out.println(sumInvoker3);
Assert.assertEquals("select failed!", sumInvoker1 + sumInvoker2 + sumInvoker3, loop);
}

@Test
public void testSelectByWeight() {
int sumInvoker1 = 0;
int sumInvoker2 = 0;
int sumInvoker3 = 0;
int loop = 10000;
RoundRobinLoadBalance lb = new RoundRobinLoadBalance();
for (int i = 0; i < loop; i++) {
Invoker selected = lb.select(weightInvokers, null, weightTestInvocation);
if (selected.getUrl().getProtocol().equals("test1")) {
sumInvoker1++;
}
if (selected.getUrl().getProtocol().equals("test2")) {
sumInvoker2++;
}
if (selected.getUrl().getProtocol().equals("test3")) {
sumInvoker3++;
}
}
// 1 : 9 : 6
System.out.println(sumInvoker1);
System.out.println(sumInvoker2);
System.out.println(sumInvoker3);
Assert.assertEquals("select failed!", sumInvoker1 + sumInvoker2 + sumInvoker3, loop);
}

@Test
public void testRandomLoadBalance_select() {
int runs = 1000;
Expand All @@ -125,7 +204,7 @@ public void testRandomLoadBalance_select() {
Long count = counter.get(minvoker).get();
// System.out.println(count);
Assert.assertTrue("abs diff shoud < avg",
Math.abs(count - runs / (0f + invokers.size())) < runs / (0f + invokers.size()));
Math.abs(count - runs / (0f + invokers.size())) < runs / (0f + invokers.size()));
}

for (int i = 0; i < 5; i++) {
Expand All @@ -152,7 +231,7 @@ public void testLeastActiveLoadBalance_select() {
Long count = counter.get(minvoker).get();
// System.out.println(count);
Assert.assertTrue("abs diff shoud < avg",
Math.abs(count - runs / (0f + invokers.size())) < runs / (0f + invokers.size()));
Math.abs(count - runs / (0f + invokers.size())) < runs / (0f + invokers.size()));
}
}

Expand All @@ -172,33 +251,74 @@ public Map<Invoker, AtomicLong> getInvokeCounter(int runs, String loadbalanceNam
@Test
public void testLoadBalanceWarmup() {
Assert.assertEquals(1,
AbstractLoadBalance.calculateWarmupWeight(0, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
AbstractLoadBalance.calculateWarmupWeight(0, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(1,
AbstractLoadBalance.calculateWarmupWeight(13, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
AbstractLoadBalance.calculateWarmupWeight(13, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(1,
AbstractLoadBalance.calculateWarmupWeight(6 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
AbstractLoadBalance.calculateWarmupWeight(6 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(2,
AbstractLoadBalance.calculateWarmupWeight(12 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
AbstractLoadBalance.calculateWarmupWeight(12 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(10,
AbstractLoadBalance.calculateWarmupWeight(60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
AbstractLoadBalance.calculateWarmupWeight(60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(50, AbstractLoadBalance
.calculateWarmupWeight(5 * 60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(5 * 60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(50, AbstractLoadBalance
.calculateWarmupWeight(5 * 60 * 1000 + 23, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(5 * 60 * 1000 + 23, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(50, AbstractLoadBalance
.calculateWarmupWeight(5 * 60 * 1000 + 5999, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(5 * 60 * 1000 + 5999, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(51, AbstractLoadBalance
.calculateWarmupWeight(5 * 60 * 1000 + 6000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(5 * 60 * 1000 + 6000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(90, AbstractLoadBalance
.calculateWarmupWeight(9 * 60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(9 * 60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(98, AbstractLoadBalance
.calculateWarmupWeight(10 * 60 * 1000 - 12 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(10 * 60 * 1000 - 12 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(99, AbstractLoadBalance
.calculateWarmupWeight(10 * 60 * 1000 - 6 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(10 * 60 * 1000 - 6 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(100, AbstractLoadBalance
.calculateWarmupWeight(10 * 60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(10 * 60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
Assert.assertEquals(100, AbstractLoadBalance
.calculateWarmupWeight(20 * 60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
.calculateWarmupWeight(20 * 60 * 1000, Constants.DEFAULT_WARMUP, Constants.DEFAULT_WEIGHT));
}

/*------------------------------------test invokers for weight---------------------------------------*/

protected List<Invoker<LoadBalanceTest>> weightInvokers = new ArrayList<Invoker<LoadBalanceTest>>();
protected Invoker<LoadBalanceTest> weightInvoker1;
protected Invoker<LoadBalanceTest> weightInvoker2;
protected Invoker<LoadBalanceTest> weightInvoker3;

@Before
public void before() throws Exception {
weightInvoker1 = mock(Invoker.class);
weightInvoker2 = mock(Invoker.class);
weightInvoker3 = mock(Invoker.class);
weightTestInvocation = new RpcInvocation();
weightTestInvocation.setMethodName("test");
URL url1 = URL.valueOf("test1://0:1/DemoService");
url1 = url1.addParameter(Constants.WEIGHT_KEY, 1);
url1 = url1.addParameter(weightTestInvocation.getMethodName() + "." + Constants.WEIGHT_KEY, 1);
url1 = url1.addParameter("active", 0);
URL url2 = URL.valueOf("test2://0:9/DemoService");
url2 = url2.addParameter(Constants.WEIGHT_KEY, 9);
url2 = url2.addParameter(weightTestInvocation.getMethodName() + "." + Constants.WEIGHT_KEY, 9);
url2 = url2.addParameter("active", 0);
URL url3 = URL.valueOf("test3://1:6/DemoService");
url3 = url3.addParameter(Constants.WEIGHT_KEY, 6);
url3 = url3.addParameter(weightTestInvocation.getMethodName() + "." + Constants.WEIGHT_KEY, 6);
url3 = url3.addParameter("active", 1);
given(weightInvoker1.isAvailable()).willReturn(true);
given(weightInvoker1.getUrl()).willReturn(url1);
given(weightInvoker2.isAvailable()).willReturn(true);
given(weightInvoker2.getUrl()).willReturn(url2);
given(weightInvoker3.isAvailable()).willReturn(true);
given(weightInvoker3.getUrl()).willReturn(url3);
weightInvokers.add(weightInvoker1);
weightInvokers.add(weightInvoker2);
weightInvokers.add(weightInvoker3);
weightTestRpcStatus1 = RpcStatus.getStatus(weightInvoker1.getUrl(), weightTestInvocation.getMethodName());
weightTestRpcStatus2 = RpcStatus.getStatus(weightInvoker2.getUrl(), weightTestInvocation.getMethodName());
weightTestRpcStatus3 = RpcStatus.getStatus(weightInvoker3.getUrl(), weightTestInvocation.getMethodName());
// weightTestRpcStatus3 active is 1
RpcStatus.beginCount(weightInvoker3.getUrl(), weightTestInvocation.getMethodName());
}
}

0 comments on commit 28e1037

Please sign in to comment.