From 6bb2de875008cf131149edf80d630da80ebb0900 Mon Sep 17 00:00:00 2001 From: Eric Zhao Date: Wed, 6 Nov 2019 16:10:25 +0800 Subject: [PATCH] Support classification for Sentinel resources Signed-off-by: Eric Zhao --- .../com/alibaba/csp/sentinel/Constants.java | 4 +- .../java/com/alibaba/csp/sentinel/CtSph.java | 32 ++++++- .../csp/sentinel/ResourceTypeConstants.java | 31 ++++++ .../java/com/alibaba/csp/sentinel/Sph.java | 2 +- .../csp/sentinel/SphResourceTypeSupport.java | 69 ++++++++++++++ .../java/com/alibaba/csp/sentinel/SphU.java | 95 ++++++++++++++++++- .../sentinel/annotation/SentinelResource.java | 6 ++ .../csp/sentinel/node/ClusterNode.java | 39 +++++++- .../csp/sentinel/node/metric/MetricNode.java | 71 ++++++++++++-- .../node/metric/MetricTimerListener.java | 12 +-- .../slotchain/MethodResourceWrapper.java | 24 ++--- .../sentinel/slotchain/ResourceWrapper.java | 48 ++++++++-- .../slotchain/StringResourceWrapper.java | 24 ++--- .../clusterbuilder/ClusterBuilderSlot.java | 2 +- .../slots/statistic/StatisticSlot.java | 10 +- .../slots/system/SystemRuleManager.java | 2 +- .../com/alibaba/csp/sentinel/CtSphTest.java | 6 +- .../com/alibaba/csp/sentinel/SphOTest.java | 16 ++-- .../com/alibaba/csp/sentinel/SphUTest.java | 20 ++-- .../csp/sentinel/node/ClusterNodeTest.java | 6 +- .../sentinel/node/metric/MetricNodeTest.java | 37 ++++++++ 21 files changed, 462 insertions(+), 94 deletions(-) create mode 100644 sentinel-core/src/main/java/com/alibaba/csp/sentinel/ResourceTypeConstants.java create mode 100644 sentinel-core/src/main/java/com/alibaba/csp/sentinel/SphResourceTypeSupport.java create mode 100644 sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/metric/MetricNodeTest.java diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Constants.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Constants.java index 6e728bb9..01cf5263 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Constants.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Constants.java @@ -57,12 +57,12 @@ public final class Constants { * Global ROOT statistic node that represents the universal parent node. */ public final static DefaultNode ROOT = new EntranceNode(new StringResourceWrapper(ROOT_ID, EntryType.IN), - new ClusterNode()); + new ClusterNode(ROOT_ID, ResourceTypeConstants.COMMON)); /** * Global statistic node for inbound traffic. Usually used for {@link SystemRule} checking. */ - public final static ClusterNode ENTRY_NODE = new ClusterNode(); + public final static ClusterNode ENTRY_NODE = new ClusterNode(TOTAL_IN_RESOURCE_NAME, ResourceTypeConstants.COMMON); /** * Response time that exceeds TIME_DROP_VALVE will be calculated as TIME_DROP_VALVE. Default value is 4900 ms. diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/CtSph.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/CtSph.java index 0bb9c411..5c5b137b 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/CtSph.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/CtSph.java @@ -71,7 +71,7 @@ public class CtSph implements Sph { } if (context == null) { // Using default context. - context = MyContextUtil.myEnter(Constants.CONTEXT_DEFAULT_NAME, "", resourceWrapper.getType()); + context = InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME); } // Global switch is turned off, so no rule checking will be done. @@ -125,7 +125,7 @@ public class CtSph implements Sph { if (context == null) { // Using default context. - context = MyContextUtil.myEnter(Constants.CONTEXT_DEFAULT_NAME, "", resourceWrapper.getType()); + context = InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME); } // Global switch is close, no rule checking will do. @@ -245,8 +245,12 @@ public class CtSph implements Sph { /** * This class is used for skip context name checking. */ - private final static class MyContextUtil extends ContextUtil { - static Context myEnter(String name, String origin, EntryType type) { + private final static class InternalContextUtil extends ContextUtil { + static Context internalEnter(String name) { + return trueEnter(name, ""); + } + + static Context internalEnter(String name, String origin) { return trueEnter(name, origin); } } @@ -329,4 +333,24 @@ public class CtSph implements Sph { StringResourceWrapper resource = new StringResourceWrapper(name, type); return entryWithPriority(resource, count, prioritized, args); } + + @Override + public Entry entryWithType(String name, int resourceType, EntryType entryType, int count, Object[] args) + throws BlockException { + return entryWithType(name, resourceType, entryType, count, false, args); + } + + @Override + public Entry entryWithType(String name, int resourceType, EntryType entryType, int count, boolean prioritized, + Object[] args) throws BlockException { + StringResourceWrapper resource = new StringResourceWrapper(name, entryType, resourceType); + return entryWithPriority(resource, count, prioritized, args); + } + + @Override + public AsyncEntry asyncEntryWithType(String name, int resourceType, EntryType entryType, int count, + boolean prioritized, Object[] args) throws BlockException { + StringResourceWrapper resource = new StringResourceWrapper(name, entryType, resourceType); + return asyncEntryWithPriorityInternal(resource, count, prioritized, args); + } } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/ResourceTypeConstants.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/ResourceTypeConstants.java new file mode 100644 index 00000000..1ae421cc --- /dev/null +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/ResourceTypeConstants.java @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2019 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 + * + * https://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; + +/** + * @author Eric Zhao + * @since 1.7.0 + */ +public final class ResourceTypeConstants { + + public static final int COMMON = 0; + public static final int COMMON_WEB = 1; + public static final int COMMON_RPC = 2; + public static final int COMMON_API_GATEWAY = 3; + public static final int COMMON_DB_SQL = 4; + + private ResourceTypeConstants() {} +} diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Sph.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Sph.java index bedbd33b..32643b46 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Sph.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Sph.java @@ -29,7 +29,7 @@ import com.alibaba.csp.sentinel.slots.block.BlockException; * @author leyou * @author Eric Zhao */ -public interface Sph { +public interface Sph extends SphResourceTypeSupport { /** * Create a protected resource. diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/SphResourceTypeSupport.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/SphResourceTypeSupport.java new file mode 100644 index 00000000..4349473f --- /dev/null +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/SphResourceTypeSupport.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2019 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 + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel; + +import com.alibaba.csp.sentinel.slots.block.BlockException; + +/** + * @author Eric Zhao + * @since 1.7.0 + */ +public interface SphResourceTypeSupport { + + /** + * Create a protected resource with provided classification. + * + * @param name the unique name of the protected resource + * @param resourceType the classification of the resource + * @param entryType the traffic entry type (IN/OUT) of the resource + * @param count tokens required + * @param args extra parameters + * @return new entry of the resource + * @throws BlockException if the block criteria is met + */ + Entry entryWithType(String name, int resourceType, EntryType entryType, int count, Object[] args) + throws BlockException; + + /** + * Create a protected resource with provided classification. + * + * @param name the unique name of the protected resource + * @param resourceType the classification of the resource + * @param entryType the traffic entry type (IN/OUT) of the resource + * @param count tokens required + * @param prioritized whether the entry is prioritized + * @param args extra parameters + * @return new entry of the resource + * @throws BlockException if the block criteria is met + */ + Entry entryWithType(String name, int resourceType, EntryType entryType, int count, boolean prioritized, + Object[] args) throws BlockException; + + /** + * Create an asynchronous resource with provided classification. + * + * @param name the unique name of the protected resource + * @param resourceType the classification of the resource + * @param entryType the traffic entry type (IN/OUT) of the resource + * @param count tokens required + * @param prioritized whether the entry is prioritized + * @param args extra parameters + * @return new entry of the resource + * @throws BlockException if the block criteria is met + */ + AsyncEntry asyncEntryWithType(String name, int resourceType, EntryType entryType, int count, boolean prioritized, + Object[] args) throws BlockException; +} diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/SphU.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/SphU.java index 696b686f..a7ad2aa1 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/SphU.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/SphU.java @@ -76,6 +76,8 @@ public class SphU { private static final Object[] OBJECTS0 = new Object[0]; + private SphU() {} + /** * Checking all {@link Rule}s about the resource. * @@ -246,7 +248,7 @@ public class SphU { /** * Checking all {@link Rule}s related the resource. The entry is prioritized. * - * @param name the unique name for the protected resource + * @param name the unique name for the protected resource * @throws BlockException if the block criteria is met, eg. when any rule's threshold is exceeded. * @since 1.4.0 */ @@ -257,14 +259,97 @@ public class SphU { /** * Checking all {@link Rule}s related the resource. The entry is prioritized. * - * @param name the unique name for the protected resource - * @param type the resource is an inbound or an outbound method. This is used - * to mark whether it can be blocked when the system is unstable, - * only inbound traffic could be blocked by {@link SystemRule} + * @param name the unique name for the protected resource + * @param type the resource is an inbound or an outbound method. This is used + * to mark whether it can be blocked when the system is unstable, + * only inbound traffic could be blocked by {@link SystemRule} * @throws BlockException if the block criteria is met, eg. when any rule's threshold is exceeded. * @since 1.4.0 */ public static Entry entryWithPriority(String name, EntryType type) throws BlockException { return Env.sph.entryWithPriority(name, type, 1, true); } + + /** + * Record statistics and check all rules of the resource. + * + * @param name the unique name for the protected resource + * @param resourceType classification of the resource (e.g. Web or RPC) + * @param type the resource is an inbound or an outbound method. This is used + * to mark whether it can be blocked when the system is unstable, + * only inbound traffic could be blocked by {@link SystemRule} + * @throws BlockException if the block criteria is met, eg. when any rule's threshold is exceeded + * @since 1.7.0 + */ + public static Entry entry(String name, int resourceType, EntryType type) throws BlockException { + return Env.sph.entryWithType(name, resourceType, type, 1, OBJECTS0); + } + + /** + * Record statistics and check all rules of the resource. + * + * @param name the unique name for the protected resource + * @param type the resource is an inbound or an outbound method. This is used + * to mark whether it can be blocked when the system is unstable, + * only inbound traffic could be blocked by {@link SystemRule} + * @param resourceType classification of the resource (e.g. Web or RPC) + * @param args extra parameters. + * @throws BlockException if the block criteria is met, eg. when any rule's threshold is exceeded + * @since 1.7.0 + */ + public static Entry entry(String name, int resourceType, EntryType type, Object[] args) + throws BlockException { + return Env.sph.entryWithType(name, resourceType, type, 1, args); + } + + /** + * Record statistics and check all rules of the resource. + * + * @param name the unique name for the protected resource + * @param type the resource is an inbound or an outbound method. This is used + * to mark whether it can be blocked when the system is unstable, + * only inbound traffic could be blocked by {@link SystemRule} + * @param resourceType classification of the resource (e.g. Web or RPC) + * @throws BlockException if the block criteria is met, eg. when any rule's threshold is exceeded + * @since 1.7.0 + */ + public static AsyncEntry asyncEntry(String name, int resourceType, EntryType type) + throws BlockException { + return Env.sph.asyncEntryWithType(name, resourceType, type, 1, false, OBJECTS0); + } + + /** + * Record statistics and check all rules of the resource. + * + * @param name the unique name for the protected resource + * @param type the resource is an inbound or an outbound method. This is used + * to mark whether it can be blocked when the system is unstable, + * only inbound traffic could be blocked by {@link SystemRule} + * @param resourceType classification of the resource (e.g. Web or RPC) + * @param args extra parameters + * @throws BlockException if the block criteria is met, eg. when any rule's threshold is exceeded + * @since 1.7.0 + */ + public static AsyncEntry asyncEntry(String name, int resourceType, EntryType type, Object[] args) + throws BlockException { + return Env.sph.asyncEntryWithType(name, resourceType, type, 1, false, args); + } + + /** + * Record statistics and check all rules of the resource. + * + * @param name the unique name for the protected resource + * @param type the resource is an inbound or an outbound method. This is used + * to mark whether it can be blocked when the system is unstable, + * only inbound traffic could be blocked by {@link SystemRule} + * @param resourceType classification of the resource (e.g. Web or RPC) + * @param acquireCount tokens required + * @param args extra parameters + * @throws BlockException if the block criteria is met, eg. when any rule's threshold is exceeded + * @since 1.7.0 + */ + public static AsyncEntry asyncEntry(String name, int resourceType, EntryType type, int acquireCount, + Object[] args) throws BlockException { + return Env.sph.asyncEntryWithType(name, resourceType, type, acquireCount, false, args); + } } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/annotation/SentinelResource.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/annotation/SentinelResource.java index a0fa11d6..95f65848 100644 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/annotation/SentinelResource.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/annotation/SentinelResource.java @@ -40,6 +40,12 @@ public @interface SentinelResource { */ EntryType entryType() default EntryType.OUT; + /** + * @return the classification (type) of the resource + * @since 1.7.0 + */ + int resourceType() default 0; + /** * @return name of the block exception function, empty by default */ diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/ClusterNode.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/ClusterNode.java index c342697d..6f5f4ef4 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/ClusterNode.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/ClusterNode.java @@ -19,8 +19,10 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; +import com.alibaba.csp.sentinel.ResourceTypeConstants; import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.util.AssertUtil; /** *

@@ -42,6 +44,19 @@ import com.alibaba.csp.sentinel.slots.block.BlockException; */ public class ClusterNode extends StatisticNode { + private final String name; + private final int resourceType; + + public ClusterNode(String name) { + this(name, ResourceTypeConstants.COMMON); + } + + public ClusterNode(String name, int resourceType) { + AssertUtil.notEmpty(name, "name cannot be empty"); + this.name = name; + this.resourceType = resourceType; + } + /** *

The origin map holds the pair: (origin, originNode) for one specific resource.

*

@@ -50,10 +65,30 @@ public class ClusterNode extends StatisticNode { * at the very beginning while concurrent map will hold the lock all the time. *

*/ - private Map originCountMap = new HashMap(); + private Map originCountMap = new HashMap<>(); private final ReentrantLock lock = new ReentrantLock(); + /** + * Get resource name of the resource node. + * + * @return resource name + * @since 1.7.0 + */ + public String getName() { + return name; + } + + /** + * Get classification (type) of the resource. + * + * @return resource type + * @since 1.7.0 + */ + public int getResourceType() { + return resourceType; + } + /** *

Get {@link Node} of the specific origin. Usually the origin is the Service Consumer's app name.

*

If the origin node for given origin is absent, then a new {@link StatisticNode} @@ -84,7 +119,7 @@ public class ClusterNode extends StatisticNode { return statisticNode; } - public synchronized Map getOriginCountMap() { + public Map getOriginCountMap() { return originCountMap; } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/metric/MetricNode.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/metric/MetricNode.java index e1a6707c..2f8de6bc 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/metric/MetricNode.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/metric/MetricNode.java @@ -27,6 +27,13 @@ import java.util.Date; */ public class MetricNode { + private String resource; + /** + * Resource classification (e.g. SQL or RPC) + * @since 1.7.0 + */ + private int classification; + private long timestamp; private long passQps; private long blockQps; @@ -38,8 +45,10 @@ public class MetricNode { * @since 1.5.0 */ private long occupiedPassQps; - - private String resource; + /** + * @since 1.7.0 + */ + private int concurrency; public long getTimestamp() { return timestamp; @@ -105,12 +114,38 @@ public class MetricNode { this.resource = resource; } + public int getClassification() { + return classification; + } + + public MetricNode setClassification(int classification) { + this.classification = classification; + return this; + } + + public int getConcurrency() { + return concurrency; + } + + public MetricNode setConcurrency(int concurrency) { + this.concurrency = concurrency; + return this; + } + @Override public String toString() { - return "MetricNode{" + "timestamp=" + timestamp + ", passQps=" + passQps + ", blockQps=" + blockQps - + ", successQps=" + successQps + ", exceptionQps=" + exceptionQps + ", rt=" + rt - + ", occupiedPassQps=" + occupiedPassQps + ", resource='" - + resource + '\'' + '}'; + return "MetricNode{" + + "resource='" + resource + '\'' + + ", classification=" + classification + + ", timestamp=" + timestamp + + ", passQps=" + passQps + + ", blockQps=" + blockQps + + ", successQps=" + successQps + + ", exceptionQps=" + exceptionQps + + ", rt=" + rt + + ", concurrency=" + concurrency + + ", occupiedPassQps=" + occupiedPassQps + + '}'; } /** @@ -132,7 +167,9 @@ public class MetricNode { sb.append(successQps).append("|"); sb.append(exceptionQps).append("|"); sb.append(rt).append("|"); - sb.append(occupiedPassQps); + sb.append(occupiedPassQps).append("|"); + sb.append(concurrency).append("|"); + sb.append(classification); return sb.toString(); } @@ -152,9 +189,15 @@ public class MetricNode { node.setSuccessQps(Long.parseLong(strs[4])); node.setExceptionQps(Long.parseLong(strs[5])); node.setRt(Long.parseLong(strs[6])); - if (strs.length == 8) { + if (strs.length >= 8) { node.setOccupiedPassQps(Long.parseLong(strs[7])); } + if (strs.length >= 9) { + node.setConcurrency(Integer.parseInt(strs[8])); + } + if (strs.length == 10) { + node.setClassification(Integer.parseInt(strs[9])); + } return node; } @@ -180,7 +223,9 @@ public class MetricNode { sb.append(getSuccessQps()).append("|"); sb.append(getExceptionQps()).append("|"); sb.append(getRt()).append("|"); - sb.append(getOccupiedPassQps()); + sb.append(getOccupiedPassQps()).append("|"); + sb.append(concurrency).append("|"); + sb.append(classification); sb.append('\n'); return sb.toString(); } @@ -202,9 +247,15 @@ public class MetricNode { node.setSuccessQps(Long.parseLong(strs[5])); node.setExceptionQps(Long.parseLong(strs[6])); node.setRt(Long.parseLong(strs[7])); - if (strs.length == 9) { + if (strs.length >= 9) { node.setOccupiedPassQps(Long.parseLong(strs[8])); } + if (strs.length >= 10) { + node.setConcurrency(Integer.parseInt(strs[9])); + } + if (strs.length == 11) { + node.setClassification(Integer.parseInt(strs[10])); + } return node; } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/metric/MetricTimerListener.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/metric/MetricTimerListener.java index 4e3d3a1e..93992cc9 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/metric/MetricTimerListener.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/metric/MetricTimerListener.java @@ -38,14 +38,13 @@ public class MetricTimerListener implements Runnable { @Override public void run() { - Map> maps = new TreeMap>(); + Map> maps = new TreeMap<>(); for (Entry e : ClusterBuilderSlot.getClusterNodeMap().entrySet()) { - String name = e.getKey().getName(); ClusterNode node = e.getValue(); Map metrics = node.metrics(); - aggregate(maps, metrics, name); + aggregate(maps, metrics, node); } - aggregate(maps, Constants.ENTRY_NODE.metrics(), Constants.TOTAL_IN_RESOURCE_NAME); + aggregate(maps, Constants.ENTRY_NODE.metrics(), Constants.ENTRY_NODE); if (!maps.isEmpty()) { for (Entry> entry : maps.entrySet()) { try { @@ -57,11 +56,12 @@ public class MetricTimerListener implements Runnable { } } - private void aggregate(Map> maps, Map metrics, String resourceName) { + private void aggregate(Map> maps, Map metrics, ClusterNode node) { for (Entry entry : metrics.entrySet()) { long time = entry.getKey(); MetricNode metricNode = entry.getValue(); - metricNode.setResource(resourceName); + metricNode.setResource(node.getName()); + metricNode.setClassification(node.getResourceType()); if (maps.get(time) == null) { maps.put(time, new ArrayList()); } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/MethodResourceWrapper.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/MethodResourceWrapper.java index 77d17474..5f89daf7 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/MethodResourceWrapper.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/MethodResourceWrapper.java @@ -18,6 +18,7 @@ package com.alibaba.csp.sentinel.slotchain; import java.lang.reflect.Method; import com.alibaba.csp.sentinel.EntryType; +import com.alibaba.csp.sentinel.ResourceTypeConstants; import com.alibaba.csp.sentinel.util.IdUtil; import com.alibaba.csp.sentinel.util.MethodUtil; @@ -28,17 +29,15 @@ import com.alibaba.csp.sentinel.util.MethodUtil; */ public class MethodResourceWrapper extends ResourceWrapper { - private transient Method method; + private final transient Method method; - public MethodResourceWrapper(Method method, EntryType type) { - this.method = method; - this.name = MethodUtil.resolveMethodName(method); - this.type = type; + public MethodResourceWrapper(Method method, EntryType e) { + this(method, e, ResourceTypeConstants.COMMON); } - @Override - public String getName() { - return name; + public MethodResourceWrapper(Method method, EntryType e, int resType) { + super(MethodUtil.resolveMethodName(method), e, resType); + this.method = method; } public Method getMethod() { @@ -51,8 +50,11 @@ public class MethodResourceWrapper extends ResourceWrapper { } @Override - public EntryType getType() { - return type; + public String toString() { + return "MethodResourceWrapper{" + + "name='" + name + '\'' + + ", entryType=" + entryType + + ", resourceType=" + resourceType + + '}'; } - } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/ResourceWrapper.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/ResourceWrapper.java index a796344c..a3eb0196 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/ResourceWrapper.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/ResourceWrapper.java @@ -16,28 +16,64 @@ package com.alibaba.csp.sentinel.slotchain; import com.alibaba.csp.sentinel.EntryType; +import com.alibaba.csp.sentinel.util.AssertUtil; /** - * A wrapper of resource name and {@link EntryType}. + * A wrapper of resource name and type. * * @author qinan.qn * @author jialiang.linjl + * @author Eric Zhao */ public abstract class ResourceWrapper { - protected String name; - protected EntryType type = EntryType.OUT; + protected final String name; - public abstract String getName(); + protected final EntryType entryType; + protected final int resourceType; - public abstract String getShowName(); + public ResourceWrapper(String name, EntryType entryType, int resourceType) { + AssertUtil.notEmpty(name, "resource name cannot be empty"); + AssertUtil.notNull(entryType, "entryType cannot be null"); + this.name = name; + this.entryType = entryType; + this.resourceType = resourceType; + } + + /** + * Get the resource name. + * + * @return the resource name + */ + public String getName() { + return name; + } /** * Get {@link EntryType} of this wrapper. * * @return {@link EntryType} of this wrapper. */ - public abstract EntryType getType(); + public EntryType getEntryType() { + return entryType; + } + + /** + * Get the classification of this resource. + * + * @return the classification of this resource + * @since 1.7.0 + */ + public int getResourceType() { + return resourceType; + } + + /** + * Get the beautified resource name to be showed. + * + * @return the beautified resource name + */ + public abstract String getShowName(); /** * Only {@link #getName()} is considered. diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/StringResourceWrapper.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/StringResourceWrapper.java index d45f0882..dd4ff691 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/StringResourceWrapper.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slotchain/StringResourceWrapper.java @@ -16,26 +16,22 @@ package com.alibaba.csp.sentinel.slotchain; import com.alibaba.csp.sentinel.EntryType; +import com.alibaba.csp.sentinel.ResourceTypeConstants; /** - * Common resource wrapper. + * Common string resource wrapper. * * @author qinan.qn * @author jialiang.linjl */ public class StringResourceWrapper extends ResourceWrapper { - public StringResourceWrapper(String name, EntryType type) { - if (name == null) { - throw new IllegalArgumentException("Resource name cannot be null"); - } - this.name = name; - this.type = type; + public StringResourceWrapper(String name, EntryType e) { + super(name, e, ResourceTypeConstants.COMMON); } - @Override - public String getName() { - return name; + public StringResourceWrapper(String name, EntryType e, int resType) { + super(name, e, resType); } @Override @@ -43,16 +39,12 @@ public class StringResourceWrapper extends ResourceWrapper { return name; } - @Override - public EntryType getType() { - return type; - } - @Override public String toString() { return "StringResourceWrapper{" + "name='" + name + '\'' + - ", type=" + type + + ", entryType=" + entryType + + ", resourceType=" + resourceType + '}'; } } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/clusterbuilder/ClusterBuilderSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/clusterbuilder/ClusterBuilderSlot.java index 1757e9dc..b4ee5918 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/clusterbuilder/ClusterBuilderSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/clusterbuilder/ClusterBuilderSlot.java @@ -78,7 +78,7 @@ public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot synchronized (lock) { if (clusterNode == null) { // Create the cluster node. - clusterNode = new ClusterNode(); + clusterNode = new ClusterNode(resourceWrapper.getName(), resourceWrapper.getResourceType()); HashMap newMap = new HashMap<>(Math.max(clusterNodeMap.size(), 16)); newMap.putAll(clusterNodeMap); newMap.put(node.getId(), clusterNode); diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java index d35a8bdd..30b6a6a8 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java @@ -65,7 +65,7 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot { context.getCurEntry().getOriginNode().addPassRequest(count); } - if (resourceWrapper.getType() == EntryType.IN) { + if (resourceWrapper.getEntryType() == EntryType.IN) { // Add count for global inbound entry node for global statistics. Constants.ENTRY_NODE.increaseThreadNum(); Constants.ENTRY_NODE.addPassRequest(count); @@ -82,7 +82,7 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot { context.getCurEntry().getOriginNode().increaseThreadNum(); } - if (resourceWrapper.getType() == EntryType.IN) { + if (resourceWrapper.getEntryType() == EntryType.IN) { // Add count for global inbound entry node for global statistics. Constants.ENTRY_NODE.increaseThreadNum(); } @@ -100,7 +100,7 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot { context.getCurEntry().getOriginNode().increaseBlockQps(count); } - if (resourceWrapper.getType() == EntryType.IN) { + if (resourceWrapper.getEntryType() == EntryType.IN) { // Add count for global inbound entry node for global statistics. Constants.ENTRY_NODE.increaseBlockQps(count); } @@ -121,7 +121,7 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot { context.getCurEntry().getOriginNode().increaseExceptionQps(count); } - if (resourceWrapper.getType() == EntryType.IN) { + if (resourceWrapper.getEntryType() == EntryType.IN) { Constants.ENTRY_NODE.increaseExceptionQps(count); } throw e; @@ -151,7 +151,7 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot { context.getCurEntry().getOriginNode().decreaseThreadNum(); } - if (resourceWrapper.getType() == EntryType.IN) { + if (resourceWrapper.getEntryType() == EntryType.IN) { Constants.ENTRY_NODE.addRtAndSuccess(rt, count); Constants.ENTRY_NODE.decreaseThreadNum(); } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java index 84263352..d860344e 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java @@ -297,7 +297,7 @@ public final class SystemRuleManager { } // for inbound traffic only - if (resourceWrapper.getType() != EntryType.IN) { + if (resourceWrapper.getEntryType() != EntryType.IN) { return; } diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/CtSphTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/CtSphTest.java index 8c203f00..1d910ee7 100644 --- a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/CtSphTest.java +++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/CtSphTest.java @@ -41,7 +41,7 @@ public class CtSphTest { Entry entry = null; try { if (async) { - entry = ctSph.asyncEntry(resourceName, resourceWrapper.getType(), 1); + entry = ctSph.asyncEntry(resourceName, resourceWrapper.getEntryType(), 1); } else { entry = ctSph.entry(resourceWrapper, 1); } @@ -80,7 +80,7 @@ public class CtSphTest { if (!async) { entry = ctSph.entry(resourceWrapper, 1); } else { - entry = ctSph.asyncEntry(resourceName, resourceWrapper.getType(), 1); + entry = ctSph.asyncEntry(resourceName, resourceWrapper.getEntryType(), 1); Context asyncContext = ((AsyncEntry)entry).getAsyncContext(); assertTrue(ContextUtil.isDefaultContext(asyncContext)); assertTrue(asyncContext.isAsync()); @@ -127,7 +127,7 @@ public class CtSphTest { AsyncEntry asyncEntry = null; try { entry = ctSph.entry(resourceWrapperA, 1); - asyncEntry = ctSph.asyncEntry(resourceNameB, resourceWrapperB.getType(), 1); + asyncEntry = ctSph.asyncEntry(resourceNameB, resourceWrapperB.getEntryType(), 1); } catch (BlockException ex) { fail("Unexpected blocked: " + ex.getClass().getCanonicalName()); } finally { diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/SphOTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/SphOTest.java index 7f8787a5..4233a702 100755 --- a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/SphOTest.java +++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/SphOTest.java @@ -63,7 +63,7 @@ public class SphOTest { try { assertTrue(StringUtil.equalsIgnoreCase( ContextUtil.getContext().getCurEntry().getResourceWrapper().getName(), "resourceName")); - assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getType(), EntryType.OUT); + assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getEntryType(), EntryType.OUT); } finally { SphO.exit(2); } @@ -78,7 +78,7 @@ public class SphOTest { assertTrue(StringUtil.equalsIgnoreCase( ContextUtil.getContext().getCurEntry().getResourceWrapper().getName(), "com.alibaba.csp.sentinel.SphOTest:testMethodEntryCount()")); - assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getType(), EntryType.OUT); + assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getEntryType(), EntryType.OUT); } finally { SphO.exit(2); } @@ -91,7 +91,7 @@ public class SphOTest { try { assertTrue(StringUtil.equalsIgnoreCase( ContextUtil.getContext().getCurEntry().getResourceWrapper().getName(), "resourceName")); - assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getType(), EntryType.IN); + assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getEntryType(), EntryType.IN); } finally { SphO.exit(); } @@ -106,7 +106,7 @@ public class SphOTest { assertTrue(StringUtil.equalsIgnoreCase( ContextUtil.getContext().getCurEntry().getResourceWrapper().getName(), "com.alibaba.csp.sentinel.SphOTest:testMethodEntryType()")); - assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getType(), EntryType.IN); + assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getEntryType(), EntryType.IN); } finally { SphO.exit(); } @@ -119,7 +119,7 @@ public class SphOTest { try { assertTrue(StringUtil.equalsIgnoreCase( ContextUtil.getContext().getCurEntry().getResourceWrapper().getName(), "resourceName")); - assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getType(), EntryType.IN); + assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getEntryType(), EntryType.IN); } finally { SphO.exit(2); } @@ -134,7 +134,7 @@ public class SphOTest { assertTrue(StringUtil.equalsIgnoreCase( ContextUtil.getContext().getCurEntry().getResourceWrapper().getName(), "com.alibaba.csp.sentinel.SphOTest:testMethodEntryTypeCount()")); - assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getType(), EntryType.IN); + assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getEntryType(), EntryType.IN); } finally { SphO.exit(2); } @@ -147,7 +147,7 @@ public class SphOTest { try { assertTrue(StringUtil.equalsIgnoreCase( ContextUtil.getContext().getCurEntry().getResourceWrapper().getName(), "resourceName")); - assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getType(), EntryType.IN); + assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getEntryType(), EntryType.IN); } finally { SphO.exit(2, "hello1", "hello2"); } @@ -162,7 +162,7 @@ public class SphOTest { assertTrue(StringUtil.equalsIgnoreCase( ContextUtil.getContext().getCurEntry().getResourceWrapper().getName(), "com.alibaba.csp.sentinel.SphOTest:testMethodEntryAll()")); - assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getType(), EntryType.IN); + assertSame(ContextUtil.getContext().getCurEntry().getResourceWrapper().getEntryType(), EntryType.IN); } finally { SphO.exit(2, "hello1", "hello2"); } diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/SphUTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/SphUTest.java index a1a58a1a..e546f87c 100755 --- a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/SphUTest.java +++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/SphUTest.java @@ -38,7 +38,7 @@ public class SphUTest { assertNotNull(e); assertEquals(e.resourceWrapper.getName(), "resourceName"); - assertEquals(e.resourceWrapper.getType(), EntryType.OUT); + assertEquals(e.resourceWrapper.getEntryType(), EntryType.OUT); assertEquals(ContextUtil.getContext().getName(), Constants.CONTEXT_DEFAULT_NAME); e.exit(); @@ -53,7 +53,7 @@ public class SphUTest { assertTrue(StringUtil .equalsIgnoreCase(e.resourceWrapper.getName(), "com.alibaba.csp.sentinel.SphUTest:testMethodEntryNormal()")); - assertEquals(e.resourceWrapper.getType(), EntryType.OUT); + assertEquals(e.resourceWrapper.getEntryType(), EntryType.OUT); assertEquals(ContextUtil.getContext().getName(), Constants.CONTEXT_DEFAULT_NAME); e.exit(); @@ -78,7 +78,7 @@ public class SphUTest { assertNotNull(e); assertEquals("resourceName", e.resourceWrapper.getName()); - assertEquals(e.resourceWrapper.getType(), EntryType.OUT); + assertEquals(e.resourceWrapper.getEntryType(), EntryType.OUT); assertEquals(ContextUtil.getContext().getName(), Constants.CONTEXT_DEFAULT_NAME); e.exit(2); @@ -93,7 +93,7 @@ public class SphUTest { assertTrue(StringUtil .equalsIgnoreCase(e.resourceWrapper.getName(), "com.alibaba.csp.sentinel.SphUTest:testMethodEntryNormal()")); - assertEquals(e.resourceWrapper.getType(), EntryType.OUT); + assertEquals(e.resourceWrapper.getEntryType(), EntryType.OUT); e.exit(2); } @@ -102,7 +102,7 @@ public class SphUTest { public void testStringEntryType() throws BlockException { Entry e = SphU.entry("resourceName", EntryType.IN); - assertSame(e.resourceWrapper.getType(), EntryType.IN); + assertSame(e.resourceWrapper.getEntryType(), EntryType.IN); e.exit(); } @@ -112,7 +112,7 @@ public class SphUTest { Method method = SphUTest.class.getMethod("testMethodEntryNormal"); Entry e = SphU.entry(method, EntryType.IN); - assertSame(e.resourceWrapper.getType(), EntryType.IN); + assertSame(e.resourceWrapper.getEntryType(), EntryType.IN); e.exit(); } @@ -121,7 +121,7 @@ public class SphUTest { public void testStringEntryCountType() throws BlockException { Entry e = SphU.entry("resourceName", EntryType.IN, 2); - assertSame(e.resourceWrapper.getType(), EntryType.IN); + assertSame(e.resourceWrapper.getEntryType(), EntryType.IN); e.exit(2); } @@ -131,7 +131,7 @@ public class SphUTest { Method method = SphUTest.class.getMethod("testMethodEntryNormal"); Entry e = SphU.entry(method, EntryType.IN, 2); - assertSame(e.resourceWrapper.getType(), EntryType.IN); + assertSame(e.resourceWrapper.getEntryType(), EntryType.IN); e.exit(); } @@ -141,7 +141,7 @@ public class SphUTest { final String arg0 = "foo"; final String arg1 = "baz"; Entry e = SphU.entry("resourceName", EntryType.IN, 2, arg0, arg1); - assertSame(e.resourceWrapper.getType(), EntryType.IN); + assertSame(e.resourceWrapper.getEntryType(), EntryType.IN); e.exit(2, arg0, arg1); } @@ -153,7 +153,7 @@ public class SphUTest { Method method = SphUTest.class.getMethod("testMethodEntryNormal"); Entry e = SphU.entry(method, EntryType.IN, 2, arg0, arg1); - assertSame(e.resourceWrapper.getType(), EntryType.IN); + assertSame(e.resourceWrapper.getEntryType(), EntryType.IN); e.exit(2, arg0, arg1); } diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/ClusterNodeTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/ClusterNodeTest.java index e900cea9..9c571057 100644 --- a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/ClusterNodeTest.java +++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/ClusterNodeTest.java @@ -41,7 +41,7 @@ public class ClusterNodeTest { @Test public void testGetOrCreateOriginNodeSingleThread() { - ClusterNode clusterNode = new ClusterNode(); + ClusterNode clusterNode = new ClusterNode("test"); String origin1 = "origin1"; Node originNode1 = clusterNode.getOrCreateOriginNode(origin1); @@ -74,7 +74,7 @@ public class ClusterNodeTest { final int testTimes = 10; for (int times = 0; times < testTimes; times++) { - final ClusterNode clusterNode = new ClusterNode(); + final ClusterNode clusterNode = new ClusterNode("test"); // Store all distinct nodes by calling ClusterNode#getOrCreateOriginNode. // Here we need a thread-safe concurrent set (created from ConcurrentHashMap). @@ -130,7 +130,7 @@ public class ClusterNodeTest { @Test public void testTraceException() { - ClusterNode clusterNode = new ClusterNode(); + ClusterNode clusterNode = new ClusterNode("test"); Exception exception = new RuntimeException("test"); diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/metric/MetricNodeTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/metric/MetricNodeTest.java new file mode 100644 index 00000000..9331f0b6 --- /dev/null +++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/metric/MetricNodeTest.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.node.metric; + +import com.alibaba.csp.sentinel.ResourceTypeConstants; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Eric Zhao + */ +public class MetricNodeTest { + + @Test + public void testFromFatString() { + String line = "1564382218000|2019-07-29 14:36:58|/foo/*|1|0|1|0|0|0|2|1"; + MetricNode node = MetricNode.fromFatString(line); + assertEquals(ResourceTypeConstants.COMMON_WEB, node.getClassification()); + assertEquals(2, node.getConcurrency()); + assertEquals(1, node.getSuccessQps()); + } +}