瀏覽代碼

Fix sentinel-apache-dubbo-adapter full GC bug (#1431)

master
Lin.Liang GitHub 4 年之前
父節點
當前提交
5d439adf60
沒有發現已知的金鑰在資料庫的簽署中 GPG 金鑰 ID: 4AEE18F83AFDEB23
共有 9 個檔案被更改,包括 413 行新增265 行删除
  1. +19
    -50
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java
  2. +7
    -2
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtils.java
  3. +73
    -18
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java
  4. +32
    -8
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java
  5. +27
    -38
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java
  6. +80
    -0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/DubboTestUtil.java
  7. +23
    -5
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java
  8. +130
    -121
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java
  9. +22
    -23
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java

+ 19
- 50
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java 查看文件

@@ -16,13 +16,9 @@
package com.alibaba.csp.sentinel.adapter.dubbo; package com.alibaba.csp.sentinel.adapter.dubbo;




import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.context.ContextUtil;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;


/** /**
* Base Class of the {@link SentinelDubboProviderFilter} and {@link SentinelDubboConsumerFilter}. * Base Class of the {@link SentinelDubboProviderFilter} and {@link SentinelDubboConsumerFilter}.
@@ -30,52 +26,25 @@ import org.apache.dubbo.rpc.*;
* @author Zechao Zheng * @author Zechao Zheng
*/ */


public abstract class BaseSentinelDubboFilter extends ListenableFilter {
public BaseSentinelDubboFilter() {
this.listener = new SentinelDubboListener();
}
public abstract class BaseSentinelDubboFilter implements Filter {


static class SentinelDubboListener implements Listener {


public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
onSuccess(appResponse, invoker);
}
/**
* Get method name of dubbo rpc
*
* @param invoker
* @param invocation
* @return
*/
abstract String getMethodName(Invoker invoker, Invocation invocation);


//for compatible dubbo 2.7.5 rename onResponse to onMessage
public void onMessage(Result appResponse, Invoker<?> invoker, Invocation invocation) {
onSuccess(appResponse, invoker);
}
/**
* Get interface name of dubbo rpc
*
* @param invoker
* @return
*/
abstract String getInterfaceName(Invoker invoker);


private void onSuccess(Result appResponse, Invoker<?> invoker) {
if (DubboConfig.getDubboBizExceptionTraceEnabled()) {
traceAndExit(appResponse.getException(), invoker.getUrl());
} else {
traceAndExit(null, invoker.getUrl());
}
}


@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
traceAndExit(t, invoker.getUrl());
}

}

static void traceAndExit(Throwable throwable, URL url) {
Entry interfaceEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY);
Entry methodEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY);
if (methodEntry != null) {
Tracer.traceEntry(throwable, methodEntry);
methodEntry.exit();
RpcContext.getContext().remove(DubboUtils.DUBBO_METHOD_ENTRY_KEY);
}
if (interfaceEntry != null) {
Tracer.traceEntry(throwable, interfaceEntry);
interfaceEntry.exit();
RpcContext.getContext().remove(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY);
}
if (CommonConstants.PROVIDER_SIDE.equals(url.getParameter(CommonConstants.SIDE_KEY))) {
ContextUtil.exit();
}
}
} }

+ 7
- 2
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtils.java 查看文件

