序
本文主要研究一下sentinel的ModifyRulesCommandHandler
ModifyRulesCommandHandler
sentinel-transport-common-0.1.1-sources.jar!/com/alibaba/csp/sentinel/command/handler/ModifyRulesCommandHandler.java
@CommandMapping(name = "setRules")
public class ModifyRulesCommandHandler implements CommandHandler<String> {
static DataSource<?, List<FlowRule>> flowDataSource = null;
static DataSource<?, List<AuthorityRule>> authorityDataSource = null;
static DataSource<?, List<DegradeRule>> degradeDataSource = null;
static DataSource<?, List<SystemRule>> systemSource = null;
public static synchronized void registerFlowDataSource(DataSource<?, List<FlowRule>> datasource) {
flowDataSource = datasource;
}
public static synchronized void registerAuthorityDataSource(DataSource<?, List<AuthorityRule>> dataSource) {
authorityDataSource = dataSource;
}
public static synchronized void registerDegradeDataSource(DataSource<?, List<DegradeRule>> dataSource) {
degradeDataSource = dataSource;
}
public static synchronized void registerSystemDataSource(DataSource<?, List<SystemRule>> dataSource) {
systemSource = dataSource;
}
@Override
public CommandResponse<String> handle(CommandRequest request) {
String type = request.getParam("type");
// rule data in get parameter
String data = request.getParam("data");
if (StringUtil.isNotEmpty(data)) {
try {
data = URLDecoder.decode(data, "utf-8");
} catch (Exception e) {
RecordLog.info("decode rule data error", e);
return CommandResponse.ofFailure(e, "decode rule data error");
}
}
RecordLog.info("receive rule change:" + type);
RecordLog.info(data);
String result = "success";
if ("flow".equalsIgnoreCase(type)) {
List<FlowRule> flowRules = JSONArray.parseArray(data, FlowRule.class);
FlowRuleManager.loadRules(flowRules);
if (flowDataSource != null) {
try {
flowDataSource.writeDataSource(flowRules);
} catch (Exception e) {
result = "partial success";
RecordLog.info(e.getMessage(), e);
}
}
return CommandResponse.ofSuccess(result);
} else if ("authority".equalsIgnoreCase(type)) {
List<AuthorityRule> rules = JSONArray.parseArray(data, AuthorityRule.class);
AuthorityRuleManager.loadRules(rules);
if (authorityDataSource != null) {
try {
authorityDataSource.writeDataSource(rules);
} catch (Exception e) {
result = "partial success";
RecordLog.info(e.getMessage(), e);
}
}
return CommandResponse.ofSuccess(result);
} else if ("degrade".equalsIgnoreCase(type)) {
List<DegradeRule> rules = JSONArray.parseArray(data, DegradeRule.class);
DegradeRuleManager.loadRules(rules);
if (degradeDataSource != null) {
try {
degradeDataSource.writeDataSource(rules);
} catch (Exception e) {
result = "partial success";
RecordLog.info(e.getMessage(), e);
}
}
return CommandResponse.ofSuccess(result);
} else if ("system".equalsIgnoreCase(type)) {
List<SystemRule> rules = JSONArray.parseArray(data, SystemRule.class);
SystemRuleManager.loadRules(rules);
if (systemSource != null) {
try {
systemSource.writeDataSource(rules);
} catch (Exception e) {
result = "partial success";
RecordLog.info(e.getMessage(), e);
}
}
return CommandResponse.ofSuccess(result);
}
return CommandResponse.ofFailure(new IllegalArgumentException("invalid type"));
}
}
- 如果type是flow的话,则调用FlowRuleManager.loadRules(flowRules);更新
FlowRuleManager
sentinel-core-0.1.1-sources.jar!/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleManager.java
/**
* Load {@link FlowRule}s, former rules will be replaced.
*
* @param rules new rules to load.
*/
public static void loadRules(List<FlowRule> rules) {
currentProperty.updateValue(rules);
}
- 调用的是DynamicSentinelProperty的updateValue
DynamicSentinelProperty
sentinel-core-0.1.1-sources.jar!/com/alibaba/csp/sentinel/property/DynamicSentinelProperty.java
public void updateValue(T newValue) {
if (isEqual(value, newValue)) {
return;
}
RecordLog.info("SentinelProperty, config is real updated to: " + newValue);
value = newValue;
for (PropertyListener<T> listener : listeners) {
listener.configUpdate(newValue);
}
}
- 这里委托给listeners去进行configUpdate
FlowPropertyListener
sentinel-core-0.1.1-sources.jar!/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleManager.java
private static final class FlowPropertyListener implements PropertyListener<List<FlowRule>> {
@Override
public void configUpdate(List<FlowRule> value) {
Map<String, List<FlowRule>> rules = loadFlowConf(value);
if (rules != null) {
flowRules.clear();
flowRules.putAll(rules);
}
RecordLog.info("receive flow config: " + flowRules);
}
@Override
public void configLoad(List<FlowRule> conf) {
Map<String, List<FlowRule>> rules = loadFlowConf(conf);
if (rules != null) {
flowRules.clear();
flowRules.putAll(rules);
}
RecordLog.info("load flow config: " + flowRules);
}
}
- 这里的configUpdate方法调用loadFlowConf进行加载
FlowRuleManager.loadFlowConf
sentinel-core-0.1.1-sources.jar!/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleManager.java
private static Map<String, List<FlowRule>> loadFlowConf(List<FlowRule> list) {
Map<String, List<FlowRule>> newRuleMap = new ConcurrentHashMap<String, List<FlowRule>>();
if (list == null) {
return newRuleMap;
}
for (FlowRule rule : list) {
if (StringUtil.isBlank(rule.getLimitApp())) {
rule.setLimitApp(FlowRule.LIMIT_APP_DEFAULT);
}
Controller rater = new DefaultController(rule.getCount(), rule.getGrade());
if (rule.getGrade() == RuleConstant.FLOW_GRADE_QPS
&& rule.getControlBehavior() == RuleConstant.CONTROL_BEHAVIOR_WARM_UP
&& rule.getWarmUpPeriodSec() > 0) {
rater = new WarmUpController(rule.getCount(), rule.getWarmUpPeriodSec(), ColdFactorProperty.coldFactor);
} else if (rule.getGrade() == RuleConstant.FLOW_GRADE_QPS
&& rule.getControlBehavior() == RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
&& rule.getMaxQueueingTimeMs() > 0) {
rater = new PaceController(rule.getMaxQueueingTimeMs(), rule.getCount());
}
rule.setRater(rater);
String identity = rule.getResource();
List<FlowRule> ruleM = newRuleMap.get(identity);
if (ruleM == null) {
ruleM = new ArrayList<FlowRule>();
newRuleMap.put(identity, ruleM);
}
ruleM.add(rule);
}
return newRuleMap;
}
- 这里主要是设置rater,rater有两种,一种是WarmUpController,另外一种是PaceController
小结
- 在sentinel的dashboard给指定实例添加限流规则的话,会同步调用实例的sentinel接口,发送setRules指令
- 应用端接收到setRules指令之后,使用ModifyRulesCommandHandler来处理,具体就是将规则覆盖本地
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。