目前Sentinel支持以下五种限流/熔断规则:基于资源限流(FlowRule)、系统自适应限流(SystemRule)、系统熔断降级(DegradeRule)、热点参数限流(ParamFlowRule),sentinel还支持基于授权的限流(AuthorityRule),其父类为AbstractRule
。
另外,Sentinel还支持网关限流,说到底就是Filter限流,控制限流资源范围。其实现原理为为Servlet添加了一个CommonFilter,doFilter方法如下:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest sRequest = (HttpServletRequest)request;
Entry urlEntry = null;
try {
String target = FilterUtil.filterTarget(sRequest);
UrlCleaner urlCleaner = WebCallbackManager.getUrlCleaner();
if (urlCleaner != null) {
target = urlCleaner.clean(target);
}
if (!StringUtil.isEmpty(target)) {
String origin = this.parseOrigin(sRequest);
String contextName = this.webContextUnify ? "sentinel_web_servlet_context" : target;
ContextUtil.enter(contextName, origin);
//=============标记请求路径为资源 start===============
if (this.httpMethodSpecify) {
String pathWithHttpMethod = sRequest.getMethod().toUpperCase() + ":" + target;
urlEntry = SphU.entry(pathWithHttpMethod, 1, EntryType.IN);
} else {
urlEntry = SphU.entry(target, 1, EntryType.IN);
}
//=============标记请求路径为资源 end===============
}
chain.doFilter(request, response);
} catch (BlockException var15) {
HttpServletResponse sResponse = (HttpServletResponse)response;
WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, var15);
} catch (ServletException | RuntimeException | IOException var16) {
Tracer.traceEntry(var16, urlEntry);
throw var16;
} finally {
if (urlEntry != null) {
urlEntry.exit();
}
ContextUtil.exit();
}
}
“资源”在一个系统中是唯一的吗?即不同接口上的资源名称可以重复吗?
答:可以重复。resource相当于是一个分类,可以加在不同的接口上。
相同名称的rule可以加载成功吗?
答:不可以,同一种类型的rule名称应保持唯一,规则会被放到一个Map中,key为resource名称。源码:com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil#buildFlowRuleMap(java.util.List
一个资源名称,在两个接口上一起使用时,限流统计规则是两个接口一起还是独立计算?
答:独立计算。
是否允许通配的方式批量添加到controller层?
答:可以。具体操作方法见第四节《网关限流》,其原理是基于Filter,请求进来的时候就被标记了资源。
资源定义的方式有很多种,建议通过注解。
通用异常处理方式?
答:平台可以添加统一的异常处理,违反限流规则会抛出FlowException。源码追溯:com.alibaba.csp.sentinel.slots.block.flow.FlowRuleChecker#checkFlow
。
定义规则名称,与实际注解资源不匹配会报错吗?即注解使用了错误的规则。
答:流控失败,且不会报错。
注解使用一定要放在Controller方法上吗?
答:不一定,也可以在Service、工具类中,其本质为抛出了FlowException异常。
设置了全局范围资源点,且在接口上未定义其他资源,那么设置的资源规则、系统规则、降级规则还生效吗?
答:1-资源规则不生效,检查过程是根据资源名称获取规则后再校验的,如图得到的规则未空,实际上是配置了资源规则的。
public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource,
Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {
if (ruleProvider == null || resource == null) {
return;
}
Collection<FlowRule> rules = ruleProvider.apply(resource.getName());
if (rules != null) {
for (FlowRule rule : rules) {
if (!canPassCheck(rule, context, node, count, prioritized)) {
throw new FlowException(rule.getLimitApp(), rule);
}
}
}
}
2-系统规则生效。com.alibaba.csp.sentinel.slots.system.SystemRuleManager#checkSystem
3-降级规则不生效。
public static void checkDegrade(ResourceWrapper resource, Context context, DefaultNode node, int count)
throws BlockException {
Set<DegradeRule> rules = degradeRules.get(resource.getName());
if (rules == null) {
return;
}
for (DegradeRule rule : rules) {
if (!rule.passCheck(context, node, count)) {
throw new DegradeException(rule.getLimitApp(), rule);
}
}
}
Sentinel的官网文档已经很是完整了,此处仅是在下做的一些小总结。当然Sentinel的功能还是非常强大的,参数类型也众多,未能测试全面。大家在测试过程中可以使用测试工具JMeter进行测试。
顺便说两句,关于如何学习一个工具有两种思路:
大家在学习的过程中,建议2种方式结合一下。通过测试
来了解
基本功能,通过读源码
来解释测试结果
。这样双管齐下,便可进一步加深理解,学习软件背后的学习思路~
大家如有问题欢迎与我交流~