@@ -26,8 +26,6 @@ import org.apache.dubbo.rpc.Invoker;
public final class DubboUtils { public final class DubboUtils {


public static final String SENTINEL_DUBBO_APPLICATION_KEY = "dubboApplication"; public static final String SENTINEL_DUBBO_APPLICATION_KEY = "dubboApplication";
public static final String DUBBO_METHOD_ENTRY_KEY = "dubboMethodEntry";
public static final String DUBBO_INTERFACE_ENTRY_KEY = "dubboInterfaceEntry";


public static String getApplication(Invocation invocation, String defaultValue) { public static String getApplication(Invocation invocation, String defaultValue) {
if (invocation == null || invocation.getAttachments() == null) { if (invocation == null || invocation.getAttachments() == null) {
@@ -69,6 +67,13 @@ public final class DubboUtils {
return getResourceName(invoker, invocation, DubboConfig.getDubboInterfaceGroupAndVersionEnabled()); return getResourceName(invoker, invocation, DubboConfig.getDubboInterfaceGroupAndVersionEnabled());
} }
} }


public static String getInterfaceName(Invoker invoker) {
return DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey()
: invoker.getInterface().getName();
}

private DubboUtils() { private DubboUtils() {
} }
} }

+ 73
- 18
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java 查看文件

@@ -19,6 +19,7 @@ import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.ResourceTypeConstants; import com.alibaba.csp.sentinel.ResourceTypeConstants;
import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.log.RecordLog;
@@ -28,10 +29,12 @@ import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.InvokeMode; import org.apache.dubbo.rpc.InvokeMode;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.support.RpcUtils; import org.apache.dubbo.rpc.support.RpcUtils;


import java.util.LinkedList;
import java.util.function.BiConsumer;

import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;


/** /**
@@ -52,33 +55,85 @@ public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {
RecordLog.info("Sentinel Apache Dubbo consumer filter initialized"); RecordLog.info("Sentinel Apache Dubbo consumer filter initialized");
} }


@Override
String getMethodName(Invoker invoker, Invocation invocation) {
return DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix());
}

@Override
String getInterfaceName(Invoker invoker) {
return DubboUtils.getInterfaceName(invoker);
}

@Override @Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
InvokeMode invokeMode = RpcUtils.getInvokeMode(invoker.getUrl(), invocation);
if (InvokeMode.SYNC == invokeMode) {
return syncInvoke(invoker, invocation);
} else {
return asyncInvoke(invoker, invocation);
}

}

private Result syncInvoke(Invoker<?> invoker, Invocation invocation) {
Entry interfaceEntry = null; Entry interfaceEntry = null;
Entry methodEntry = null; Entry methodEntry = null;
RpcContext rpcContext = RpcContext.getContext();
String methodResourceName = getMethodName(invoker, invocation);
String interfaceResourceName = getInterfaceName(invoker);
try { try {
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix());
String interfaceResourceName = DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey()
: invoker.getInterface().getName();
InvokeMode invokeMode = RpcUtils.getInvokeMode(invoker.getUrl(), invocation);

if (InvokeMode.SYNC == invokeMode) {
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry);
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, invocation.getArguments());
} else {
// should generate the AsyncEntry when the invoke model in future or async
interfaceEntry = SphU.asyncEntry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry);
methodEntry = SphU.asyncEntry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, 1, invocation.getArguments());
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, invocation.getArguments());
Result result = invoker.invoke(invocation);
if (result.hasException()) {
Tracer.traceEntry(result.getException(), interfaceEntry);
Tracer.traceEntry(result.getException(), methodEntry);
} }
rpcContext.set(DubboUtils.DUBBO_METHOD_ENTRY_KEY, methodEntry);
return invoker.invoke(invocation);
return result;
} catch (BlockException e) { } catch (BlockException e) {
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e); return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e);
} catch (RpcException e) {
Tracer.traceEntry(e, interfaceEntry);
Tracer.traceEntry(e, methodEntry);
throw e;
} finally {
if (methodEntry != null) {
methodEntry.exit();
}
if (interfaceEntry != null) {
interfaceEntry.exit();
}
} }
} }


private Result asyncInvoke(Invoker<?> invoker, Invocation invocation) {
LinkedList<Entry> queue = new LinkedList<>();
String methodResourceName = getMethodName(invoker, invocation);
String interfaceResourceName = getInterfaceName(invoker);
try {
queue.push(SphU.asyncEntry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT));
queue.push(SphU.asyncEntry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, 1, invocation.getArguments()));
Result result = invoker.invoke(invocation);
result.whenCompleteWithContext(new BiConsumer<Result, Throwable>() {
@Override
public void accept(Result result, Throwable throwable) {
while (!queue.isEmpty()) {
Entry entry = queue.pop();
Tracer.traceEntry(result.getException(), entry);
entry.exit();
}
}
});
return result;
} catch (BlockException e) {
while (!queue.isEmpty()) {
queue.pop().exit();
}
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e);
}
}

} }





+ 32
- 8
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java 查看文件

@@ -19,16 +19,17 @@ import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.ResourceTypeConstants; import com.alibaba.csp.sentinel.ResourceTypeConstants;
import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;


import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
@@ -52,27 +53,50 @@ public class SentinelDubboProviderFilter extends BaseSentinelDubboFilter {
RecordLog.info("Sentinel Apache Dubbo provider filter initialized"); RecordLog.info("Sentinel Apache Dubbo provider filter initialized");
} }


@Override
String getMethodName(Invoker invoker, Invocation invocation) {
return DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix());
}

@Override
String getInterfaceName(Invoker invoker) {
return DubboUtils.getInterfaceName(invoker);
}

@Override @Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// Get origin caller. // Get origin caller.
String application = DubboUtils.getApplication(invocation, ""); String application = DubboUtils.getApplication(invocation, "");
RpcContext rpcContext = RpcContext.getContext();
Entry interfaceEntry = null; Entry interfaceEntry = null;
Entry methodEntry = null; Entry methodEntry = null;
String methodResourceName = getMethodName(invoker, invocation);
String interfaceResourceName = getInterfaceName(invoker);
try { try {
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix());
String interfaceResourceName = DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey()
: invoker.getInterface().getName();
// Only need to create entrance context at provider side, as context will take effect // Only need to create entrance context at provider side, as context will take effect
// at entrance of invocation chain only (for inbound traffic). // at entrance of invocation chain only (for inbound traffic).
ContextUtil.enter(methodResourceName, application); ContextUtil.enter(methodResourceName, application);
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN); interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry);
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, invocation.getArguments()); methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, invocation.getArguments());
rpcContext.set(DubboUtils.DUBBO_METHOD_ENTRY_KEY, methodEntry);
return invoker.invoke(invocation);
Result result = invoker.invoke(invocation);
if (result.hasException()) {
Tracer.traceEntry(result.getException(), interfaceEntry);
Tracer.traceEntry(result.getException(), methodEntry);
}
return result;
} catch (BlockException e) { } catch (BlockException e) {
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e); return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e);
} catch (RpcException e) {
Tracer.traceEntry(e, interfaceEntry);
Tracer.traceEntry(e, methodEntry);
throw e;
} finally {
if (methodEntry != null) {
methodEntry.exit(1, invocation.getArguments());
}
if (interfaceEntry != null) {
interfaceEntry.exit();
}
ContextUtil.exit();
} }
} }




+ 27
- 38
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java 查看文件

@@ -16,25 +16,19 @@
package com.alibaba.csp.sentinel; package com.alibaba.csp.sentinel;


import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DefaultDubboFallback;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;


import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;


import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/** /**
* Base test class, provide common methods for subClass * Base test class, provide common methods for subClass
* The package is same as CtSph, to call CtSph.resetChainMap() method for test * The package is same as CtSph, to call CtSph.resetChainMap() method for test
@@ -42,46 +36,41 @@ import static org.mockito.Mockito.when;
* Note: Only for test. DO NOT USE IN PRODUCTION! * Note: Only for test. DO NOT USE IN PRODUCTION!
* *
* @author cdfive * @author cdfive
* @author lianglin
*/ */
public class BaseTest { public class BaseTest {




protected Invoker invoker;
protected Invocation invocation;

public void constructInvokerAndInvocation() {
invoker = mock(Invoker.class);
URL url = URL.valueOf("dubbo://127.0.0.1:2181")
.addParameter(CommonConstants.VERSION_KEY, "1.0.0")
.addParameter(CommonConstants.GROUP_KEY, "grp1")
.addParameter(CommonConstants.INTERFACE_KEY, DemoService.class.getName());
when(invoker.getUrl()).thenReturn(url);
when(invoker.getInterface()).thenReturn(DemoService.class);

invocation = mock(Invocation.class);
Method method = DemoService.class.getMethods()[0];
when(invocation.getMethodName()).thenReturn(method.getName());
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());

}

/** /**
* Clean up resources for context, clusterNodeMap, processorSlotChainMap * Clean up resources for context, clusterNodeMap, processorSlotChainMap
*/ */
protected static void cleanUpAll() {
public void cleanUpAll() {
try { try {
RpcContext.removeContext();
ClusterBuilderSlot.getClusterNodeMap().clear();
CtSph.resetChainMap();
Method method = ContextUtil.class.getDeclaredMethod("resetContextMap");
method.setAccessible(true);
method.invoke(null, null);
ContextUtil.exit();
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "true");
FlowRuleManager.loadRules(new ArrayList<>());
DegradeRuleManager.loadRules(new ArrayList<>());
clearDubboContext();
cleanUpCstContext();
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }

private void cleanUpCstContext() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ClusterBuilderSlot.getClusterNodeMap().clear();
CtSph.resetChainMap();
Method method = ContextUtil.class.getDeclaredMethod("resetContextMap");
method.setAccessible(true);
method.invoke(null, null);
ContextUtil.exit();
FlowRuleManager.loadRules(new ArrayList<>());
DegradeRuleManager.loadRules(new ArrayList<>());
}

private void clearDubboContext() {
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false");
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
DubboFallbackRegistry.setConsumerFallback(new DefaultDubboFallback());
RpcContext.removeContext();

}
} }

+ 80
- 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/DubboTestUtil.java 查看文件

@@ -0,0 +1,80 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel;

import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;

import java.lang.reflect.Method;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
* @author lianglin
*/
public class DubboTestUtil {


public static Class<?> DEFAULT_TEST_SERVICE = DemoService.class;
public static Method DEFAULT_TEST_METHOD_ONE = DEFAULT_TEST_SERVICE.getMethods()[0];
public static Method DEFAULT_TEST_METHOD_TWO = DEFAULT_TEST_SERVICE.getMethods()[1];

public static Invoker getMockInvoker(URL url, Class<?> cls) {
Invoker invoker = mock(Invoker.class);
when(invoker.getUrl()).thenReturn(url);
when(invoker.getInterface()).thenReturn(cls);
return invoker;
}

public static Invoker getDefaultMockInvoker() {
return getMockInvoker(getDefaultTestURL(), DEFAULT_TEST_SERVICE);
}

public static Invocation getMockInvocation(Method method) {
Invocation invocation = mock(Invocation.class);
when(invocation.getMethodName()).thenReturn(method.getName());
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());
return invocation;
}

public static Invocation getDefaultMockInvocationOne() {
Invocation invocation = mock(Invocation.class);
when(invocation.getMethodName()).thenReturn(DEFAULT_TEST_METHOD_ONE.getName());
when(invocation.getParameterTypes()).thenReturn(DEFAULT_TEST_METHOD_ONE.getParameterTypes());
return invocation;
}

public static Invocation getDefaultMockInvocationTwo() {
Invocation invocation = mock(Invocation.class);
when(invocation.getMethodName()).thenReturn(DEFAULT_TEST_METHOD_TWO.getName());
when(invocation.getParameterTypes()).thenReturn(DEFAULT_TEST_METHOD_TWO.getParameterTypes());
return invocation;
}

public static URL getDefaultTestURL() {
URL url = URL.valueOf("dubbo://127.0.0.1:2181")
.addParameter(CommonConstants.VERSION_KEY, "1.0.0")
.addParameter(CommonConstants.GROUP_KEY, "grp1")
.addParameter(CommonConstants.INTERFACE_KEY, DEFAULT_TEST_SERVICE.getName());
return url;
}


}

