From a204f6183989f9b96bedc2a7a41b76470938fa7f Mon Sep 17 00:00:00 2001 From: nobodyw-cell <81509671+nobodyw-cell@users.noreply.github.com> Date: Sun, 6 Nov 2022 17:13:52 +0800 Subject: [PATCH] Support consistent hash load balance when gerenic invoke (#10799) --- .../ConsistentHashLoadBalance.java | 11 ++++++-- .../ConsistentHashLoadBalanceTest.java | 28 +++++++++++++++++++ .../loadbalance/LoadBalanceBaseTest.java | 23 +++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java index 15c7066e06..8604def436 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java @@ -28,6 +28,7 @@ import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import static org.apache.dubbo.common.constants.CommonConstants.$INVOKE; import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN; /** @@ -96,15 +97,21 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance { } public Invoker select(Invocation invocation) { - String key = toKey(invocation.getArguments()); + boolean isGeneric = invocation.getMethodName().equals($INVOKE); + String key = toKey(invocation.getArguments(),isGeneric); + byte[] digest = Bytes.getMD5(key); return selectForKey(hash(digest, 0)); } + private String toKey(Object[] args, boolean isGeneric) { + return isGeneric ? toKey((Object[]) args[1]) : toKey(args); + } + private String toKey(Object[] args) { StringBuilder buf = new StringBuilder(); for (int i : argumentIndex) { - if (i >= 0 && i < args.length) { + if (i >= 0 && args != null && i < args.length) { buf.append(args[i]); } } diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalanceTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalanceTest.java index d9b78afd69..6d1381c993 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalanceTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalanceTest.java @@ -33,6 +33,34 @@ import java.util.concurrent.atomic.AtomicLong; @SuppressWarnings("rawtypes") public class ConsistentHashLoadBalanceTest extends LoadBalanceBaseTest { + @Test + public void testConsistentHashLoadBalanceInGenericCall() { + int runs = 10000; + Map genericInvokeCounter = getGenericInvokeCounter(runs, ConsistentHashLoadBalance.NAME); + Map invokeCounter = getInvokeCounter(runs, ConsistentHashLoadBalance.NAME); + + Invoker genericHitted = findHitted(genericInvokeCounter); + Invoker hitted = findHitted(invokeCounter); + + Assertions.assertEquals(hitted, + genericHitted, "hitted should equals to genericHitted"); + } + + private Invoker findHitted(Map invokerCounter) { + Invoker invoker = null; + + for (Map.Entry entry : invokerCounter.entrySet()) { + if (entry.getValue().longValue() > 0) { + invoker = entry.getKey(); + break; + } + } + + Assertions.assertNotNull(invoker,"invoker should be found"); + + return null; + } + @Test public void testConsistentHashLoadBalance() { int runs = 10000; diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/LoadBalanceBaseTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/LoadBalanceBaseTest.java index c96c0fc391..cab69a1302 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/LoadBalanceBaseTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/LoadBalanceBaseTest.java @@ -48,6 +48,7 @@ import static org.mockito.Mockito.mock; @SuppressWarnings({"unchecked", "rawtypes"}) public class LoadBalanceBaseTest { Invocation invocation; + Invocation genericInvocation; List> invokers = new ArrayList>(); Invoker invoker1; Invoker invoker2; @@ -79,6 +80,14 @@ public class LoadBalanceBaseTest { given(invocation.getMethodName()).willReturn("method1"); given(invocation.getArguments()).willReturn(new Object[] {"arg1","arg2","arg3"}); + genericInvocation = mock(Invocation.class); + String methodName = "method1"; + given(genericInvocation.getMethodName()).willReturn("$invoke"); + String[] paraTypes = new String[] {String.class.getName(),String.class.getName(),String.class.getName()}; + Object[] argsObject = new Object[] {"arg1","arg2","arg3"}; + Object[] args = new Object[] {methodName,paraTypes,argsObject}; + given(genericInvocation.getArguments()).willReturn(args); + invoker1 = mock(Invoker.class); invoker2 = mock(Invoker.class); invoker3 = mock(Invoker.class); @@ -132,6 +141,20 @@ public class LoadBalanceBaseTest { return counter; } + public Map getGenericInvokeCounter(int runs, String loadbalanceName) { + Map counter = new ConcurrentHashMap(); + LoadBalance lb = getLoadBalance(loadbalanceName); + for (Invoker invoker : invokers) { + counter.put(invoker, new AtomicLong(0)); + } + URL url = invokers.get(0).getUrl(); + for (int i = 0; i < runs; i++) { + Invoker sinvoker = lb.select(invokers, url, genericInvocation); + counter.get(sinvoker).incrementAndGet(); + } + return counter; + } + protected AbstractLoadBalance getLoadBalance(String loadbalanceName) { return (AbstractLoadBalance) ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName); }