diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java index aa6ec12c23c..a3847f4b767 100644 --- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java @@ -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; @@ -41,26 +40,26 @@ protected Invoker doSelect(List> 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 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; } } @@ -72,7 +71,7 @@ protected Invoker doSelect(List> 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]; diff --git a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceTest.java b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceTest.java index 442b1087da6..bdede14a4fa 100644 --- a/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceTest.java +++ b/dubbo-cluster/src/test/java/com/alibaba/dubbo/rpc/cluster/loadbalance/LoadBalanceTest.java @@ -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; @@ -40,7 +40,6 @@ /** * RoundRobinLoadBalanceTest - * */ @SuppressWarnings({"unchecked", "rawtypes"}) public class LoadBalanceTest { @@ -52,6 +51,11 @@ public class LoadBalanceTest { Invoker invoker4; Invoker invoker5; + RpcStatus weightTestRpcStatus1; + RpcStatus weightTestRpcStatus2; + RpcStatus weightTestRpcStatus3; + RpcInvocation weightTestInvocation; + /** * @throws java.lang.Exception */ @@ -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; @@ -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++) { @@ -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())); } } @@ -172,33 +251,74 @@ public Map 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> weightInvokers = new ArrayList>(); + protected Invoker weightInvoker1; + protected Invoker weightInvoker2; + protected Invoker 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()); + } } \ No newline at end of file