+ 23
- 5
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java 查看文件

@@ -29,11 +29,10 @@ import org.junit.Test;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;


import static com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;


/** /**
* @author cdfive * @author cdfive
@@ -45,7 +44,7 @@ public class DubboUtilsTest {
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true"); SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true");
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
} }




@@ -54,7 +53,7 @@ public class DubboUtilsTest {
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false"); SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false");
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
} }




@@ -146,4 +145,23 @@ public class DubboUtilsTest {
assertEquals("my:dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); assertEquals("my:dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);


} }

@Test
public void testGetInterfaceName() {

URL url = URL.valueOf("dubbo://127.0.0.1:2181")
.addParameter(CommonConstants.VERSION_KEY, "1.0.0")
.addParameter(CommonConstants.GROUP_KEY, "grp1")
.addParameter(CommonConstants.INTERFACE_KEY, DemoService.class.getName());
Invoker invoker = mock(Invoker.class);
when(invoker.getUrl()).thenReturn(url);
when(invoker.getInterface()).thenReturn(DemoService.class);

SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService", DubboUtils.getInterfaceName(invoker));

SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "true");
assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:1.0.0:grp1", DubboUtils.getInterfaceName(invoker));

}
} }

+ 130
- 121
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java 查看文件

@@ -16,13 +16,11 @@
package com.alibaba.csp.sentinel.adapter.dubbo; package com.alibaba.csp.sentinel.adapter.dubbo;


import com.alibaba.csp.sentinel.BaseTest; import com.alibaba.csp.sentinel.BaseTest;
import com.alibaba.csp.sentinel.DubboTestUtil;
import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DefaultDubboFallback;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallback; import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallback;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
import com.alibaba.csp.sentinel.context.Context; import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.node.ClusterNode; import com.alibaba.csp.sentinel.node.ClusterNode;
@@ -36,8 +34,10 @@ import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.InvokeMode;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
@@ -46,7 +46,6 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@@ -56,105 +55,80 @@ import java.util.Set;


import static com.alibaba.csp.sentinel.slots.block.RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO; import static com.alibaba.csp.sentinel.slots.block.RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO;
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY; import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;


/** /**
* @author cdfive * @author cdfive
* @author lianglin
*/ */
public class SentinelDubboConsumerFilterTest extends BaseTest { public class SentinelDubboConsumerFilterTest extends BaseTest {


private SentinelDubboConsumerFilter filter = new SentinelDubboConsumerFilter();
private SentinelDubboConsumerFilter consumerFilter = new SentinelDubboConsumerFilter();




@Before @Before
public void setUp() { public void setUp() {
cleanUpAll(); cleanUpAll();
initFallback(); initFallback();
constructInvokerAndInvocation();
} }


@After @After
public void cleanUp() {
public void destroy() {
cleanUpAll(); cleanUpAll();
DubboFallbackRegistry.setConsumerFallback(new DefaultDubboFallback());
} }


public void initFlowRule(String resource) {
FlowRule flowRule = new FlowRule(resource);
flowRule.setCount(1);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
List<FlowRule> flowRules = new ArrayList<>();
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
}

public void initDegradeRule(String resource) {
DegradeRule degradeRule = new DegradeRule(resource)
.setCount(0.5)
.setGrade(DEGRADE_GRADE_EXCEPTION_RATIO);
List<DegradeRule> degradeRules = new ArrayList<>();
degradeRules.add(degradeRule);
degradeRule.setTimeWindow(1);
DegradeRuleManager.loadRules(degradeRules);
}


public void initFallback() {
DubboFallbackRegistry.setConsumerFallback(new DubboFallback() {
@Override
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) {
boolean async = RpcUtils.isAsync(invoker.getUrl(), invocation);
Result fallbackResult = null;
fallbackResult = AsyncRpcResult.newDefaultAsyncResult("fallback", invocation);
return fallbackResult;
}
});
}


@Test @Test
public void testInterfaceLevelFollowControlAsync() throws InterruptedException { public void testInterfaceLevelFollowControlAsync() throws InterruptedException {

Invoker invoker = DubboTestUtil.getDefaultMockInvoker();
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne();

when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString()); when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());
initFlowRule(invoker.getUrl().getColonSeparatedKey());
Result result1 = responseBack(requestGo(false, invocation));
initFlowRule(DubboUtils.getInterfaceName(invoker));

Result result1 = invokeDubboRpc(false, invoker, invocation);
assertEquals("normal", result1.getValue()); assertEquals("normal", result1.getValue());

// should fallback because the qps > 1 // should fallback because the qps > 1
Result result2 = responseBack(requestGo(false, invocation));
Result result2 = invokeDubboRpc(false, invoker, invocation);
assertEquals("fallback", result2.getValue()); assertEquals("fallback", result2.getValue());

// sleeping 1000 ms to reset qps // sleeping 1000 ms to reset qps
Thread.sleep(1000); Thread.sleep(1000);
Result result3 = responseBack(requestGo(false, invocation));
Result result3 = invokeDubboRpc(false, invoker, invocation);
assertEquals("normal", result3.getValue()); assertEquals("normal", result3.getValue());


verifyInvocationStructureForCallFinish();
verifyInvocationStructureForCallFinish(invoker, invocation);
} }


