From 18acb1d154d0412fc34a2db541ffa6bbfd1eff6c Mon Sep 17 00:00:00 2001 From: cdfive <31885791+cdfive@users.noreply.github.com> Date: Mon, 2 Mar 2020 18:13:54 +0800 Subject: [PATCH] Add Sentinel SOFARPC adapter module (#1307) --- sentinel-adapter/pom.xml | 1 + .../sentinel-sofa-rpc-adapter/README.md | 63 +++++++ .../sentinel-sofa-rpc-adapter/pom.xml | 43 +++++ .../sofa/rpc/AbstractSofaRpcFilter.java | 57 +++++++ .../rpc/SentinelSofaRpcConsumerFilter.java | 82 +++++++++ .../rpc/SentinelSofaRpcProviderFilter.java | 93 +++++++++++ .../adapter/sofa/rpc/SofaRpcUtils.java | 59 +++++++ .../sofa/rpc/config/SofaRpcConfig.java | 9 + .../rpc/fallback/DefaultSofaRpcFallback.java | 37 +++++ .../sofa/rpc/fallback/SofaRpcFallback.java | 39 +++++ .../rpc/fallback/SofaRpcFallbackRegistry.java | 46 ++++++ .../com.alipay.sofa.rpc.filter.Filter | 3 + .../sofa/rpc/AbstractSofaRpcFilterTest.java | 109 ++++++++++++ .../sentinel/adapter/sofa/rpc/BaseTest.java | 58 +++++++ .../SentinelSofaRpcConsumerFilterTest.java | 155 ++++++++++++++++++ .../SentinelSofaRpcProviderFilterTest.java | 154 +++++++++++++++++ .../adapter/sofa/rpc/SofaRpcUtilsTest.java | 68 ++++++++ .../fallback/DefaultSofaRpcFallbackTest.java | 48 ++++++ .../fallback/SofaRpcFallbackRegistryTest.java | 74 +++++++++ .../adapter/sofa/rpc/service/DemoService.java | 24 +++ .../rpc/service/impl/DemoServiceImpl.java | 29 ++++ sentinel-demo/pom.xml | 1 + .../sentinel-demo-sofa-rpc/README.md | 42 +++++ sentinel-demo/sentinel-demo-sofa-rpc/pom.xml | 44 +++++ .../sentinel/demo/sofa/rpc/DemoConsumer.java | 79 +++++++++ .../sentinel/demo/sofa/rpc/DemoProvider.java | 54 ++++++ .../demo/sofa/rpc/service/DemoService.java | 24 +++ .../rpc/service/impl/DemoServiceImpl.java | 41 +++++ .../src/main/resources/log4j.xml | 16 ++ .../main/resources/sofa-rpc/rpc-config.json | 6 + 30 files changed, 1558 insertions(+) create mode 100755 sentinel-adapter/sentinel-sofa-rpc-adapter/README.md create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/config/SofaRpcConfig.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilterTest.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilterTest.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtilsTest.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallbackTest.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistryTest.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/DemoService.java create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/impl/DemoServiceImpl.java create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/README.md create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/pom.xml create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoConsumer.java create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoProvider.java create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/DemoService.java create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/impl/DemoServiceImpl.java create mode 100755 sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/log4j.xml create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/sofa-rpc/rpc-config.json diff --git a/sentinel-adapter/pom.xml b/sentinel-adapter/pom.xml index 1f152c16..d1bdc9e6 100755 --- a/sentinel-adapter/pom.xml +++ b/sentinel-adapter/pom.xml @@ -18,6 +18,7 @@ sentinel-web-servlet sentinel-dubbo-adapter sentinel-apache-dubbo-adapter + sentinel-sofa-rpc-adapter sentinel-grpc-adapter sentinel-zuul-adapter sentinel-reactor-adapter diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/README.md b/sentinel-adapter/sentinel-sofa-rpc-adapter/README.md new file mode 100755 index 00000000..ee9d2522 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/README.md @@ -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 + + com.alibaba.csp + sentinel-sofa-rpc-adapter + x.y.z + +``` + +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 interface:resourceName format is `interfaceName`,e.g. `com.alibaba.csp.sentinel.demo.sofa.rpc.DemoService` +- Service method:resourceName 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. \ No newline at end of file diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml b/sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml new file mode 100644 index 00000000..12b91a9d --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml @@ -0,0 +1,43 @@ + + + + sentinel-adapter + com.alibaba.csp + 1.7.2-SNAPSHOT + + 4.0.0 + + sentinel-sofa-rpc-adapter + + + 5.6.4 + + + + + com.alibaba.csp + sentinel-core + + + + com.alipay.sofa + sofa-rpc-all + ${sofa-rpc-all.version} + provided + + + + junit + junit + test + + + + org.mockito + mockito-core + test + + + \ No newline at end of file diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java new file mode 100644 index 00000000..850f255a --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java @@ -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; + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java new file mode 100644 index 00000000..c881be5a --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java @@ -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: + *
ConsumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+ * + * or add setting in rpc-config.json: + *
"sofa.rpc.sentinel.enabled": false 
+ * + * @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(); + } + } + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java new file mode 100644 index 00000000..6ffa95a9 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java @@ -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: + *
ProviderConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+ * + * or add setting in rpc-config.json file: + *
+ * {
+ *   "sofa.rpc.sentinel.enabled": false
+ * }
+ * 
+ * + * @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(); + } + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java new file mode 100644 index 00000000..f313c8a1 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java @@ -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(); + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/config/SofaRpcConfig.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/config/SofaRpcConfig.java new file mode 100644 index 00000000..b63755ec --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/config/SofaRpcConfig.java @@ -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"; +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java new file mode 100644 index 00000000..a85bb828 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java @@ -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); + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java new file mode 100644 index 00000000..e025eee8 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java @@ -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); +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java new file mode 100644 index 00000000..15361e3b --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java @@ -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() {} +} + diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter new file mode 100644 index 00000000..6c12ce2d --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter @@ -0,0 +1,3 @@ +# name # order +com.alibaba.csp.sentinel.adapter.sofa.rpc.SentinelSofaRpcProviderFilter # -1000 +com.alibaba.csp.sentinel.adapter.sofa.rpc.SentinelSofaRpcConsumerFilter # -1000 \ No newline at end of file diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java new file mode 100644 index 00000000..5d1d5303 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java @@ -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 + } + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java new file mode 100644 index 00000000..9f2a7508 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java @@ -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 + } + } +} \ No newline at end of file diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilterTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilterTest.java new file mode 100644 index 00000000..1c0b333a --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilterTest.java @@ -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() { + @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 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 methodOriginCountMap = methodClusterNode.getOriginCountMap(); + assertEquals(0, methodOriginCountMap.size()); + + Map interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap(); + assertEquals(0, interfaceOriginCountMap.size()); + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilterTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilterTest.java new file mode 100644 index 00000000..5673aa96 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilterTest.java @@ -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() { + @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 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 methodOriginCountMap = methodClusterNode.getOriginCountMap(); + assertEquals(1, methodOriginCountMap.size()); + assertTrue(methodOriginCountMap.containsKey(applicationName)); + Map interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap(); + assertEquals(1, interfaceOriginCountMap.size()); + assertTrue(interfaceOriginCountMap.containsKey(applicationName)); + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtilsTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtilsTest.java new file mode 100644 index 00000000..f9f019a8 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtilsTest.java @@ -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]); + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallbackTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallbackTest.java new file mode 100644 index 00000000..af707727 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallbackTest.java @@ -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); + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistryTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistryTest.java new file mode 100644 index 00000000..15930d10 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistryTest.java @@ -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()); + } +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/DemoService.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/DemoService.java new file mode 100644 index 00000000..d767fd15 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/DemoService.java @@ -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); +} diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/impl/DemoServiceImpl.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/impl/DemoServiceImpl.java new file mode 100644 index 00000000..e87d7f37 --- /dev/null +++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/impl/DemoServiceImpl.java @@ -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; + } +} diff --git a/sentinel-demo/pom.xml b/sentinel-demo/pom.xml index 1f055d29..2e03da0e 100755 --- a/sentinel-demo/pom.xml +++ b/sentinel-demo/pom.xml @@ -32,6 +32,7 @@ sentinel-demo-command-handler sentinel-demo-spring-webflux sentinel-demo-apache-dubbo + sentinel-demo-sofa-rpc sentinel-demo-spring-cloud-gateway sentinel-demo-zuul-gateway sentinel-demo-etcd-datasource diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/README.md b/sentinel-demo/sentinel-demo-sofa-rpc/README.md new file mode 100644 index 00000000..ddf08319 --- /dev/null +++ b/sentinel-demo/sentinel-demo-sofa-rpc/README.md @@ -0,0 +1,42 @@ +# Sentinel SOFARPC Demo + +Sentinel 提供了与 SOFARPC 整合的模块 - `sentinel-sofa-rpc-adapter`,主要包括针对 Service Provider 和 Service Consumer 实现的 Filter。使用时用户只需引入以下模块(以 Maven 为例): + +```xml + + com.alibaba.csp + sentinel-sofa-rpc-adapter + x.y.z + +``` + +引入此依赖后,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/控制台). \ No newline at end of file diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/pom.xml b/sentinel-demo/sentinel-demo-sofa-rpc/pom.xml new file mode 100644 index 00000000..3eb808c6 --- /dev/null +++ b/sentinel-demo/sentinel-demo-sofa-rpc/pom.xml @@ -0,0 +1,44 @@ + + + + sentinel-demo + com.alibaba.csp + 1.7.2-SNAPSHOT + + 4.0.0 + + sentinel-demo-sofa-rpc + + + 5.6.4 + 1.7.21 + + + + + com.alibaba.csp + sentinel-sofa-rpc-adapter + ${project.version} + + + + com.alibaba.csp + sentinel-transport-simple-http + ${project.version} + + + + com.alipay.sofa + sofa-rpc-all + ${sofa-rpc-all.version} + + + + org.slf4j + slf4j-log4j12 + ${slf4j-log4j12.version} + + + \ No newline at end of file diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoConsumer.java b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoConsumer.java new file mode 100644 index 00000000..a4e31649 --- /dev/null +++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoConsumer.java @@ -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: + *
+ * -Dproject.name=DemoProvider -Dcsp.sentinel.dashboard.server=localhost:8080
+ * 
+ * + * @author cdfive + */ +public class DemoConsumer { + + public static void main(String[] args) throws Exception { + ApplicationConfig application = new ApplicationConfig().setAppName("DemoConsumer"); + + ConsumerConfig consumerConfig = new ConsumerConfig() + .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); + } +} \ No newline at end of file diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoProvider.java b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoProvider.java new file mode 100644 index 00000000..35415242 --- /dev/null +++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoProvider.java @@ -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: + *
+ * -Dproject.name=DemoProvider -Dcsp.sentinel.dashboard.server=localhost:8080
+ * 
+ * + * @author cdfive + */ +public class DemoProvider { + + public static void main(String[] args) { + ServerConfig serverConfig = new ServerConfig() + .setProtocol("bolt") + .setPort(12001) + .setDaemon(false); + + ProviderConfig providerConfig = new ProviderConfig() + .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!"); + } +} \ No newline at end of file diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/DemoService.java b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/DemoService.java new file mode 100644 index 00000000..a1a6318c --- /dev/null +++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/DemoService.java @@ -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); +} \ No newline at end of file diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/impl/DemoServiceImpl.java b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/impl/DemoServiceImpl.java new file mode 100644 index 00000000..5a842eaa --- /dev/null +++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/impl/DemoServiceImpl.java @@ -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]"; + } +} \ No newline at end of file diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/log4j.xml b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/log4j.xml new file mode 100755 index 00000000..e95634f1 --- /dev/null +++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/log4j.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/sofa-rpc/rpc-config.json b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/sofa-rpc/rpc-config.json new file mode 100644 index 00000000..4c5458b2 --- /dev/null +++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/sofa-rpc/rpc-config.json @@ -0,0 +1,6 @@ +{ + "rpc.config.order": 999, + "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl", + // 是否启用Sentinel,不设置默认为true + "sofa.rpc.sentinel.enabled": true +} \ No newline at end of file