Add Sentinel SOFARPC adapter module (#1307)

This commit is contained in:
cdfive 2020-03-02 18:13:54 +08:00 committed by GitHub
parent cd1d9be0ea
commit 18acb1d154
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1558 additions and 0 deletions

View File

@ -18,6 +18,7 @@
<module>sentinel-web-servlet</module> <module>sentinel-web-servlet</module>
<module>sentinel-dubbo-adapter</module> <module>sentinel-dubbo-adapter</module>
<module>sentinel-apache-dubbo-adapter</module> <module>sentinel-apache-dubbo-adapter</module>
<module>sentinel-sofa-rpc-adapter</module>
<module>sentinel-grpc-adapter</module> <module>sentinel-grpc-adapter</module>
<module>sentinel-zuul-adapter</module> <module>sentinel-zuul-adapter</module>
<module>sentinel-reactor-adapter</module> <module>sentinel-reactor-adapter</module>

View File

@ -0,0 +1,63 @@
# Sentinel SOFARPC Adapter
Sentinel SOFARPC Adapter provides service provider filter and consumer filter
for [SOFARPC](https://www.sofastack.tech/projects/sofa-rpc) services.
**Note: This adapter supports SOFARPC 5.4.x version and above, and 5.6.x is officially recommended.**
To use Sentinel SOFARPC Adapter, you can simply add the following dependency to your `pom.xml`:
```xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-sofa-rpc-adapter</artifactId>
<version>x.y.z</version>
</dependency>
```
The Sentinel filters are **enabled by default**. Once you add the dependency,
the SOFARPC services and methods will become protected resources in Sentinel,
which can leverage Sentinel's flow control and guard ability when rules are configured.
Demos can be found in [sentinel-demo-sofa-rpc](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-sofa-rpc).
If you don't want the filters enabled, you can manually disable them. For example:
```java
providerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
consumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
```
or add setting in `rpc-config.json` file, and its priority is lower than above.
```json
{
"sofa.rpc.sentinel.enabled": true
}
```
For more details of SOFARPC filter, see [here](https://www.sofastack.tech/projects/sofa-rpc/custom-filter/).
## SOFARPC resources
The resource for SOFARPC services has two granularities: service interface and service method.
- Service interfaceresourceName format is `interfaceName`e.g. `com.alibaba.csp.sentinel.demo.sofa.rpc.DemoService`
- Service methodresourceName format is `interfaceName#methodSignature`e.g. `com.alibaba.csp.sentinel.demo.sofa.rpc.DemoService#sayHello(java.lang.Integer,java.lang.String,int)`
## Flow control based on caller
In many circumstances, it's also significant to control traffic flow based on the **caller**.
For example, assuming that there are two services A and B, both of them initiate remote call requests to the service provider.
If we want to limit the calls from service B only, we can set the `limitApp` of flow rule as the identifier of service B (e.g. service name).
Sentinel SOFARPC Adapter will automatically resolve the SOFARPC consumer's *application name* as the caller's name (`origin`),
and will bring the caller's name when doing resource protection.
If `limitApp` of flow rules is not configured (`default`), flow control will take effects on all callers.
If `limitApp` of a flow rule is configured with a caller, then the corresponding flow rule will only take effect on the specific caller.
## Global fallback
Sentinel SOFARPC Adapter supports global fallback configuration.
The global fallback will handle exceptions and give replacement result when blocked by
flow control, degrade or system load protection. You can implement your own `SofaRpcFallback` interface
and then register to `SofaRpcFallbackRegistry`. If no fallback is configured, Sentinel will wrap the `BlockException`
then directly throw it out.

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sentinel-adapter</artifactId>
<groupId>com.alibaba.csp</groupId>
<version>1.7.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel-sofa-rpc-adapter</artifactId>
<properties>
<sofa-rpc-all.version>5.6.4</sofa-rpc-all.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-rpc-all</artifactId>
<version>${sofa-rpc-all.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,57 @@
package com.alibaba.csp.sentinel.adapter.sofa.rpc;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.adapter.sofa.rpc.config.SofaRpcConfig;
import com.alipay.sofa.rpc.common.RpcConfigs;
import com.alipay.sofa.rpc.common.utils.StringUtils;
import com.alipay.sofa.rpc.config.AbstractInterfaceConfig;
import com.alipay.sofa.rpc.core.exception.RpcErrorType;
import com.alipay.sofa.rpc.core.exception.SofaRpcException;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.filter.Filter;
import com.alipay.sofa.rpc.filter.FilterInvoker;
/**
* @author cdfive
*/
abstract class AbstractSofaRpcFilter extends Filter {
@Override
public boolean needToLoad(FilterInvoker invoker) {
AbstractInterfaceConfig config = invoker.getConfig();
String enabled = config.getParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED);
if (StringUtils.isNotBlank(enabled)) {
return Boolean.valueOf(enabled);
}
return RpcConfigs.getOrDefaultValue(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, true);
}
protected void traceResponseException(SofaResponse response, Entry interfaceEntry, Entry methodEntry) {
if (response.isError()) {
SofaRpcException rpcException = new SofaRpcException(RpcErrorType.SERVER_FILTER, response.getErrorMsg());
Tracer.traceEntry(rpcException, interfaceEntry);
Tracer.traceEntry(rpcException, methodEntry);
} else {
Object appResponse = response.getAppResponse();
if (appResponse instanceof Throwable) {
Tracer.traceEntry((Throwable) appResponse, interfaceEntry);
Tracer.traceEntry((Throwable) appResponse, methodEntry);
}
}
}
protected SofaRpcException traceOtherException(Throwable t, Entry interfaceEntry, Entry methodEntry) {
SofaRpcException rpcException;
if (t instanceof SofaRpcException) {
rpcException = (SofaRpcException) t;
} else {
rpcException = new SofaRpcException(RpcErrorType.SERVER_FILTER, t);
}
Tracer.traceEntry(rpcException, interfaceEntry);
Tracer.traceEntry(rpcException, methodEntry);
return rpcException;
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.adapter.sofa.rpc;
import com.alibaba.csp.sentinel.*;
import com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback.SofaRpcFallbackRegistry;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alipay.sofa.rpc.common.RpcConstants;
import com.alipay.sofa.rpc.core.exception.SofaRpcException;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.ext.Extension;
import com.alipay.sofa.rpc.filter.AutoActive;
import com.alipay.sofa.rpc.filter.FilterInvoker;
import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getInterfaceResourceName;
import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodResourceName;
import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodArguments;
/**
* SOFARPC service consumer filter for Sentinel, auto activated by default.
*
* If you want to disable the consumer filter, you can configure:
* <pre>ConsumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");</pre>
*
* or add setting in rpc-config.json:
* <pre>"sofa.rpc.sentinel.enabled": false </pre>
*
* @author cdfive
*/
@Extension(value = "consumerSentinel", order = -1000)
@AutoActive(consumerSide = true)
public class SentinelSofaRpcConsumerFilter extends AbstractSofaRpcFilter {
@Override
public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
// Now only support sync invoke.
if (request.getInvokeType() != null && !RpcConstants.INVOKER_TYPE_SYNC.equals(request.getInvokeType())) {
return invoker.invoke(request);
}
String interfaceResourceName = getInterfaceResourceName(request);
String methodResourceName = getMethodResourceName(request);
Entry interfaceEntry = null;
Entry methodEntry = null;
try {
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, getMethodArguments(request));
SofaResponse response = invoker.invoke(request);
traceResponseException(response, interfaceEntry, methodEntry);
return response;
} catch (BlockException e) {
return SofaRpcFallbackRegistry.getConsumerFallback().handle(invoker, request, e);
} catch (Throwable t) {
throw traceOtherException(t, interfaceEntry, methodEntry);
} finally {
if (methodEntry != null) {
methodEntry.exit(1, getMethodArguments(request));
}
if (interfaceEntry != null) {
interfaceEntry.exit();
}
}
}
}

View File

@ -0,0 +1,93 @@
/*
* 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.adapter.sofa.rpc;
import com.alibaba.csp.sentinel.*;
import com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback.SofaRpcFallbackRegistry;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alipay.sofa.rpc.common.RpcConstants;
import com.alipay.sofa.rpc.core.exception.SofaRpcException;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.ext.Extension;
import com.alipay.sofa.rpc.filter.AutoActive;
import com.alipay.sofa.rpc.filter.FilterInvoker;
import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getApplicationName;
import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getInterfaceResourceName;
import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodResourceName;
import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodArguments;
/**
* SOFARPC service provider filter for Sentinel, auto activated by default.
*
* If you want to disable the provider filter, you can configure:
* <pre>ProviderConfig.setParameter("sofa.rpc.sentinel.enabled", "false");</pre>
*
* or add setting in rpc-config.json file:
* <pre>
* {
* "sofa.rpc.sentinel.enabled": false
* }
* </pre>
*
* @author cdfive
*/
@Extension(value = "providerSentinel", order = -1000)
@AutoActive(providerSide = true)
public class SentinelSofaRpcProviderFilter extends AbstractSofaRpcFilter {
@Override
public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
// Now only support sync invoke.
if (request.getInvokeType() != null && !RpcConstants.INVOKER_TYPE_SYNC.equals(request.getInvokeType())) {
return invoker.invoke(request);
}
String applicationName = getApplicationName(request);
String interfaceResourceName = getInterfaceResourceName(request);
String methodResourceName = getMethodResourceName(request);
Entry interfaceEntry = null;
Entry methodEntry = null;
try {
ContextUtil.enter(methodResourceName, applicationName);
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, getMethodArguments(request));
SofaResponse response = invoker.invoke(request);
traceResponseException(response, interfaceEntry, methodEntry);
return response;
} catch (BlockException e) {
return SofaRpcFallbackRegistry.getProviderFallback().handle(invoker, request, e);
} catch (Throwable t) {
throw traceOtherException(t, interfaceEntry, methodEntry);
} finally {
if (methodEntry != null) {
methodEntry.exit(1, getMethodArguments(request));
}
if (interfaceEntry != null) {
interfaceEntry.exit();
}
ContextUtil.exit();
}
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.adapter.sofa.rpc;
import com.alipay.sofa.rpc.common.RemotingConstants;
import com.alipay.sofa.rpc.core.request.SofaRequest;
/**
* @author cdfive
*/
public class SofaRpcUtils {
public static String getApplicationName(SofaRequest request) {
String appName = (String) request.getRequestProp(RemotingConstants.HEAD_APP_NAME);
return appName == null ? "" : appName;
}
public static String getInterfaceResourceName(SofaRequest request) {
return request.getInterfaceName();
}
public static String getMethodResourceName(SofaRequest request) {
StringBuilder buf = new StringBuilder(64);
buf.append(request.getInterfaceName())
.append("#")
.append(request.getMethodName())
.append("(");
boolean isFirst = true;
for (String methodArgSig : request.getMethodArgSigs()) {
if (!isFirst) {
buf.append(",");
} else {
isFirst = false;
}
buf.append(methodArgSig);
}
buf.append(")");
return buf.toString();
}
public static Object[] getMethodArguments(SofaRequest request) {
return request.getMethodArgs();
}
}

View File

@ -0,0 +1,9 @@
package com.alibaba.csp.sentinel.adapter.sofa.rpc.config;
/**
* @author cdfive
*/
public class SofaRpcConfig {
public static final String SOFA_RPC_SENTINEL_ENABLED = "sofa.rpc.sentinel.enabled";
}

View File

@ -0,0 +1,37 @@
/*
* 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.adapter.sofa.rpc.fallback;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.filter.FilterInvoker;
/**
* Default Sentinel fallback handler for SOFARPC services.
* Just wrap and throw the exception.
*
* @author cdfive
*/
public class DefaultSofaRpcFallback implements SofaRpcFallback {
@Override
public SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex) {
// Just wrap and throw the exception.
throw new SentinelRpcException(ex);
}
}

View File

@ -0,0 +1,39 @@
/*
* 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.adapter.sofa.rpc.fallback;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.filter.FilterInvoker;
/**
* Sentinel fallback handler for SOFARPC services.
*
* @author cdfive
*/
public interface SofaRpcFallback {
/**
* Handle the block exception and provide fallback result.
*
* @param invoker FilterInvoker
* @param request SofaRequest
* @param ex block exception
* @return fallback result
*/
SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex);
}

View File

@ -0,0 +1,46 @@
/*
* 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.adapter.sofa.rpc.fallback;
/**
* Global Sentinel fallback registry for SOFARPC services.
*
* @author cdfive
*/
public final class SofaRpcFallbackRegistry {
private static volatile SofaRpcFallback providerFallback = new DefaultSofaRpcFallback();
private static volatile SofaRpcFallback consumerFallback = new DefaultSofaRpcFallback();
public static SofaRpcFallback getProviderFallback() {
return providerFallback;
}
public static void setProviderFallback(SofaRpcFallback providerFallback) {
SofaRpcFallbackRegistry.providerFallback = providerFallback;
}
public static SofaRpcFallback getConsumerFallback() {
return consumerFallback;
}
public static void setConsumerFallback(SofaRpcFallback consumerFallback) {
SofaRpcFallbackRegistry.consumerFallback = consumerFallback;
}
private SofaRpcFallbackRegistry() {}
}

View File

@ -0,0 +1,3 @@
# name # order
com.alibaba.csp.sentinel.adapter.sofa.rpc.SentinelSofaRpcProviderFilter # -1000
com.alibaba.csp.sentinel.adapter.sofa.rpc.SentinelSofaRpcConsumerFilter # -1000

View File

@ -0,0 +1,109 @@
package com.alibaba.csp.sentinel.adapter.sofa.rpc;
import com.alibaba.csp.sentinel.adapter.sofa.rpc.config.SofaRpcConfig;
import com.alipay.sofa.rpc.codec.Serializer;
import com.alipay.sofa.rpc.common.RpcConfigs;
import com.alipay.sofa.rpc.config.ConsumerConfig;
import com.alipay.sofa.rpc.config.ProviderConfig;
import com.alipay.sofa.rpc.filter.FilterInvoker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Method;
import static org.junit.Assert.*;
/**
* Test cases for {@link AbstractSofaRpcFilter}.
*
* @author cdfive
*/
public class AbstractSofaRpcFilterTest {
@Before
public void setUp() {
removeRpcConfig(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED);
}
@After
public void cleanUp() {
removeRpcConfig(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED);
}
@Test
public void testNeedToLoadProvider() {
SentinelSofaRpcProviderFilter providerFilter = new SentinelSofaRpcProviderFilter();
ProviderConfig providerConfig = new ProviderConfig();
providerConfig.setInterfaceId(Serializer.class.getName());
providerConfig.setId("AAA");
FilterInvoker invoker = new FilterInvoker(null, null, providerConfig);
assertTrue(providerFilter.needToLoad(invoker));
providerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
assertFalse(providerFilter.needToLoad(invoker));
providerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "");
assertTrue(providerFilter.needToLoad(invoker));
RpcConfigs.putValue(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
assertFalse(providerFilter.needToLoad(invoker));
}
@Test
public void testNeedToLoadConsumer() {
SentinelSofaRpcConsumerFilter consumerFilter = new SentinelSofaRpcConsumerFilter();
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setInterfaceId(Serializer.class.getName());
consumerConfig.setId("BBB");
FilterInvoker invoker = new FilterInvoker(null, null, consumerConfig);
assertTrue(consumerFilter.needToLoad(invoker));
consumerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
assertFalse(consumerFilter.needToLoad(invoker));
consumerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "");
assertTrue(consumerFilter.needToLoad(invoker));
RpcConfigs.putValue(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
assertFalse(consumerFilter.needToLoad(invoker));
}
@Test
public void testNeedToLoadProviderAndConsumer() {
SentinelSofaRpcProviderFilter providerFilter = new SentinelSofaRpcProviderFilter();
ProviderConfig providerConfig = new ProviderConfig();
providerConfig.setInterfaceId(Serializer.class.getName());
providerConfig.setId("AAA");
FilterInvoker providerInvoker = new FilterInvoker(null, null, providerConfig);
assertTrue(providerFilter.needToLoad(providerInvoker));
SentinelSofaRpcConsumerFilter consumerFilter = new SentinelSofaRpcConsumerFilter();
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setInterfaceId(Serializer.class.getName());
consumerConfig.setId("BBB");
FilterInvoker consumerInvoker = new FilterInvoker(null, null, consumerConfig);
assertTrue(consumerFilter.needToLoad(consumerInvoker));
providerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
assertFalse(providerFilter.needToLoad(providerInvoker));
assertTrue(consumerFilter.needToLoad(consumerInvoker));
providerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "");
assertTrue(providerFilter.needToLoad(providerInvoker));
RpcConfigs.putValue(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
assertFalse(providerFilter.needToLoad(providerInvoker));
assertFalse(consumerFilter.needToLoad(consumerInvoker));
}
private void removeRpcConfig(String key) {
try {
Method removeValueMethod = RpcConfigs.class.getDeclaredMethod("removeValue", String.class);
removeValueMethod.setAccessible(true);
removeValueMethod.invoke(null, key);
} catch (Exception e) {
// Empty
}
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.adapter.sofa.rpc;
import com.alibaba.csp.sentinel.Constants;
import com.alibaba.csp.sentinel.CtSph;
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import java.lang.reflect.Method;
/**
* Base test class, provide common methods for sub test class.
*
* Note: Only for test. DO NOT USE IN PRODUCTION!
*
* @author cdfive
*/
public class BaseTest {
/**
* Clean up resources.
*/
protected static void cleanUpAll() {
Context context = ContextUtil.getContext();
if (context != null) {
context.setCurEntry(null);
ContextUtil.exit();
}
Constants.ROOT.removeChildList();
ClusterBuilderSlot.getClusterNodeMap().clear();
// Clear chainMap in CtSph
try {
Method resetChainMapMethod = CtSph.class.getDeclaredMethod("resetChainMap");
resetChainMapMethod.setAccessible(true);
resetChainMapMethod.invoke(null);
} catch (Exception e) {
// Empty
}
}
}

View File

@ -0,0 +1,155 @@
/*
* 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.adapter.sofa.rpc;
import com.alibaba.csp.sentinel.Constants;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.node.ClusterNode;
import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.node.StatisticNode;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alipay.sofa.rpc.common.RpcConstants;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.filter.FilterInvoker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* Test cases for {@link SentinelSofaRpcConsumerFilter}.
*
* @author cdfive
*/
public class SentinelSofaRpcConsumerFilterTest extends BaseTest {
@Before
public void setUp() {
cleanUpAll();
}
@After
public void cleanUp() {
cleanUpAll();
}
@Test
public void testInvokeSentinelWorks() {
SentinelSofaRpcConsumerFilter filter = new SentinelSofaRpcConsumerFilter();
final String interfaceResourceName = "com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService";
final String methodResourceName = "com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService#sayHello(java.lang.String,int)";
SofaRequest request = mock(SofaRequest.class);
when(request.getInvokeType()).thenReturn(RpcConstants.INVOKER_TYPE_SYNC);
when(request.getInterfaceName()).thenReturn(interfaceResourceName);
when(request.getMethodName()).thenReturn("sayHello");
when(request.getMethodArgSigs()).thenReturn(new String[]{"java.lang.String", "int"});
when(request.getMethodArgs()).thenReturn(new Object[]{"Sentinel", 2020});
FilterInvoker filterInvoker = mock(FilterInvoker.class);
when(filterInvoker.invoke(request)).thenAnswer(new Answer<SofaResponse>() {
@Override
public SofaResponse answer(InvocationOnMock invocationOnMock) throws Throwable {
verifyInvocationStructure(interfaceResourceName, methodResourceName);
SofaResponse response = new SofaResponse();
response.setAppResponse("Hello Sentinel 2020");
return response;
}
});
// Before invoke
assertNull(ContextUtil.getContext());
// Do invoke
SofaResponse response = filter.invoke(filterInvoker, request);
assertEquals("Hello Sentinel 2020", response.getAppResponse());
verify(filterInvoker).invoke(request);
// After invoke, make sure exit context
assertNull(ContextUtil.getContext());
}
/**
* Verify Sentinel invocation structure in memory:
* EntranceNode(defaultContextName)
* --InterfaceNode(interfaceName)
* ----MethodNode(resourceName)
*/
private void verifyInvocationStructure(String interfaceResourceName, String methodResourceName) {
Context context = ContextUtil.getContext();
assertNotNull(context);
// As not call ContextUtil.enter(methodResourceName, applicationName) in SentinelSofaRpcConsumerFilter, use default context
// In actual project, a consumer is usually also a provider, the context will be created by SentinelSofaRpcProviderFilter
// If consumer is on the top of SOFARPC invocation chain, use default context
assertEquals(Constants.CONTEXT_DEFAULT_NAME, context.getName());
assertEquals("", context.getOrigin());
DefaultNode entranceNode = context.getEntranceNode();
ResourceWrapper entranceResource = entranceNode.getId();
assertEquals(Constants.CONTEXT_DEFAULT_NAME, entranceResource.getName());
assertSame(EntryType.IN, entranceResource.getEntryType());
// As SphU.entry(interfaceResourceName, EntryType.OUT);
Set<Node> childList = entranceNode.getChildList();
assertEquals(1, childList.size());
DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
ResourceWrapper interfaceResource = interfaceNode.getId();
assertEquals(interfaceResourceName, interfaceResource.getName());
assertSame(EntryType.OUT, interfaceResource.getEntryType());
// As SphU.entry(methodResourceName, EntryType.OUT);
childList = interfaceNode.getChildList();
assertEquals(1, childList.size());
DefaultNode methodNode = (DefaultNode) childList.iterator().next();
ResourceWrapper methodResource = methodNode.getId();
assertEquals(methodResourceName, methodResource.getName());
assertSame(EntryType.OUT, methodResource.getEntryType());
// Verify curEntry
Entry curEntry = context.getCurEntry();
assertSame(methodNode, curEntry.getCurNode());
assertSame(interfaceNode, curEntry.getLastNode());
// As context origin is not "", no originNode should be created in curEntry
assertNull(curEntry.getOriginNode());
// Verify clusterNode
ClusterNode methodClusterNode = methodNode.getClusterNode();
ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
// Different resource->Different ProcessorSlot->Different ClusterNode
assertNotSame(methodClusterNode, interfaceClusterNode);
// As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode
Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
assertEquals(0, methodOriginCountMap.size());
Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
assertEquals(0, interfaceOriginCountMap.size());
}
}

View File

@ -0,0 +1,154 @@
/*
* 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.adapter.sofa.rpc;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.node.ClusterNode;
import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.node.StatisticNode;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alipay.sofa.rpc.common.RpcConstants;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.filter.FilterInvoker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* Test cases for {@link SentinelSofaRpcProviderFilter}.
*
* @author cdfive
*/
public class SentinelSofaRpcProviderFilterTest extends BaseTest {
@Before
public void setUp() {
cleanUpAll();
}
@After
public void cleanUp() {
cleanUpAll();
}
@Test
public void testInvokeSentinelWorks() {
SentinelSofaRpcProviderFilter filter = new SentinelSofaRpcProviderFilter();
final String applicationName = "demo-provider";
final String interfaceResourceName = "com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService";
final String methodResourceName = "com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService#sayHello(java.lang.String,int)";
SofaRequest request = mock(SofaRequest.class);
when(request.getRequestProp("app")).thenReturn(applicationName);
when(request.getInvokeType()).thenReturn(RpcConstants.INVOKER_TYPE_SYNC);
when(request.getInterfaceName()).thenReturn(interfaceResourceName);
when(request.getMethodName()).thenReturn("sayHello");
when(request.getMethodArgSigs()).thenReturn(new String[]{"java.lang.String", "int"});
when(request.getMethodArgs()).thenReturn(new Object[]{"Sentinel", 2020});
FilterInvoker filterInvoker = mock(FilterInvoker.class);
when(filterInvoker.invoke(request)).thenAnswer(new Answer<SofaResponse>() {
@Override
public SofaResponse answer(InvocationOnMock invocationOnMock) throws Throwable {
verifyInvocationStructure(applicationName, interfaceResourceName, methodResourceName);
SofaResponse response = new SofaResponse();
response.setAppResponse("Hello Sentinel 2020");
return response;
}
});
// Before invoke
assertNull(ContextUtil.getContext());
// Do invoke
SofaResponse response = filter.invoke(filterInvoker, request);
assertEquals("Hello Sentinel 2020", response.getAppResponse());
verify(filterInvoker).invoke(request);
// After invoke, make sure exit context
assertNull(ContextUtil.getContext());
}
/**
* Verify Sentinel invocation structure in memory:
* EntranceNode(methodResourceName)
* --InterfaceNode(interfaceResourceName)
* ----MethodNode(methodResourceName)
*/
private void verifyInvocationStructure(String applicationName, String interfaceResourceName, String methodResourceName) {
Context context = ContextUtil.getContext();
assertNotNull(context);
assertEquals(methodResourceName, context.getName());
assertEquals(applicationName, context.getOrigin());
DefaultNode entranceNode = context.getEntranceNode();
ResourceWrapper entranceResource = entranceNode.getId();
assertEquals(methodResourceName, entranceResource.getName());
assertSame(EntryType.IN, entranceResource.getEntryType());
// As SphU.entry(interfaceResourceName, EntryType.IN);
Set<Node> childList = entranceNode.getChildList();
assertEquals(1, childList.size());
DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
ResourceWrapper interfaceResource = interfaceNode.getId();
assertEquals(interfaceResourceName, interfaceResource.getName());
assertSame(EntryType.IN, interfaceResource.getEntryType());
// As SphU.entry(methodResourceName, EntryType.IN, 1, methodArguments);
childList = interfaceNode.getChildList();
assertEquals(1, childList.size());
DefaultNode methodNode = (DefaultNode) childList.iterator().next();
ResourceWrapper methodResource = methodNode.getId();
assertEquals(methodResourceName, methodResource.getName());
assertSame(EntryType.IN, methodResource.getEntryType());
// Verify curEntry
Entry curEntry = context.getCurEntry();
assertSame(methodNode, curEntry.getCurNode());
assertSame(interfaceNode, curEntry.getLastNode());
// As context origin is not "", originNode should be created
assertNotNull(curEntry.getOriginNode());
// Verify clusterNode
ClusterNode methodClusterNode = methodNode.getClusterNode();
ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
// Different resource->Different ProcessorSlot->Different ClusterNode
assertNotSame(methodClusterNode, interfaceClusterNode);
// As context origin is not "", the StatisticNode should be created in originCountMap of ClusterNode
Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
assertEquals(1, methodOriginCountMap.size());
assertTrue(methodOriginCountMap.containsKey(applicationName));
Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
assertEquals(1, interfaceOriginCountMap.size());
assertTrue(interfaceOriginCountMap.containsKey(applicationName));
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.adapter.sofa.rpc;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test cases for {@link SofaRpcUtils}.
*
* @author cdfive
*/
public class SofaRpcUtilsTest {
@Test
public void testGetApplicationName() {
SofaRequest request = new SofaRequest();
String applicationName = SofaRpcUtils.getApplicationName(request);
assertEquals("", applicationName);
request.addRequestProp("app", "test-app");
applicationName = SofaRpcUtils.getApplicationName(request);
assertEquals("test-app", applicationName);
}
@Test
public void testGetInterfaceResourceName() {
SofaRequest request = new SofaRequest();
request.setInterfaceName("com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService");
String interfaceResourceName = SofaRpcUtils.getInterfaceResourceName(request);
assertEquals("com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService", interfaceResourceName);
}
@Test
public void testGetMethodResourceName() {
SofaRequest request = new SofaRequest();
request.setInterfaceName("com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService");
request.setMethodName("sayHello");
request.setMethodArgSigs(new String[]{"java.lang.String", "int"});
String methodResourceName = SofaRpcUtils.getMethodResourceName(request);
assertEquals("com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService#sayHello(java.lang.String,int)", methodResourceName);
}
@Test
public void testGetMethodArguments() {
SofaRequest request = new SofaRequest();
request.setMethodArgs(new Object[]{"Sentinel", 2020});
Object[] arguments = SofaRpcUtils.getMethodArguments(request);
assertEquals(arguments.length, 2);
assertEquals("Sentinel", arguments[0]);
assertEquals(2020, arguments[1]);
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.adapter.sofa.rpc.fallback;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* Test cases for {@link DefaultSofaRpcFallback}.
*
* @author cdfive
*/
public class DefaultSofaRpcFallbackTest {
@Test
public void testHandle() {
SofaRpcFallback sofaRpcFallback = new DefaultSofaRpcFallback();
BlockException blockException = mock(BlockException.class);
boolean throwSentinelRpcException = false;
boolean causeIsBlockException = false;
try {
sofaRpcFallback.handle(null, null, blockException);
} catch (Exception e) {
throwSentinelRpcException = e instanceof SentinelRpcException;
causeIsBlockException = e.getCause() instanceof BlockException;
}
assertTrue(throwSentinelRpcException);
assertTrue(causeIsBlockException);
}
}

View File

@ -0,0 +1,74 @@
/*
* 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.adapter.sofa.rpc.fallback;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.filter.FilterInvoker;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test cases for {@link SofaRpcFallbackRegistry}.
*
* @author cdfive
*/
public class SofaRpcFallbackRegistryTest {
@Test
public void testDefaultfallback() {
// Test get default provider fallback
SofaRpcFallback providerFallback = SofaRpcFallbackRegistry.getProviderFallback();
assertNotNull(providerFallback);
assertTrue(providerFallback instanceof DefaultSofaRpcFallback);
// Test get default consumer fallback
SofaRpcFallback consumerFallback = SofaRpcFallbackRegistry.getConsumerFallback();
assertNotNull(consumerFallback);
assertTrue(consumerFallback instanceof DefaultSofaRpcFallback);
}
@Test
public void testCustomFallback() {
// Test invoke custom provider fallback
SofaRpcFallbackRegistry.setProviderFallback(new SofaRpcFallback() {
@Override
public SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex) {
SofaResponse response = new SofaResponse();
response.setAppResponse("test provider response");
return response;
}
});
SofaResponse providerResponse = SofaRpcFallbackRegistry.getProviderFallback().handle(null, null, null);
assertNotNull(providerResponse);
assertEquals("test provider response", providerResponse.getAppResponse());
// Test invoke custom consumer fallback
SofaRpcFallbackRegistry.setConsumerFallback(new SofaRpcFallback() {
@Override
public SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex) {
SofaResponse response = new SofaResponse();
response.setAppResponse("test consumer response");
return response;
}
});
SofaResponse consumerResponse = SofaRpcFallbackRegistry.getConsumerFallback().handle(null, null, null);
assertNotNull(consumerResponse);
assertEquals("test consumer response", consumerResponse.getAppResponse());
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.adapter.sofa.rpc.service;
/**
* @author cdfive
*/
public interface DemoService {
String sayHello(String name, int year);
}

View File

@ -0,0 +1,29 @@
/*
* 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.adapter.sofa.rpc.service.impl;
import com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService;
/**
* @author cdfive
*/
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name, int year) {
return "Hello " + name + " " + year;
}
}

View File

@ -32,6 +32,7 @@
<module>sentinel-demo-command-handler</module> <module>sentinel-demo-command-handler</module>
<module>sentinel-demo-spring-webflux</module> <module>sentinel-demo-spring-webflux</module>
<module>sentinel-demo-apache-dubbo</module> <module>sentinel-demo-apache-dubbo</module>
<module>sentinel-demo-sofa-rpc</module>
<module>sentinel-demo-spring-cloud-gateway</module> <module>sentinel-demo-spring-cloud-gateway</module>
<module>sentinel-demo-zuul-gateway</module> <module>sentinel-demo-zuul-gateway</module>
<module>sentinel-demo-etcd-datasource</module> <module>sentinel-demo-etcd-datasource</module>

View File

@ -0,0 +1,42 @@
# Sentinel SOFARPC Demo
Sentinel 提供了与 SOFARPC 整合的模块 - `sentinel-sofa-rpc-adapter`,主要包括针对 Service Provider 和 Service Consumer 实现的 Filter。使用时用户只需引入以下模块以 Maven 为例):
```xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-sofa-rpc-adapter</artifactId>
<version>x.y.z</version>
</dependency>
```
引入此依赖后SOFARPC 的服务接口和方法(包括调用端和服务端)就会成为 Sentinel 中的资源,在配置了规则后就可以自动享受到 Sentinel 的防护能力。
> **注:若希望接入 Dashboard请参考demo中的注释添加VM参数只引入`sentinel-sofa-rpc-adapter`无法接入控制台!**
若不希望开启 Sentinel SOFARPC Adapter 中的某个 Filter可以手动关闭对应的 Filter比如
```java
providerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
consumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
```
或者在`rpc-config.json`文件中设置,它的优先级要低一些。
```json
{
"sofa.rpc.sentinel.enabled": true
}
```
# 运行Demo
1. 启动控制台,运行`DashboardApplication`
2. 启动Provider运行`DemoProvider`VM参数`-Dproject.name=DemoProvider -Dcsp.sentinel.dashboard.server=localhost:8080`
3. 启动Consumer运行`DemoConsumer`VM参数`-Dproject.name=DemoConsumer -Dcsp.sentinel.dashboard.server=localhost:8080`
通过控制台实时监控、簇点链路菜单观察接口调用、资源情况;对资源设置不同流控规则,进行观察和调试。
参考:[Sentinel控制台](https://github.com/alibaba/Sentinel/wiki/控制台).

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sentinel-demo</artifactId>
<groupId>com.alibaba.csp</groupId>
<version>1.7.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel-demo-sofa-rpc</artifactId>
<properties>
<sofa-rpc-all.version>5.6.4</sofa-rpc-all.version>
<slf4j-log4j12.version>1.7.21</slf4j-log4j12.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-sofa-rpc-adapter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-rpc-all</artifactId>
<version>${sofa-rpc-all.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-log4j12.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,79 @@
/*
* 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.demo.sofa.rpc;
import com.alibaba.csp.sentinel.demo.sofa.rpc.service.DemoService;
import com.alipay.sofa.rpc.common.RpcConstants;
import com.alipay.sofa.rpc.config.ApplicationConfig;
import com.alipay.sofa.rpc.config.ConsumerConfig;
import java.util.concurrent.TimeUnit;
/**
* Demo consumer of SOFARPC.
*
* Interact with Sentinel Dashboard, add the following VM arguments:
* <pre>
* -Dproject.name=DemoProvider -Dcsp.sentinel.dashboard.server=localhost:8080
* </pre>
*
* @author cdfive
*/
public class DemoConsumer {
public static void main(String[] args) throws Exception {
ApplicationConfig application = new ApplicationConfig().setAppName("DemoConsumer");
ConsumerConfig<DemoService> consumerConfig = new ConsumerConfig<DemoService>()
.setApplication(application)
.setInterfaceId(DemoService.class.getName())
.setProtocol("bolt")
.setDirectUrl("bolt://127.0.0.1:12001")
.setInvokeType(RpcConstants.INVOKER_TYPE_SYNC);
// 设置是否启用Sentinel,默认启用
// 也可在rpc-config.json全局设置
// consumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
DemoService helloService = consumerConfig.refer();
System.out.println("DemoConsumer started!");
long sleepMs = 5;
int total = 5000;
int index = 0;
System.out.println("Total call " + total + " times and sleep " + sleepMs + "ms after each call.");
while (true) {
try {
index++;
String result = helloService.sayHello(index, "SOFARPC", 2020);
System.out.println("[" + index + "][Consumer]receive response: " + result);
} catch (Exception e) {
System.out.println("[" + index + "][Consumer]receive exception: " + e.getMessage());
}
TimeUnit.MILLISECONDS.sleep(sleepMs);
if (index == total) {
break;
}
}
System.out.println("DemoConsumer exit!");
System.exit(0);
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.demo.sofa.rpc;
import com.alibaba.csp.sentinel.demo.sofa.rpc.service.DemoService;
import com.alibaba.csp.sentinel.demo.sofa.rpc.service.impl.DemoServiceImpl;
import com.alipay.sofa.rpc.config.ProviderConfig;
import com.alipay.sofa.rpc.config.ServerConfig;
/**
* Demo provider of SOFARPC
*
* Interact with Sentinel Dashboard, add the following VM arguments:
* <pre>
* -Dproject.name=DemoProvider -Dcsp.sentinel.dashboard.server=localhost:8080
* </pre>
*
* @author cdfive
*/
public class DemoProvider {
public static void main(String[] args) {
ServerConfig serverConfig = new ServerConfig()
.setProtocol("bolt")
.setPort(12001)
.setDaemon(false);
ProviderConfig<DemoService> providerConfig = new ProviderConfig<DemoService>()
.setInterfaceId(DemoService.class.getName())
.setRef(new DemoServiceImpl())
.setServer(serverConfig);
// 设置是否启用Sentinel,默认启用
// 也可在rpc-config.json全局设置
// providerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
providerConfig.export();
System.out.println("DemoProvider started!");
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.demo.sofa.rpc.service;
/**
* @author cdfive
*/
public interface DemoService {
String sayHello(Integer index, String name, int year);
}

View File

@ -0,0 +1,41 @@
/*
* 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.demo.sofa.rpc.service.impl;
import com.alibaba.csp.sentinel.demo.sofa.rpc.service.DemoService;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
/**
* @author cdfive
*/
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(Integer index, String name, int year) {
System.out.println("[" + index + "][Provider]receive request: " + name + "," + year);
int sleepMs = ThreadLocalRandom.current().nextInt(50);
try {
TimeUnit.MILLISECONDS.sleep(sleepMs);
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
return "Hello " + name + " " + year + "[" + sleepMs + "ms]";
}
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %t %5p [%c:%M:%L] - %m%n"/>
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="CONSOLE"/>
</root>
</log4j:configuration>

View File

@ -0,0 +1,6 @@
{
"rpc.config.order": 999,
"logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl",
// Sentinel,true
"sofa.rpc.sentinel.enabled": true
}