Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract flow rule checker from FlowRule #234

Merged
merged 2 commits into from
Nov 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,15 @@
*/
package com.alibaba.csp.sentinel.slots.block.flow;

import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;

/***
/**
* <p>
* Each flow rule is mainly composed of three factors: <strong>grade</strong>,
* <strong>strategy</strong> and <strong>controlBehavior</strong>.
* Each flow rule is mainly composed of three factors: <strong>grade</strong>,
* <strong>strategy</strong> and <strong>controlBehavior</strong>:
* </p>
* <ul>
* <li>The {@link #grade} represents the threshold type of flow control (by QPS or thread count).</li>
Expand All @@ -45,6 +42,12 @@ public FlowRule() {
setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);
}

public FlowRule(String resourceName) {
super();
setResource(resourceName);
setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);
}

/**
* The threshold type of flow control (0: thread count, 1: QPS).
*/
Expand All @@ -65,7 +68,7 @@ public FlowRule() {
private int strategy = RuleConstant.STRATEGY_DIRECT;

/**
* Reference resource in flow control with relevant resource.
* Reference resource in flow control with relevant resource or context.
*/
private String refResource;

Expand All @@ -82,7 +85,10 @@ public FlowRule() {
*/
private int maxQueueingTimeMs = 500;

private Controller controller;
/**
* The traffic shaping (throttling) controller.
*/
private TrafficShapingController controller;

public int getControlBehavior() {
return controlBehavior;
Expand All @@ -102,11 +108,15 @@ public FlowRule setMaxQueueingTimeMs(int maxQueueingTimeMs) {
return this;
}

public FlowRule setRater(Controller rater) {
FlowRule setRater(TrafficShapingController rater) {
this.controller = rater;
return this;
}

TrafficShapingController getRater() {
return controller;
}

public int getWarmUpPeriodSec() {
return warmUpPeriodSec;
}
Expand Down Expand Up @@ -154,90 +164,7 @@ public FlowRule setRefResource(String refResource) {

@Override
public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
String limitApp = this.getLimitApp();
if (limitApp == null) {
return true;
}

String origin = context.getOrigin();
Node selectedNode = selectNodeByRequesterAndStrategy(origin, context, node);
if (selectedNode == null) {
return true;
}

return controller.canPass(selectedNode, acquireCount);
}

private Node selectNodeByRequesterAndStrategy(String origin, Context context, DefaultNode node) {
// The limit app should not be empty.
String limitApp = this.getLimitApp();

if (limitApp.equals(origin)) {
if (strategy == RuleConstant.STRATEGY_DIRECT) {
return context.getOriginNode();
}

String refResource = this.getRefResource();
if (StringUtil.isEmpty(refResource)) {
return null;
}

if (strategy == RuleConstant.STRATEGY_RELATE) {
return ClusterBuilderSlot.getClusterNode(refResource);
}

if (strategy == RuleConstant.STRATEGY_CHAIN) {
if (!refResource.equals(context.getName())) {
return null;
}
return node;
}

} else if (RuleConstant.LIMIT_APP_DEFAULT.equals(limitApp)) {
if (strategy == RuleConstant.STRATEGY_DIRECT) {
return node.getClusterNode();
}
String refResource = this.getRefResource();
if (StringUtil.isEmpty(refResource)) {
return null;
}

if (strategy == RuleConstant.STRATEGY_RELATE) {
return ClusterBuilderSlot.getClusterNode(refResource);
}

if (strategy == RuleConstant.STRATEGY_CHAIN) {
if (!refResource.equals(context.getName())) {
return null;
}
return node;
}

} else if (RuleConstant.LIMIT_APP_OTHER.equals(limitApp)
&& FlowRuleManager.isOtherOrigin(origin, getResource())) {
if (strategy == RuleConstant.STRATEGY_DIRECT) {
return context.getOriginNode();
}

String refResource = this.getRefResource();
if (StringUtil.isEmpty(refResource)) {
return null;
}
if (strategy == RuleConstant.STRATEGY_RELATE) {
return ClusterBuilderSlot.getClusterNode(refResource);
}

if (strategy == RuleConstant.STRATEGY_CHAIN) {
if (!refResource.equals(context.getName())) {
return null;
}
if (node != null) {
return node;
}
}
}

return null;
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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.slots.block.flow;

import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import com.alibaba.csp.sentinel.util.StringUtil;

/**
* Rule checker for flow control rules.
*
* @author Eric Zhao
*/
final class FlowRuleChecker {

static boolean passCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node, int acquireCount) {
String limitApp = rule.getLimitApp();
if (limitApp == null) {
return true;
}

Node selectedNode = selectNodeByRequesterAndStrategy(rule, context, node);
if (selectedNode == null) {
return true;
}

return rule.getRater().canPass(selectedNode, acquireCount);
}

static Node selectReferenceNode(FlowRule rule, Context context, DefaultNode node) {
String refResource = rule.getRefResource();
int strategy = rule.getStrategy();

if (StringUtil.isEmpty(refResource)) {
return null;
}

if (strategy == RuleConstant.STRATEGY_RELATE) {
return ClusterBuilderSlot.getClusterNode(refResource);
}

if (strategy == RuleConstant.STRATEGY_CHAIN) {
if (!refResource.equals(context.getName())) {
return null;
}
return node;
}
// No node.
return null;
}

private static boolean filterOrigin(String origin) {
// Origin cannot be `default` or `other`.
return !RuleConstant.LIMIT_APP_DEFAULT.equals(origin) && !RuleConstant.LIMIT_APP_OTHER.equals(origin);
}

static Node selectNodeByRequesterAndStrategy(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node) {
// The limit app should not be empty.
String limitApp = rule.getLimitApp();
int strategy = rule.getStrategy();
String origin = context.getOrigin();

if (limitApp.equals(origin) && filterOrigin(origin)) {
if (strategy == RuleConstant.STRATEGY_DIRECT) {
// Matches limit origin, return origin statistic node.
return context.getOriginNode();
}

return selectReferenceNode(rule, context, node);
} else if (RuleConstant.LIMIT_APP_DEFAULT.equals(limitApp)) {
if (strategy == RuleConstant.STRATEGY_DIRECT) {
// Return the cluster node.
return node.getClusterNode();
}

return selectReferenceNode(rule, context, node);
} else if (RuleConstant.LIMIT_APP_OTHER.equals(limitApp)
&& FlowRuleManager.isOtherOrigin(origin, rule.getResource())) {
if (strategy == RuleConstant.STRATEGY_DIRECT) {
return context.getOriginNode();
}

return selectReferenceNode(rule, context, node);
}

return null;
}

private FlowRuleChecker() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,10 @@
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.node.metric.MetricTimerListener;
import com.alibaba.csp.sentinel.property.DynamicSentinelProperty;
import com.alibaba.csp.sentinel.property.PropertyListener;
import com.alibaba.csp.sentinel.property.SentinelProperty;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController;
import com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController;
Expand Down Expand Up @@ -118,7 +114,7 @@ private static Map<String, List<FlowRule>> loadFlowConf(List<FlowRule> list) {
rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);
}

Controller rater = new DefaultController(rule.getCount(), rule.getGrade());
TrafficShapingController rater = new DefaultController(rule.getCount(), rule.getGrade());
if (rule.getGrade() == RuleConstant.FLOW_GRADE_QPS
&& rule.getControlBehavior() == RuleConstant.CONTROL_BEHAVIOR_WARM_UP
&& rule.getWarmUpPeriodSec() > 0) {
Expand Down Expand Up @@ -151,16 +147,8 @@ private static Map<String, List<FlowRule>> loadFlowConf(List<FlowRule> list) {
return newRuleMap;
}

public static void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count)
throws BlockException {
List<FlowRule> rules = flowRules.get(resource.getName());
if (rules != null) {
for (FlowRule rule : rules) {
if (!rule.passCheck(context, node, count)) {
throw new FlowException(rule.getLimitApp());
}
}
}
static Map<String, List<FlowRule>> getFlowRules() {
return flowRules;
}

public static boolean hasConfig(String resource) {
Expand Down Expand Up @@ -232,6 +220,8 @@ private static boolean checkControlBehaviorField(/*@NonNull*/ FlowRule rule) {
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;
}
Expand Down
Loading