@Test @Test
public void testDegradeAsync() throws InterruptedException { public void testDegradeAsync() throws InterruptedException {

Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne();
Invoker invoker = DubboTestUtil.getDefaultMockInvoker();

when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString()); when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());
initDegradeRule(DubboUtils.getInterfaceName(invoker));


initDegradeRule(invoker.getUrl().getColonSeparatedKey());
Result result = requestGo(false, invocation);
verifyInvocationStructureForAsyncCall(invoker, invocation);
responseBack(result);
Result result = invokeDubboRpc(false, invoker, invocation);
verifyInvocationStructureForCallFinish(invoker, invocation);
assertEquals("normal", result.getValue()); assertEquals("normal", result.getValue());


// inc the clusterNode's exception to trigger the fallback // inc the clusterNode's exception to trigger the fallback
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
responseBack(requestGo(true, invocation));
verifyInvocationStructureForCallFinish();
invokeDubboRpc(true, invoker, invocation);
verifyInvocationStructureForCallFinish(invoker, invocation);
} }
Result result2 = responseBack(requestGo(false, invocation));

Result result2 = invokeDubboRpc(false, invoker, invocation);
assertEquals("fallback", result2.getValue()); assertEquals("fallback", result2.getValue());

// sleeping 1000 ms to reset exception // sleeping 1000 ms to reset exception
Thread.sleep(1000); Thread.sleep(1000);

