Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize LeastActiveLoadBalance and add weight test case. #2584

Merged
merged 1 commit into from
Sep 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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());
}
}