sentinel 增加规则的方式 包括三种,数据源加载,代码加载,控制台加载;每一类流控规则我都会从这三个方面去说明如何使用。
流量控制是通过监控应用流量的qps或者并发线程数是否达到阈值来保护应用的一种手段,避免应用被瞬时的流量高峰冲垮,从而保障系统的高可用。
流量控制的方式:
流量控制的相关概念:
流控规则代码方式配置示例:
FlowRule rule1 = new FlowRule();
rule1.setResource("test.hello");
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 每秒调用最大次数为 1 次
rule1.setCount(1);
List<FlowRule> rules = new ArrayList<>();
// 将控制规则载入到 Sentinel
FlowRuleManager.loadRules(rules);
流控规则控制台配置示例:
流控规则数据源json示例:
[{"clusterConfig":{"acquireRefuseStrategy":0,"clientOfflineTime":2000,"fallbackToLocalWhenFail":true,"resourceTimeout":2000,"resourceTimeoutStrategy":0,"sampleCount":10,"strategy":0,"thresholdType":0,"windowIntervalMs":1000},"clusterMode":false,"controlBehavior":0,"count":1.0,"grade":1,"limitApp":"default","maxQueueingTimeMs":500,"resource":"test","strategy":0,"warmUpPeriodSec":10}]
熔断降级会在调用链路中当某个资源指数超出阈值时对这个资源的调用进行熔断,在熔断时间窗口内所有调用都快速失败调用降级方法,直到熔断恢复; 降级熔断和流控规则的区别是在超出阈值后的时间窗内所有的调用都会被降级,直到熔断恢复。
熔断降级相关概念:
熔断降级策略:
降级熔断代码配置
DegradeRule rule = new DegradeRule();
List<DegradeRule> rules1=new ArrayList<>();
//资源名称
rule.setResource("test.hello");
// 熔断平均响应时间阈值
rule.setCount(0.01);
// 秒级RT
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
rule.setTimeWindow(10);
rules1.add(rule);
DegradeRuleManager.loadRules(rules1);
流控规则控制台配置示例:
热点规则是对热点数据进行限流,支持对特定参数和参数的值限流。热点限流会统计参数中的热点参数,并根据配置的限流阈值与模式对包含热点参数的资源进行限流。 Sentinel利用LRU策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
热点规则的概念:
热点规则代码配置
ParamFlowRule paramFlowRule = new ParamFlowRule("resourceName")
.setParamIdx(0)
.setCount(5);
// 单独设置限流 QPS,设置param 参数限流规则
ParamFlowItem item = new ParamFlowItem().setObject("param")
.setClassType(int.class.getName())
.setCount(10);
paramFlowRule.setParamFlowItemList(Collections.singletonList(item));
ParamFlowRuleManager.loadRules(Collections.singletonList(paramFlowRule));
流控规则控制台配置示例:
系统规则限流是从整体维度上去进行流控,结合应用的load,cpu使用率,总体平均RT,入口QPS和并发线程数等几个维度的监控指标来对总体的流量进行限流,在系统稳定的前提下保证系统的吞吐量
系统规则模式:
系统规则的概念
系统规则配置代码示例:
因为系统规则只对入口规则进行限定,所以需要将资源通过注解配置 @SentinelResource(entryType = EntryType.IN)
来指定为入口资源
// 指定资源为入口资源
@GetMapping("/test3")
@SentinelResource(entryType = EntryType.IN)
public String test3(){
return ">>>>>>>>";
}
SystemRule systemRule = new SystemRule();
systemRule.setHighestCpuUsage(0.8);
systemRule.setAvgRt(10);
systemRule.setQps(10);
systemRule.setMaxThread(10);
systemRule.setHighestSystemLoad(2.5);
SystemRuleManager.loadRules(Collections.singletonList(systemRule));
授权规则的作用是根据调用来源来拦截调用资源的请求,当不符合放行规则的请求过来就会被拒绝掉。
授权规则的概念
授权规则代码配置示例:
AuthorityRule authorityRule = new AuthorityRule();
authorityRule.setStrategy(RuleConstant.AUTHORITY_BLACK);
authorityRule.setLimitApp("127.0.0.1");
authorityRule.setResource("test.hello");
AuthorityRuleManager.loadRules(Collections.singletonList(authorityRule));
这里 limitApp 我设置的是 请求来源的ip 地址,这个ip地址是要我们手动去通过 ContextUtil.enter(resourceName, origin)
来设置的。
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
ContextUtil.enter("test.hello", request.getHeader("x-forwarded-for"));
return true;
}
}
前文提到过 sentinel-spring-webmvc-adapter
依赖会提供一个将拦截器 SentinelWebInterceptor
, 源码为:
protected String getResourceName(HttpServletRequest request) {
Object resourceNameObject = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
if (resourceNameObject != null && resourceNameObject instanceof String) {
String resourceName = (String)resourceNameObject;
UrlCleaner urlCleaner = this.config.getUrlCleaner();
if (urlCleaner != null) {
resourceName = urlCleaner.clean(resourceName);
}
if (StringUtil.isNotEmpty(resourceName) && this.config.isHttpMethodSpecify()) {
resourceName = request.getMethod().toUpperCase() + ":" + resourceName;
}
return resourceName;
} else {
return null;
}
}
它会解析一个请求为的请求地址为一个资源名,然后在sentinel控制台上就能看到各个请求的流控数据。但它没有提供请求适配各类流控规则的相关代码, 我们想要无缝的通过请求去适配各种流控规则还需要引入依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.1</version>
</dependency>
然后注册一个过滤器:
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns("/*");
registration.setName("sentinelFilter");
registration.setOrder(1);
return registration;
}
接入 filter 之后,所有访问的 Web URL 就会被自动统计为 Sentinel 的资源,可以针对单个 URL 维度进行流控。
若希望区分不同 HTTP Method,可以调用 CommonFilter.init(FilterConfig filterConfig)
方法将 HTTP_METHOD_SPECIFY 这个 init parameter 设为 true,给每个 URL 资源加上前缀,比如 GET:/foo
这个包中一个重要类是 WebCallbackManager
许多限流配置都需要使用到这个类的api。
设置限流处理器:
WebCallbackManager.setUrlBlockHandler((request, response, e) -> {
PrintWriter writer = response.getWriter();
writer.println(">>>>");
writer.close();
});
设置url清洗器:
WebCallbackManager.setUrlCleaner(new UrlCleaner() {
@Override
public String clean(String originUrl) {
if (originUrl == null || originUrl.isEmpty()) {
return originUrl;
}
// 比如将满足 /foo/{id} 的 URL 都归到 /foo/*
if (originUrl.startsWith("/foo/")) {
return "/foo/*";
}
// 不希望统计 *.ico 的资源文件,可以将其转换为 empty string (since 1.6.3)
if (originUrl.endsWith(".ico")) {
return "";
}
return originUrl;
}
});
设置请求来源名称,通过该配置我们在授权规则中就不需要通过ContextUtil.enter(resourceName, origin)
设置,而是通过一个自定义
的RequestOriginParser
直接指定请求的来源,也就是授权规则中的 limitApp
:
WebCallbackManager.setRequestOriginParser(request -> {
return request.getHeader("x-forwarded-for");
});