Result result3 = responseBack(requestGo(false, invocation));
Result result3 = invokeDubboRpc(false, invoker, invocation);
assertEquals("normal", result3.getValue()); assertEquals("normal", result3.getValue());


Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
@@ -164,22 +138,26 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
@Test @Test
public void testDegradeSync() throws InterruptedException { public void testDegradeSync() throws InterruptedException {


initDegradeRule(invoker.getUrl().getColonSeparatedKey());
Result result = requestGo(false, invocation);
verifyInvocationStructure(invoker, invocation);
responseBack(result);
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne();
Invoker invoker = DubboTestUtil.getDefaultMockInvoker();
initDegradeRule(DubboUtils.getInterfaceName(invoker));

Result result = invokeDubboRpc(false, invoker, invocation);
verifyInvocationStructureForCallFinish(invoker, invocation);
assertEquals("normal", result.getValue()); assertEquals("normal", result.getValue());

// inc the clusterNode's exception to trigger the fallback // inc the clusterNode's exception to trigger the fallback
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
responseBack(requestGo(true, invocation));
verifyInvocationStructureForCallFinish();
invokeDubboRpc(true, invoker, invocation);
verifyInvocationStructureForCallFinish(invoker, invocation);
} }
Result result2 = responseBack(requestGo(false, invocation));

Result result2 = invokeDubboRpc(false, invoker, invocation);
assertEquals("fallback", result2.getValue()); assertEquals("fallback", result2.getValue());

// sleeping 1000 ms to reset exception // sleeping 1000 ms to reset exception
Thread.sleep(1000); Thread.sleep(1000);

Result result3 = responseBack(requestGo(false, invocation));
Result result3 = invokeDubboRpc(false, invoker, invocation);
assertEquals("normal", result3.getValue()); assertEquals("normal", result3.getValue());


Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
@@ -189,62 +167,43 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {


@Test @Test
public void testMethodFlowControlAsync() { public void testMethodFlowControlAsync() {
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());
initFlowRule(DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix()));
responseBack(requestGo(false, invocation));


responseBack(requestGo(false, invocation));
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne();
Invoker invoker = DubboTestUtil.getDefaultMockInvoker();


Invocation invocation2 = mock(Invocation.class);
Method method = DemoService.class.getMethods()[1];
when(invocation2.getMethodName()).thenReturn(method.getName());
when(invocation2.getParameterTypes()).thenReturn(method.getParameterTypes());
Result result2 = responseBack(requestGo(false, invocation2));
verifyInvocationStructureForCallFinish();
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());
initFlowRule(consumerFilter.getMethodName(invoker, invocation));
invokeDubboRpc(false, invoker, invocation);
invokeDubboRpc(false, invoker, invocation);

