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

[1416] fix sentinel-apache-dubbo-adapter full GC problem #1431

Merged
merged 8 commits into from
Jun 4, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
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.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.ListenableFilter;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;

/**
* Base Class of the {@link SentinelDubboProviderFilter} and {@link SentinelDubboConsumerFilter}.
Expand All @@ -38,43 +42,46 @@ public BaseSentinelDubboFilter() {
static class SentinelDubboListener implements Listener {

public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
onSuccess(appResponse, invoker);
onSuccess(appResponse, invoker, invocation);
}

//for compatible dubbo 2.7.5 rename onResponse to onMessage
public void onMessage(Result appResponse, Invoker<?> invoker, Invocation invocation) {
onSuccess(appResponse, invoker);
onSuccess(appResponse, invoker, invocation);
}

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

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

}

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);
static void traceAndExit(Throwable throwable, Invoker invoker, Invocation invocation) {
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix());
Entry[] entries = (Entry[]) RpcContext.getContext().get(methodResourceName);
linlinisme marked this conversation as resolved.
Show resolved Hide resolved
if (entries != null) {
Entry interfaceEntry = entries[0];
Entry methodEntry = entries[1];
if (methodEntry != null) {
Tracer.traceEntry(throwable, methodEntry);
methodEntry.exit();
}
if (interfaceEntry != null) {
Tracer.traceEntry(throwable, interfaceEntry);
interfaceEntry.exit();
}
RpcContext.getContext().remove(methodResourceName);
}
if (CommonConstants.PROVIDER_SIDE.equals(url.getParameter(CommonConstants.SIDE_KEY))) {
if (CommonConstants.PROVIDER_SIDE.equals(invoker.getUrl().getParameter(CommonConstants.SIDE_KEY))) {
ContextUtil.exit();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
public final class DubboUtils {

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) {
if (invocation == null || invocation.getAttachments() == null) {
Expand Down Expand Up @@ -69,6 +67,13 @@ public static String getResourceName(Invoker<?> invoker, Invocation invocation,
return getResourceName(invoker, invocation, DubboConfig.getDubboInterfaceGroupAndVersionEnabled());
}
}


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

private DubboUtils() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,18 @@ public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcExcept
RpcContext rpcContext = RpcContext.getContext();
try {
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix());
String interfaceResourceName = DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey()
: invoker.getInterface().getName();
String interfaceResourceName = DubboUtils.getInterfaceName(invoker);
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());
}
rpcContext.set(DubboUtils.DUBBO_METHOD_ENTRY_KEY, methodEntry);
rpcContext.set(methodResourceName, new Entry[]{interfaceEntry, methodEntry});
return invoker.invoke(invocation);
} catch (BlockException e) {
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,13 @@ public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcExcept
Entry methodEntry = null;
try {
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix());
String interfaceResourceName = DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey()
: invoker.getInterface().getName();
String interfaceResourceName = DubboUtils.getInterfaceName(invoker);
// Only need to create entrance context at provider side, as context will take effect
// at entrance of invocation chain only (for inbound traffic).
ContextUtil.enter(methodResourceName, application);
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());
rpcContext.set(DubboUtils.DUBBO_METHOD_ENTRY_KEY, methodEntry);
rpcContext.set(methodResourceName, new Entry[]{interfaceEntry, methodEntry});
linlinisme marked this conversation as resolved.
Show resolved Hide resolved
return invoker.invoke(invocation);
linlinisme marked this conversation as resolved.
Show resolved Hide resolved
} catch (BlockException e) {
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,72 +16,61 @@
package com.alibaba.csp.sentinel;

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.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
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 java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

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

/**
* Base test class, provide common methods for subClass
* The package is same as CtSph, to call CtSph.resetChainMap() method for test
* <p>
* Note: Only for test. DO NOT USE IN PRODUCTION!
*
* @author cdfive
* @author lianglin
*/
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
*/
protected static void cleanUpAll() {
public void cleanUpAll() {
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) {
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();

}
}
Original file line number Diff line number Diff line change
@@ -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;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@
import java.lang.reflect.Method;
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.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
Expand All @@ -45,7 +44,7 @@ public void setUp() {
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true");
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
}


Expand All @@ -54,7 +53,7 @@ public void tearDown() {
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");
SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
}


Expand Down Expand Up @@ -146,4 +145,23 @@ public void testGetResourceNameWithPrefix() throws NoSuchMethodException {
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));

}
}
Loading