Skip to content

Commit

Permalink
Automatically de-duplicate rules when loading rules (#571)
Browse files Browse the repository at this point in the history
* De-duplicate rules automatically when loading rules
* Update rule managers

Signed-off-by: Eric Zhao <[email protected]>
  • Loading branch information
sczyh30 authored Mar 14, 2019
1 parent ae774db commit 1741da0
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 83 deletions.
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

0 comments on commit 1741da0

Please sign in to comment.