Invocation invocation2 = DubboTestUtil.getDefaultMockInvocationTwo();
Result result2 = invokeDubboRpc(false, invoker, invocation2);
verifyInvocationStructureForCallFinish(invoker, invocation2);
assertEquals("normal", result2.getValue()); assertEquals("normal", result2.getValue());


// the method of invocation should be blocked // the method of invocation should be blocked
Result fallback = requestGo(false, invocation);
assertNotNull(RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY));
assertNull(RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY));
responseBack(fallback);
Result fallback = invokeDubboRpc(false, invoker, invocation);
assertEquals("fallback", fallback.getValue()); assertEquals("fallback", fallback.getValue());
verifyInvocationStructureForCallFinish();

verifyInvocationStructureForCallFinish(invoker, invocation);


}

public Result requestGo(boolean exception, Invocation currentInvocation) {
AsyncRpcResult result = null;


if (exception) {
result = AsyncRpcResult.newDefaultAsyncResult(new Exception("error"), currentInvocation);
} else {
result = AsyncRpcResult.newDefaultAsyncResult("normal", currentInvocation);
}
when(invoker.invoke(currentInvocation)).thenReturn(result);
return filter.invoke(invoker, currentInvocation);
}

public Result responseBack(Result result) {
filter.listener().onMessage(result, invoker, invocation);
return result;
} }




@Test @Test
public void testInvokeAsync() throws InterruptedException {
public void testInvokeAsync() {


when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne();
Invoker invoker = DubboTestUtil.getDefaultMockInvoker();


when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());
final Result result = mock(Result.class); final Result result = mock(Result.class);
when(result.hasException()).thenReturn(false); when(result.hasException()).thenReturn(false);
when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> { when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
verifyInvocationStructureForAsyncCall(invoker, invocation); verifyInvocationStructureForAsyncCall(invoker, invocation);
return result;
return result;
}); });

filter.invoke(invoker, invocation);
consumerFilter.invoke(invoker, invocation);
verify(invoker).invoke(invocation); verify(invoker).invoke(invocation);


Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
@@ -254,6 +213,9 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
@Test @Test
public void testInvokeSync() { public void testInvokeSync() {


Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne();
Invoker invoker = DubboTestUtil.getDefaultMockInvoker();

final Result result = mock(Result.class); final Result result = mock(Result.class);
when(result.hasException()).thenReturn(false); when(result.hasException()).thenReturn(false);
when(result.getException()).thenReturn(new Exception()); when(result.getException()).thenReturn(new Exception());
@@ -262,14 +224,14 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
return result; return result;
}); });


filter.invoke(invoker, invocation);
consumerFilter.invoke(invoker, invocation);
verify(invoker).invoke(invocation); verify(invoker).invoke(invocation);


filter.listener().onMessage(result, invoker, invocation);
Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
assertNull(context); assertNull(context);
} }



