> getFlowRules() {
+ return flowRules;
}
public static boolean hasConfig(String resource) {
@@ -232,6 +220,8 @@ public class FlowRuleManager {
return rule.getWarmUpPeriodSec() > 0;
case RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER:
return rule.getMaxQueueingTimeMs() > 0;
+ case RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
+ return rule.getWarmUpPeriodSec() > 0 && rule.getMaxQueueingTimeMs() > 0;
default:
return true;
}
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java
index d01856df..ca34f274 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java
@@ -15,45 +15,64 @@
*/
package com.alibaba.csp.sentinel.slots.block.flow;
+import java.util.List;
+import java.util.Map;
+
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
/**
*
* Combined the runtime statistics collected from the previous
- * slots(NodeSelectorSlot, ClusterNodeBuilderSlot, and StatistcSlot), FlowSlot
+ * slots (NodeSelectorSlot, ClusterNodeBuilderSlot, and StatisticSlot), FlowSlot
* will use pre-set rules to decide whether the incoming requests should be
* blocked.
+ *
*
- * {@code SphU.entry (resourceName) }will throw FlowException if any rule is
- * triggered. user can customize his own logic by catching FlowException.
+ *
+ * {@code SphU.entry(resourceName)} will throw {@code FlowException} if any rule is
+ * triggered. Users can customize their own logic by catching {@code FlowException}.
+ *
*
+ *
* One resource can have multiple flow rules. FlowSlot traverses these rules
* until one of them is triggered or all rules have been traversed.
+ *
*
- * Each FlowRule is mainly composed of the 2 factors: grade, strategy, path; we
+ *
+ * Each {@link FlowRule} is mainly composed of these factors: grade, strategy, path. We
* can combine these factors to achieve different effects.
+ *
*
- * The grade is defined by the grade field in FlowRule. Here, 0 for thread
- * isolation and 1 for request count shaping. Both thread count and request
+ *
+ * The grade is defined by the {@code grade} field in {@link FlowRule}. Here, 0 for thread
+ * isolation and 1 for request count shaping (QPS). Both thread count and request
* count are collected in real runtime, and we can view these statistics by
- * following command: {@code
- * curl http:// localhost:8719 / tree?type = root`
- * idx id thread pass blocked success total aRt 1m-pass 1m-block 1m-all exeption
+ * following command:
+ *
+ *
+ *
+ * curl http://localhost:8719/tree
+ *
+ * idx id thread pass blocked success total aRt 1m-pass 1m-block 1m-all exception
* 2 abc647 0 460 46 46 1 27 630 276 897 0
- * }
- *
- * Thread for the count of threads that is currently processing the resource;
- * pass for the count of incoming request within one second; blocked for the
- * count of requests blocked within one second; success for the count of the
- * requests successfully within one second; RT for the average response time of
- * the requests within a second; total for the sum of incoming requests and
- * blocked requests within one second; 1m-pass is for the count of incoming
- * requests within one minute; 1m-block is for the count of a request blocked
- * within one minute; 1m -all is the total of incoming and blocked requests
- * within 1 minute; exception is for the count of exceptions in one second.
+ *
+ *
+ *
+ * - {@code thread} for the count of threads that is currently processing the resource
+ * - {@code pass} for the count of incoming request within one second
+ * - {@code blocked} for the count of requests blocked within one second
+ * - {@code success} for the count of the requests successfully handled by Sentinel within one second
+ * - {@code RT} for the average response time of the requests within a second
+ * - {@code total} for the sum of incoming requests and blocked requests within one second
+ * - {@code 1m-pass} is for the count of incoming requests within one minute
+ * - {@code 1m-block} is for the count of a request blocked within one minute
+ * - {@code 1m-all} is the total of incoming and blocked requests within one minute
+ * - {@code exception} is for the count of business (customized) exceptions in one second
+ *
*
* This stage is usually used to protect resources from occupying. If a resource
* takes long time to finish, threads will begin to occupy. The longer the
@@ -71,57 +90,79 @@ import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
* The benefit of using thread pool is that, it can walk away gracefully when
* time out. But it also bring us the cost of context switch and additional
* threads. If the incoming requests is already served in a separated thread,
- * for instance, a servelet request, it will almost double the threads count if
+ * for instance, a Servlet HTTP request, it will almost double the threads count if
* using thread pool.
*
- * ### QPS Shaping ### When qps exceeds the threshold, we will take actions to
- * control the incoming request, and is configured by "controlBehavior" field in
- * flowrule
- *
- * 1. immediately reject(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)
- *
+ * Traffic Shaping
+ *
+ * When QPS exceeds the threshold, Sentinel will take actions to control the incoming request,
+ * and is configured by {@code controlBehavior} field in flow rules.
+ *
+ *
+ * - Immediately reject ({@code RuleConstant.CONTROL_BEHAVIOR_DEFAULT})
+ *
* This is the default behavior. The exceeded request is rejected immediately
* and the FlowException is thrown
+ *
*
- * 2. Warmup(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)
- *
- * If the usage of system has been low for a while, and a large amount of
+ * - Warmup ({@code RuleConstant.CONTROL_BEHAVIOR_WARM_UP})
+ *
+ * If the load of system has been low for a while, and a large amount of
* requests comes, the system might not be able to handle all these requests at
* once. However if we steady increase the incoming request, the system can warm
- * up and finally be able to handle all the requests.If the usage of system has
- * been low for a while, and a large amount of requests comes, the system might
- * not be able to handle all these requests at once. However if we steady
- * increase the incoming request, the system can warm up and finally be able to
- * handle all the requests. This warmup period can be configured by setting the
- * field "warmUpPeriodSec" in flow rule.
- *
- * 3.Rate limiter(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER) This strategy
- * strictly controls the interval between requests. In other words, it allows
- * requests to pass at a stable rate.
- * This strategy is an implement of leaky bucket
- * (https://en.wikipedia.org/wiki/Leaky_bucket). It is used to handle the
- * request at a stable rate and is often used in burst traffic. For instance,
- * Message. When a large number of requests beyond the system’s capacity arrive
+ * up and finally be able to handle all the requests.
+ * This warmup period can be configured by setting the field {@code warmUpPeriodSec} in flow rules.
+ *
+ *
+ * - Uniform Rate Limiting ({@code RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER})
+ *
+ * This strategy strictly controls the interval between requests.
+ * In other words, it allows requests to pass at a stable, uniform rate.
+ *
+ *
+ *
+ * This strategy is an implement of leaky bucket.
+ * It is used to handle the request at a stable rate and is often used in burst traffic (e.g. message handling).
+ * When a large number of requests beyond the system’s capacity arrive
* at the same time, the system using this strategy will handle requests and its
* fixed rate until all the requests have been processed or time out.
+ *
+ *
*
* @author jialiang.linjl
+ * @author Eric Zhao
*/
public class FlowSlot extends AbstractLinkedProcessorSlot {
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args)
throws Throwable {
-
- FlowRuleManager.checkFlow(resourceWrapper, context, node, count);
+ checkFlow(resourceWrapper, context, node, count);
fireEntry(context, resourceWrapper, node, count, args);
}
+ void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count) throws BlockException {
+ // Flow rule map cannot be null.
+ Map> flowRules = FlowRuleManager.getFlowRules();
+
+ List rules = flowRules.get(resource.getName());
+ if (rules != null) {
+ for (FlowRule rule : rules) {
+ if (!canPassCheck(rule, context, node, count)) {
+ throw new FlowException(rule.getLimitApp());
+ }
+ }
+ }
+ }
+
+ boolean canPassCheck(FlowRule rule, Context context, DefaultNode node, int count) {
+ return FlowRuleChecker.passCheck(rule, context, node, count);
+ }
+
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
fireExit(context, resourceWrapper, count, args);
}
-
}
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/Controller.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/TrafficShapingController.java
similarity index 69%
rename from sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/Controller.java
rename to sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/TrafficShapingController.java
index ab58e751..bcba4a18 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/Controller.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/TrafficShapingController.java
@@ -18,10 +18,18 @@ package com.alibaba.csp.sentinel.slots.block.flow;
import com.alibaba.csp.sentinel.node.Node;
/**
+ * A universal interface for traffic shaping controller.
+ *
* @author jialiang.linjl
*/
-public interface Controller {
+public interface TrafficShapingController {
+ /**
+ * Check whether given resource entry can pass with provided count.
+ *
+ * @param node resource node
+ * @param acquireCount count to acquire
+ * @return true if the resource entry can pass; false if it should be blocked
+ */
boolean canPass(Node node, int acquireCount);
-
}
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/DefaultController.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/DefaultController.java
index d02d85a8..4dc8368f 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/DefaultController.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/DefaultController.java
@@ -17,18 +17,19 @@ package com.alibaba.csp.sentinel.slots.block.flow.controller;
import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
-import com.alibaba.csp.sentinel.slots.block.flow.Controller;
+import com.alibaba.csp.sentinel.slots.block.flow.TrafficShapingController;
/**
+ * Default throttling controller (immediately reject strategy).
+ *
* @author jialiang.linjl
*/
-public class DefaultController implements Controller {
+public class DefaultController implements TrafficShapingController {
- double count = 0;
- int grade = 0;
+ private double count;
+ private int grade;
public DefaultController(double count, int grade) {
- super();
this.count = count;
this.grade = grade;
}
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/RateLimiterController.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/RateLimiterController.java
index b7dc7cd9..4f0a868c 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/RateLimiterController.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/RateLimiterController.java
@@ -17,7 +17,7 @@ package com.alibaba.csp.sentinel.slots.block.flow.controller;
import java.util.concurrent.atomic.AtomicLong;
-import com.alibaba.csp.sentinel.slots.block.flow.Controller;
+import com.alibaba.csp.sentinel.slots.block.flow.TrafficShapingController;
import com.alibaba.csp.sentinel.util.TimeUtil;
import com.alibaba.csp.sentinel.node.Node;
@@ -25,7 +25,7 @@ import com.alibaba.csp.sentinel.node.Node;
/**
* @author jialiang.linjl
*/
-public class RateLimiterController implements Controller {
+public class RateLimiterController implements TrafficShapingController {
private final int maxQueueingTimeMs;
private final double count;
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/WarmUpController.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/WarmUpController.java
index 3cba3a76..08c71166 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/WarmUpController.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/controller/WarmUpController.java
@@ -19,17 +19,17 @@ import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.csp.sentinel.util.TimeUtil;
import com.alibaba.csp.sentinel.node.Node;
-import com.alibaba.csp.sentinel.slots.block.flow.Controller;
+import com.alibaba.csp.sentinel.slots.block.flow.TrafficShapingController;
/**
- * The principle idea comes from guava. However, the calculation of guava is
- * rate-based, which means that we need to translate rate to qps.
- *
- * https://github.com/google/guava/blob/master/guava/src/com/google/common/util/concurrent/SmoothRateLimiter.java
+ *
+ * The principle idea comes from Guava. However, the calculation of Guava is
+ * rate-based, which means that we need to translate rate to QPS.
+ *
*
* Requests arriving at the pulse may drag down long idle systems even though it
* has a much larger handling capability in stable period. It usually happens in
- * scenarios that require extra time for initialization, for example, db
+ * scenarios that require extra time for initialization, e.g. DB
* establishes a connection; connects to a remote service, and so on.
*
* That’s why we need “warm up”.
@@ -61,7 +61,7 @@ import com.alibaba.csp.sentinel.slots.block.flow.Controller;
*
* @author jialiang.linjl
*/
-public class WarmUpController implements Controller {
+public class WarmUpController implements TrafficShapingController {
protected double count;
private int coldFactor;