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

Automatically de-duplicate rules when loading rules #571

Merged
merged 2 commits into from
Mar 14, 2019
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 @@ -16,12 +16,15 @@
package com.alibaba.csp.sentinel.slots.block.authority;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.property.DynamicSentinelProperty;
import com.alibaba.csp.sentinel.property.PropertyListener;
Expand All @@ -36,24 +39,22 @@
*/
public final class AuthorityRuleManager {

private static Map<String, List<AuthorityRule>> authorityRules
= new ConcurrentHashMap<String, List<AuthorityRule>>();
private static Map<String, Set<AuthorityRule>> authorityRules = new ConcurrentHashMap<>();

final static RulePropertyListener listener = new RulePropertyListener();

private static SentinelProperty<List<AuthorityRule>> currentProperty
= new DynamicSentinelProperty<List<AuthorityRule>>();
private static final RulePropertyListener LISTENER = new RulePropertyListener();
private static SentinelProperty<List<AuthorityRule>> currentProperty = new DynamicSentinelProperty<>();

static {
currentProperty.addListener(listener);
currentProperty.addListener(LISTENER);
}

public static void register2Property(SentinelProperty<List<AuthorityRule>> property) {
synchronized (listener) {
AssertUtil.notNull(property, "property cannot be null");
synchronized (LISTENER) {
if (currentProperty != null) {
currentProperty.removeListener(listener);
currentProperty.removeListener(LISTENER);
}
property.addListener(listener);
property.addListener(LISTENER);
currentProperty = property;
RecordLog.info("[AuthorityRuleManager] Registering new property to authority rule manager");
}
Expand All @@ -78,11 +79,11 @@ public static boolean hasConfig(String resource) {
* @return a new copy of the rules.
*/
public static List<AuthorityRule> getRules() {
List<AuthorityRule> rules = new ArrayList<AuthorityRule>();
List<AuthorityRule> rules = new ArrayList<>();
if (authorityRules == null) {
return rules;
}
for (Map.Entry<String, List<AuthorityRule>> entry : authorityRules.entrySet()) {
for (Map.Entry<String, Set<AuthorityRule>> entry : authorityRules.entrySet()) {
rules.addAll(entry.getValue());
}
return rules;
Expand All @@ -92,7 +93,7 @@ private static class RulePropertyListener implements PropertyListener<List<Autho

@Override
public void configUpdate(List<AuthorityRule> conf) {
Map<String, List<AuthorityRule>> rules = loadAuthorityConf(conf);
Map<String, Set<AuthorityRule>> rules = loadAuthorityConf(conf);

authorityRules.clear();
if (rules != null) {
Expand All @@ -101,8 +102,8 @@ public void configUpdate(List<AuthorityRule> conf) {
RecordLog.info("[AuthorityRuleManager] Authority rules received: " + authorityRules);
}

private Map<String, List<AuthorityRule>> loadAuthorityConf(List<AuthorityRule> list) {
Map<String, List<AuthorityRule>> newRuleMap = new ConcurrentHashMap<String, List<AuthorityRule>>();
private Map<String, Set<AuthorityRule>> loadAuthorityConf(List<AuthorityRule> list) {
Map<String, Set<AuthorityRule>> newRuleMap = new ConcurrentHashMap<>();

if (list == null || list.isEmpty()) {
return newRuleMap;
Expand All @@ -119,12 +120,12 @@ private Map<String, List<AuthorityRule>> loadAuthorityConf(List<AuthorityRule> l
}

String identity = rule.getResource();
List<AuthorityRule> ruleM = newRuleMap.get(identity);
Set<AuthorityRule> ruleSet = newRuleMap.get(identity);
// putIfAbsent
if (ruleM == null) {
ruleM = new ArrayList<AuthorityRule>();
ruleM.add(rule);
newRuleMap.put(identity, ruleM);
if (ruleSet == null) {
ruleSet = new HashSet<>();
ruleSet.add(rule);
newRuleMap.put(identity, ruleSet);
} else {
// One resource should only have at most one authority rule, so just ignore redundant rules.
RecordLog.warn("[AuthorityRuleManager] Ignoring redundant rule: " + rule.toString());
Expand All @@ -136,7 +137,7 @@ private Map<String, List<AuthorityRule>> loadAuthorityConf(List<AuthorityRule> l

@Override
public void configLoad(List<AuthorityRule> value) {
Map<String, List<AuthorityRule>> rules = loadAuthorityConf(value);
Map<String, Set<AuthorityRule>> rules = loadAuthorityConf(value);

authorityRules.clear();
if (rules != null) {
Expand All @@ -146,11 +147,11 @@ public void configLoad(List<AuthorityRule> value) {
}
}

static Map<String, List<AuthorityRule>> getAuthorityRules() {
static Map<String, Set<AuthorityRule>> getAuthorityRules() {
return authorityRules;
}

static boolean isValidRule(AuthorityRule rule) {
public static boolean isValidRule(AuthorityRule rule) {
return rule != null && !StringUtil.isBlank(rule.getResource())
&& rule.getStrategy() >= 0 && StringUtil.isNotBlank(rule.getLimitApp());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/
package com.alibaba.csp.sentinel.slots.block.authority;

import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.node.DefaultNode;
Expand Down Expand Up @@ -45,13 +45,13 @@ public void exit(Context context, ResourceWrapper resourceWrapper, int count, Ob
}

void checkBlackWhiteAuthority(ResourceWrapper resource, Context context) throws AuthorityException {
Map<String, List<AuthorityRule>> authorityRules = AuthorityRuleManager.getAuthorityRules();
Map<String, Set<AuthorityRule>> authorityRules = AuthorityRuleManager.getAuthorityRules();

if (authorityRules == null) {
return;
}

List<AuthorityRule> rules = authorityRules.get(resource.getName());
Set<AuthorityRule> rules = authorityRules.get(resource.getName());
if (rules == null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
package com.alibaba.csp.sentinel.slots.block.degrade;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.csp.sentinel.Constants;
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.node.DefaultNode;
Expand All @@ -29,23 +33,24 @@
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.util.AssertUtil;
import com.alibaba.csp.sentinel.util.StringUtil;

/***
/**
* @author youji.zj
* @author jialiang.linjl
* @author Eric Zhao
*/
public class DegradeRuleManager {
public final class DegradeRuleManager {

private static volatile Map<String, List<DegradeRule>> degradeRules
= new ConcurrentHashMap<String, List<DegradeRule>>();
private static final Map<String, Set<DegradeRule>> degradeRules = new ConcurrentHashMap<>();

final static RulePropertyListener listener = new RulePropertyListener();
private static final RulePropertyListener LISTENER = new RulePropertyListener();
private static SentinelProperty<List<DegradeRule>> currentProperty
= new DynamicSentinelProperty<List<DegradeRule>>();
= new DynamicSentinelProperty<>();

static {
currentProperty.addListener(listener);
currentProperty.addListener(LISTENER);
}

/**
Expand All @@ -55,21 +60,19 @@ public class DegradeRuleManager {
* @param property the property to listen.
*/
public static void register2Property(SentinelProperty<List<DegradeRule>> property) {
synchronized (listener) {
AssertUtil.notNull(property, "property cannot be null");
synchronized (LISTENER) {
RecordLog.info("[DegradeRuleManager] Registering new property to degrade rule manager");
currentProperty.removeListener(listener);
property.addListener(listener);
currentProperty.removeListener(LISTENER);
property.addListener(LISTENER);
currentProperty = property;
}
}

public static void checkDegrade(ResourceWrapper resource, Context context, DefaultNode node, int count)
throws BlockException {
if (degradeRules == null) {
return;
}

List<DegradeRule> rules = degradeRules.get(resource.getName());
Set<DegradeRule> rules = degradeRules.get(resource.getName());
if (rules == null) {
return;
}
Expand All @@ -82,6 +85,9 @@ public static void checkDegrade(ResourceWrapper resource, Context context, Defau
}

public static boolean hasConfig(String resource) {
if (resource == null) {
return false;
}
return degradeRules.containsKey(resource);
}

Expand All @@ -91,11 +97,8 @@ public static boolean hasConfig(String resource) {
* @return a new copy of the rules.
*/
public static List<DegradeRule> getRules() {
List<DegradeRule> rules = new ArrayList<DegradeRule>();
if (degradeRules == null) {
return rules;
}
for (Map.Entry<String, List<DegradeRule>> entry : degradeRules.entrySet()) {
List<DegradeRule> rules = new ArrayList<>();
for (Map.Entry<String, Set<DegradeRule>> entry : degradeRules.entrySet()) {
rules.addAll(entry.getValue());
}
return rules;
Expand All @@ -110,15 +113,50 @@ public static void loadRules(List<DegradeRule> rules) {
try {
currentProperty.updateValue(rules);
} catch (Throwable e) {
RecordLog.info(e.getMessage(), e);
RecordLog.warn("[DegradeRuleManager] Unexpected error when loading degrade rules", e);
}
}

/**
* Set degrade rules for provided resource. Former rules of the resource will be replaced.
*
* @param resourceName valid resource name
* @param rules new rule set to load
* @return whether the rules has actually been updated
* @since 1.5.0
*/
public static boolean setRulesForResource(String resourceName, Set<DegradeRule> rules) {
AssertUtil.notEmpty(resourceName, "resourceName cannot be empty");
try {
Map<String, Set<DegradeRule>> newRuleMap = new HashMap<>(degradeRules);
if (rules == null) {
newRuleMap.remove(resourceName);
} else {
Set<DegradeRule> newSet = new HashSet<>();
for (DegradeRule rule : rules) {
if (isValidRule(rule) && resourceName.equals(rule.getResource())) {
newSet.add(rule);
}
}
newRuleMap.put(resourceName, newSet);
}
List<DegradeRule> allRules = new ArrayList<>();
for (Set<DegradeRule> set : newRuleMap.values()) {
allRules.addAll(set);
}
return currentProperty.updateValue(allRules);
} catch (Throwable e) {
RecordLog.warn(
"[DegradeRuleManager] Unexpected error when setting degrade rules for resource: " + resourceName, e);
return false;
}
}

private static class RulePropertyListener implements PropertyListener<List<DegradeRule>> {

@Override
public void configUpdate(List<DegradeRule> conf) {
Map<String, List<DegradeRule>> rules = loadDegradeConf(conf);
Map<String, Set<DegradeRule>> rules = loadDegradeConf(conf);
if (rules != null) {
degradeRules.clear();
degradeRules.putAll(rules);
Expand All @@ -128,24 +166,25 @@ public void configUpdate(List<DegradeRule> conf) {

@Override
public void configLoad(List<DegradeRule> conf) {
Map<String, List<DegradeRule>> rules = loadDegradeConf(conf);
Map<String, Set<DegradeRule>> rules = loadDegradeConf(conf);
if (rules != null) {
degradeRules.clear();
degradeRules.putAll(rules);
}
RecordLog.info("[DegradeRuleManager] Degrade rules loaded: " + degradeRules);
}

private Map<String, List<DegradeRule>> loadDegradeConf(List<DegradeRule> list) {
Map<String, List<DegradeRule>> newRuleMap = new ConcurrentHashMap<String, List<DegradeRule>>();
private Map<String, Set<DegradeRule>> loadDegradeConf(List<DegradeRule> list) {
Map<String, Set<DegradeRule>> newRuleMap = new ConcurrentHashMap<>();

if (list == null || list.isEmpty()) {
return newRuleMap;
}

for (DegradeRule rule : list) {
if (!isValidRule(rule)) {
RecordLog.warn("[DegradeRuleManager] Ignoring invalid degrade rule when loading new rules: " + rule);
RecordLog.warn(
"[DegradeRuleManager] Ignoring invalid degrade rule when loading new rules: " + rule);
continue;
}

Expand All @@ -154,17 +193,16 @@ private Map<String, List<DegradeRule>> loadDegradeConf(List<DegradeRule> list) {
}

String identity = rule.getResource();
List<DegradeRule> ruleM = newRuleMap.get(identity);
if (ruleM == null) {
ruleM = new ArrayList<DegradeRule>();
newRuleMap.put(identity, ruleM);
Set<DegradeRule> ruleSet = newRuleMap.get(identity);
if (ruleSet == null) {
ruleSet = new HashSet<>();
newRuleMap.put(identity, ruleSet);
}
ruleM.add(rule);
ruleSet.add(rule);
}

return newRuleMap;
}

}

public static boolean isValidRule(DegradeRule rule) {
Expand All @@ -173,6 +211,13 @@ public static boolean isValidRule(DegradeRule rule) {
if (!baseValid) {
return false;
}
// Warn for RT mode that exceeds the {@code TIME_DROP_VALVE}.
int maxAllowedRt = Constants.TIME_DROP_VALVE;
if (rule.getGrade() == RuleConstant.DEGRADE_GRADE_RT && rule.getCount() > maxAllowedRt) {
RecordLog.warn(String.format("[DegradeRuleManager] WARN: setting large RT threshold (%.1f ms) in RT mode"
+ " will not take effect since it exceeds the max allowed value (%d ms)", rule.getCount(),
maxAllowedRt));
}
// Check exception ratio mode.
if (rule.getGrade() == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO && rule.getCount() > 1) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.node.metric.MetricTimerListener;
import com.alibaba.csp.sentinel.property.DynamicSentinelProperty;
Expand Down Expand Up @@ -65,6 +66,7 @@ public class FlowRuleManager {
* @param property the property to listen.
*/
public static void register2Property(SentinelProperty<List<FlowRule>> property) {
AssertUtil.notNull(property, "property cannot be null");
synchronized (LISTENER) {
RecordLog.info("[FlowRuleManager] Registering new property to flow rule manager");
currentProperty.removeListener(LISTENER);
Expand Down
Loading