/** /**
* Simply verify invocation structure in memory: * Simply verify invocation structure in memory:
* EntranceNode(defaultContextName) * EntranceNode(defaultContextName)
@@ -282,7 +244,7 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
// As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default context // As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default context
// In actual project, a consumer is usually also a provider, the context will be created by SentinelDubboProviderFilter // In actual project, a consumer is usually also a provider, the context will be created by SentinelDubboProviderFilter
// If consumer is on the top of Dubbo RPC invocation chain, use default context // If consumer is on the top of Dubbo RPC invocation chain, use default context
String resourceName = DubboUtils.getResourceName(invoker, invocation, true);
String resourceName = consumerFilter.getMethodName(invoker, invocation);
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName()); assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName());
assertEquals("", context.getOrigin()); assertEquals("", context.getOrigin());


@@ -295,10 +257,10 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
// As SphU.entry(interfaceName, EntryType.OUT); // As SphU.entry(interfaceName, EntryType.OUT);
Set<Node> childList = entranceNode.getChildList(); Set<Node> childList = entranceNode.getChildList();
assertEquals(1, childList.size()); assertEquals(1, childList.size());
DefaultNode interfaceNode = getNode(invoker.getUrl().getColonSeparatedKey(), entranceNode);
DefaultNode interfaceNode = getNode(DubboUtils.getInterfaceName(invoker), entranceNode);
ResourceWrapper interfaceResource = interfaceNode.getId(); ResourceWrapper interfaceResource = interfaceNode.getId();


assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName());
assertEquals(DubboUtils.getInterfaceName(invoker), interfaceResource.getName());
assertSame(EntryType.OUT, interfaceResource.getEntryType()); assertSame(EntryType.OUT, interfaceResource.getEntryType());


// As SphU.entry(resourceName, EntryType.OUT); // As SphU.entry(resourceName, EntryType.OUT);
@@ -335,7 +297,7 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
// As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default context // As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default context
// In actual project, a consumer is usually also a provider, the context will be created by SentinelDubboProviderFilter // In actual project, a consumer is usually also a provider, the context will be created by SentinelDubboProviderFilter
// If consumer is on the top of Dubbo RPC invocation chain, use default context // If consumer is on the top of Dubbo RPC invocation chain, use default context
String resourceName = DubboUtils.getResourceName(invoker, invocation, true);
String resourceName = consumerFilter.getMethodName(invoker, invocation);
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName()); assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName());
assertEquals("", context.getOrigin()); assertEquals("", context.getOrigin());


@@ -347,9 +309,9 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
// As SphU.entry(interfaceName, EntryType.OUT); // As SphU.entry(interfaceName, EntryType.OUT);
Set<Node> childList = entranceNode.getChildList(); Set<Node> childList = entranceNode.getChildList();
assertEquals(2, childList.size()); assertEquals(2, childList.size());
DefaultNode interfaceNode = getNode(invoker.getUrl().getColonSeparatedKey(), entranceNode);
DefaultNode interfaceNode = getNode(DubboUtils.getInterfaceName(invoker), entranceNode);
ResourceWrapper interfaceResource = interfaceNode.getId(); ResourceWrapper interfaceResource = interfaceNode.getId();
assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName());
assertEquals(DubboUtils.getInterfaceName(invoker), interfaceResource.getName());
assertSame(EntryType.OUT, interfaceResource.getEntryType()); assertSame(EntryType.OUT, interfaceResource.getEntryType());


// As SphU.entry(resourceName, EntryType.OUT); // As SphU.entry(resourceName, EntryType.OUT);
@@ -379,17 +341,16 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
} }




private void verifyInvocationStructureForCallFinish() {
private void verifyInvocationStructureForCallFinish(Invoker invoker, Invocation invocation) {
Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
assertNull(context); assertNull(context);
Entry interfaceEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY);
Entry methodEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY);
assertNull(interfaceEntry);
assertNull(methodEntry);
String methodResourceName = consumerFilter.getMethodName(invoker, invocation);
Entry[] entries = (Entry[]) RpcContext.getContext().get(methodResourceName);
assertNull(entries);
} }




public DefaultNode getNode(String resourceName, DefaultNode root) {
private DefaultNode getNode(String resourceName, DefaultNode root) {


Queue<DefaultNode> queue = new LinkedList<>(); Queue<DefaultNode> queue = new LinkedList<>();
queue.offer(root); queue.offer(root);
@@ -405,4 +366,52 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
return null; return null;
} }



private void initFlowRule(String resource) {
FlowRule flowRule = new FlowRule(resource);
flowRule.setCount(1);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
List<FlowRule> flowRules = new ArrayList<>();
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
}

private void initDegradeRule(String resource) {
DegradeRule degradeRule = new DegradeRule(resource)
.setCount(0.5)
.setGrade(DEGRADE_GRADE_EXCEPTION_RATIO);
List<DegradeRule> degradeRules = new ArrayList<>();
degradeRules.add(degradeRule);
degradeRule.setTimeWindow(1);
DegradeRuleManager.loadRules(degradeRules);
}


private void initFallback() {
DubboFallbackRegistry.setConsumerFallback(new DubboFallback() {
@Override
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) {
boolean async = RpcUtils.isAsync(invoker.getUrl(), invocation);
Result fallbackResult = null;
fallbackResult = AsyncRpcResult.newDefaultAsyncResult("fallback", invocation);
return fallbackResult;
}
});
}

private Result invokeDubboRpc(boolean exception, Invoker invoker, Invocation invocation) {
Result result = null;
InvokeMode invokeMode = RpcUtils.getInvokeMode(invoker.getUrl(), invocation);
if (InvokeMode.SYNC == invokeMode) {
result = exception ? new AppResponse(new Exception("error")) : new AppResponse("normal");
} else {
result = exception ? AsyncRpcResult.newDefaultAsyncResult(new Exception("error"), invocation) : AsyncRpcResult.newDefaultAsyncResult("normal", invocation);
}
when(invoker.invoke(invocation)).thenReturn(result);
return consumerFilter.invoke(invoker, invocation);
}




} }

+ 22
- 23
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java 查看文件

@@ -16,6 +16,7 @@
package com.alibaba.csp.sentinel.adapter.dubbo; package com.alibaba.csp.sentinel.adapter.dubbo;


import com.alibaba.csp.sentinel.BaseTest; import com.alibaba.csp.sentinel.BaseTest;
import com.alibaba.csp.sentinel.DubboTestUtil;
import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
@@ -35,52 +36,49 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;


/** /**
* @author cdfive * @author cdfive
* @author lianglin
*/ */
public class SentinelDubboProviderFilterTest extends BaseTest { public class SentinelDubboProviderFilterTest extends BaseTest {



private SentinelDubboProviderFilter filter = new SentinelDubboProviderFilter(); private SentinelDubboProviderFilter filter = new SentinelDubboProviderFilter();



@Before @Before
public void setUp() { public void setUp() {
constructInvokerAndInvocation();
cleanUpAll(); cleanUpAll();
} }


@After @After
public void cleanUp() {
public void destroy() {
cleanUpAll(); cleanUpAll();
} }


@Test @Test
public void testInvoke() { public void testInvoke() {

final String originApplication = "consumerA"; final String originApplication = "consumerA";


URL url = invoker.getUrl()
.addParameter(CommonConstants.SIDE_KEY, CommonConstants.PROVIDER_SIDE);
when(invoker.getUrl()).thenReturn(url);
URL url = DubboTestUtil.getDefaultTestURL();
url = url.addParameter(CommonConstants.SIDE_KEY, CommonConstants.PROVIDER_SIDE);
Invoker invoker = DubboTestUtil.getMockInvoker(url, DemoService.class);


Invocation invocation = DubboTestUtil.getMockInvocation(DemoService.class.getMethods()[0]);
when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, "")) when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, ""))
.thenReturn(originApplication); .thenReturn(originApplication);


final Result result = mock(Result.class); final Result result = mock(Result.class);
when(result.hasException()).thenReturn(false); when(result.hasException()).thenReturn(false);
when(result.getException()).thenReturn(new Exception()); when(result.getException()).thenReturn(new Exception());

when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> { when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
verifyInvocationStructure(originApplication, invoker, invocation); verifyInvocationStructure(originApplication, invoker, invocation);
return result; return result;
@@ -89,29 +87,28 @@ public class SentinelDubboProviderFilterTest extends BaseTest {
filter.invoke(invoker, invocation); filter.invoke(invoker, invocation);
verify(invoker).invoke(invocation); verify(invoker).invoke(invocation);


filter.listener().onMessage(result, invoker, invocation);
Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
assertNull(context); assertNull(context);
} }


/** /**
* Simply verify invocation structure in memory: * Simply verify invocation structure in memory:
* EntranceNode(resourceName)
* EntranceNode(methodResourceName)
* --InterfaceNode(interfaceName) * --InterfaceNode(interfaceName)
* ----MethodNode(resourceName)
* ----MethodNode(methodResourceName)
*/ */
private void verifyInvocationStructure(String originApplication, Invoker invoker, Invocation invocation) { private void verifyInvocationStructure(String originApplication, Invoker invoker, Invocation invocation) {
Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
assertNotNull(context); assertNotNull(context);


// As ContextUtil.enter(resourceName, application) in SentinelDubboProviderFilter // As ContextUtil.enter(resourceName, application) in SentinelDubboProviderFilter
String resourceName = DubboUtils.getResourceName(invoker, invocation, true);
assertEquals(resourceName, context.getName());
String methodResourceName = filter.getMethodName(invoker, invocation);
assertEquals(methodResourceName, context.getName());
assertEquals(originApplication, context.getOrigin()); assertEquals(originApplication, context.getOrigin());


DefaultNode entranceNode = context.getEntranceNode(); DefaultNode entranceNode = context.getEntranceNode();
ResourceWrapper entranceResource = entranceNode.getId(); ResourceWrapper entranceResource = entranceNode.getId();
assertEquals(resourceName, entranceResource.getName());
assertEquals(methodResourceName, entranceResource.getName());
assertSame(EntryType.IN, entranceResource.getEntryType()); assertSame(EntryType.IN, entranceResource.getEntryType());


// As SphU.entry(interfaceName, EntryType.IN); // As SphU.entry(interfaceName, EntryType.IN);
@@ -120,7 +117,7 @@ public class SentinelDubboProviderFilterTest extends BaseTest {
DefaultNode interfaceNode = (DefaultNode) childList.iterator().next(); DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
ResourceWrapper interfaceResource = interfaceNode.getId(); ResourceWrapper interfaceResource = interfaceNode.getId();


assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName());
assertEquals(filter.getInterfaceName(invoker), interfaceResource.getName());
assertSame(EntryType.IN, interfaceResource.getEntryType()); assertSame(EntryType.IN, interfaceResource.getEntryType());


// As SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments()); // As SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments());
@@ -128,7 +125,7 @@ public class SentinelDubboProviderFilterTest extends BaseTest {
assertEquals(1, childList.size()); assertEquals(1, childList.size());
DefaultNode methodNode = (DefaultNode) childList.iterator().next(); DefaultNode methodNode = (DefaultNode) childList.iterator().next();
ResourceWrapper methodResource = methodNode.getId(); ResourceWrapper methodResource = methodNode.getId();
assertEquals(resourceName, methodResource.getName());
assertEquals(methodResourceName, methodResource.getName());
assertSame(EntryType.IN, methodResource.getEntryType()); assertSame(EntryType.IN, methodResource.getEntryType());


// Verify curEntry // Verify curEntry
@@ -151,4 +148,6 @@ public class SentinelDubboProviderFilterTest extends BaseTest {
assertEquals(1, interfaceOriginCountMap.size()); assertEquals(1, interfaceOriginCountMap.size());
assertTrue(interfaceOriginCountMap.containsKey(originApplication)); assertTrue(interfaceOriginCountMap.containsKey(originApplication));
} }


} }

Loading…
取消
儲存