Support consistent hash load balance when gerenic invoke (#10799)
This commit is contained in:
parent
b319fce427
commit
a204f61839
|
|
@ -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<T> 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]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Invoker, AtomicLong> genericInvokeCounter = getGenericInvokeCounter(runs, ConsistentHashLoadBalance.NAME);
|
||||
Map<Invoker, AtomicLong> 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<Invoker,AtomicLong> invokerCounter) {
|
||||
Invoker invoker = null;
|
||||
|
||||
for (Map.Entry<Invoker,AtomicLong> 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;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import static org.mockito.Mockito.mock;
|
|||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class LoadBalanceBaseTest {
|
||||
Invocation invocation;
|
||||
Invocation genericInvocation;
|
||||
List<Invoker<LoadBalanceBaseTest>> invokers = new ArrayList<Invoker<LoadBalanceBaseTest>>();
|
||||
Invoker<LoadBalanceBaseTest> invoker1;
|
||||
Invoker<LoadBalanceBaseTest> 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<Invoker, AtomicLong> getGenericInvokeCounter(int runs, String loadbalanceName) {
|
||||
Map<Invoker, AtomicLong> counter = new ConcurrentHashMap<Invoker, AtomicLong>();
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue