- Published on
Sentinel原理和使用
总体的框架如下:
Sentinel 里,最关键的是两个概念:资源、规则,resource、rule,资源是什么意思,资源,可以是任何东西,一般指的是你的一块代码,访问数据库、rpc调用、访问es、调用其他服务、对第三方平台发起http调用、系统所有接口请求的入口(filter、interceptor拦截器),代码,各种代码,都可能去访问各种资源。
定义一块资源,就是一块代码,这个代码在做一些事情,定义资源对应的一个规则,流控、降级、热点、授权,**Sentinel **支持各种各样的规则,对一块资源的访问,是对依赖系统发起rpc调用,配置对应的规则,对这个系统的rpc调用,他能放行的线程数量只有20个,就可以实现对依赖系统调用的舱壁隔离。
public static void main(String[] args) {
// 配置规则.
initFlowRules();
while (true) {
// 1.5.0 版本开始可以直接利用 try-with-resources 特性
try (Entry entry = SphU.entry("HelloWorld")) {
// 被保护的逻辑
System.out.println("hello world");
} catch (BlockException ex) {
// 处理被流控的逻辑
System.out.println("blocked!");
}
}
}
@SentinelResource("HelloWorld")
public void helloWorld() {
// 资源中的逻辑
System.out.println("hello world");
}
private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("HelloWorld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20.
rule.setCount(20);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
sentinel dashboard
https://github.com/alibaba/Sentinel/releases
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
用户名和密码:sentinel
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>x.y.z</version>
</dependency>
-Dcsp.sentinel.dashboard.server=consoleIp:port
Sentinel责任链模式工作原理分析
Sentinel核心源码以及工作原理,是基于责任链模式,来进行的,在里面定义了很多的slot(功能槽位,function slot,不是data slot),通过很多个slot顺序编排和串行执行,形成了一个责任链模式。
对于我们通过各种方式定义的资源,真正代码在执行的时候,对每个资源的调用都会走一系列的slot,各个slot可以干自己的事情,他还做了一个SPI机制,跟dubbo是类似的,SPI扩展机制,dubbo源码,SPI是一个重点,就是说可以扩展他的slot功能槽位,加入你自己的功能槽位,而且你还可以按照你自己的想法,去编排slot顺序。
资源调用路径:
- odeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于 根据调用路径来限流降级;
- ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
- StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
- FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
- AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
- DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;
- SystemSlot 则通过系统的状态,例如 load1 等,来控制总的入口流量;
Sentinel资源定义和各类规则介绍
定义资源:框架适配(自动定义资源点),代码定义Entry,注解,各类规则
FlowRule,流控规则
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,资源名是限流规则的作用对象 | |
count | 限流阈值 | |
grade | 限流阈值类型,QPS或线程数模式 | QPS模式 |
limitApp | 流控针对的调用来源 | default,代表不区分调用来源 |
strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流 | 直接拒绝 |
private static void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource(resource);
// Set max qps to 20
rule1.setCount(20);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
DegradeRule
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
private static void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule(resource);
.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
.setCount(0.7); // Threshold is 70% error ratio
.setMinRequestAmount(100)
.setStatIntervalMs(30000) // 30s
.setTimeWindow(10);
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
SystemRule
Field | 说明 | 默认值 |
---|---|---|
highestSystemLoad | load1 触发值,用于触发自适应控制阶段 | -1 (不生效) |
avgRt | 所有入口流量的平均响应时间 | -1 (不生效) |
maxThread | 入口流量的最大并发数 | -1 (不生效) |
qps | 所有入口资源的 QPS | -1 (不生效) |
highestCpuUsage | 当前系统的 CPU 使用率(0.0-1.0) | -1 (不生效) |
private void initSystemProtectionRule() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(10);
rules.add(rule);
SystemRuleManager.loadRules(rules);
}
授权规 则
- resource:资源名,即限流规则的作用对象
- limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB
- strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式
规则默认在内存里,即使动态修改了,重启就丢失,因此需要基于二次开发和改造,能够结合sentinel、nacos、redis、zk等存储去持久化规则,每次启动就加载最新的规则。
__
Spring Cloud Gateway如何基于Sentinel进行限流
- 必须要在spring cloud gateway工程里,引入sentinel的依赖
- 必须要在spring cloud gateway工程里,定义一些sentinel自己实现的gateway的filter一样的东西,让gateway收到请求之后,可以交给sentinel来做一个处理
- sentinel应该会按照自己默认的一个规则,把收到的请求自动的识别为一个一个的资源,所有接收到的HTTP请求的都会被识别为资源
- 打通跟sentinel dashboard整合,在里面可以对网关里识别出来的各种资源点,做一个限流规则的配置,下发给网关工程里的sentinel,限流规则生效
Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块,此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑
- GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流
- ApiDefinition:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/** 和 /baz/** 的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。
- 其中网关限流规则 GatewayFlowRule 的字段解释如下
- resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称
- resourceMode:规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route
- grade:限流指标维度,同限流规则的 grade 字段
- count:限流阈值
- intervalSec:统计时间窗口,单位是秒,默认是 1 秒
- controlBehavior:流量整形的控制效果,同限流规则的 controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败
- burst:应对突发请求时额外允许的请求数目
- maxQueueingTimeoutMs:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效
- paramItem:参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:
- parseStrategy:从请求中提取参数的策略,目前支持提取来源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意 Header(PARAM_PARSE_STRATEGY_HEADER)和任意 URL 参数(PARAM_PARSE_STRATEGY_URL_PARAM)四种模式。
- fieldName:若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。
- pattern:参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则统计该请求属性的所有值。(1.6.2 版本开始支持)
- matchStrategy:参数值的匹配策略,目前支持精确匹配(PARAM_MATCH_STRATEGY_EXACT)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正则匹 配(PARAM_MATCH_STRATEGY_REGEX)。(1.6.2 版本开始支持)
Sentinel在网关中实现限流的原理分析
-Dcsp.sentinel.app.type=1
根据你的请求url,匹配到spring cloud gateway里配置的route路由规则;或者是你自定义的API分组里的url模式;此时就可以把当前的url请求划分到一个资源里去,这就属于针对某个资源的请求和访问。
正常来说,他会把你的dashboard里配置的网关规则拉过来,是会去进行网关规则的管理,如果说你没配置热点参数的规则,默认他就是普通的流量规则。
检查一下,你当前这个请求匹配上的资源,他的流量规则会执行一下,流量规则在执行的时候,slot功能槽的链条,一环一环的,先去做一些数据统计,根据数据统计再去执行流量规则,看是否要进行限流。
被限流掉的话,此时你还可以实现一个自己的block request handler,被限流的请求应该如何来进行处理。
为业务系统入口网关增加Sentinel限流
Sentinel自适应流控原理
老的自适应的算法,看cpu负载,如果cpu负载比较高了,就做一下限流,把流量降下来,监控cpu负载,如果cpu负载降下来了,再把流量多放一些出去,cpu负载又会上来,再把流量降下来,cpu负载又会下去。
我希望的不是这样的效果,我们希望的效果,应该,当cpu负载达到一个高位的状态的时候,同时此时还能承受,我们就对流量做一个计算,看看大致流量控制在什么级别,可以让cpu负载在高位上,但是不会到危险的瓶颈,在cpu负载高位稳定的状态下,让流量就稳定的通过就可以了。就是在cpu负载尽可能高但是稳定的情况下,让流量/并发量尽可能高而且平稳的通过 -> 目标和效果(要实现这样的效果,sentinel的自适应的流控的效果)。
你要去定义你的系统里的入口流量的进入点
默认所有的资源,EntryType都是OUT,资源点都是出口流量,都是你的系统对外往外发送出去的,针对后端的系统的调用,对于你的系统而言,针对其他服务的调用,数据存储的访问。
一般来说如果你要是tomcat对外http请求的系统,此时可以基于spring mvc做一个拦截器,filter一类的东西,所有请求还没到controller呢,所有的请求都会经过一个filter拦截器,在这个里面,定义一个入口流量资源点,让所有入口流量都经过这个资源点。
dubbo服务,dubbo自己也是有filter机制,定义过滤器,所有的请求先走filter过滤器,在里面去定义流量进入点,所有的dubbo服务的流量都会经过这个流量进入点。
在dashboard里配置系统流控的规则
如果说你的机器cpu使用率达到了80%,此时你的入口流量进入点,他就会开始使用自适应流控算法,思路,尽可能算出来你此时的QPS和每个请求的平均响应时间,去计算一下,此时应该让你的流量保持再每秒处理多少个请求,才可以让你的系统在cpu负载较高的情况下,保持一个稳定的请求处理的速率。
在大部分公司里,包括是一些大厂,其实限流这块,主要的是两个,一个是网关限流,一个是每个系统自己的接口集群限流,对一个系统每个接口单独的去做一个压测,测试出来每个核心接口他的极限最大的TPS值是多少。
对每个接口最大的TPS值,会去配置一个接口的集群限流规则,在系统集群部署的情况之下,接口集群模式下,可以抗多大的TPS,对每个接口的限流值,还不一定完全是用TPS值,我们会压一下,整体系统最大压力值,TPS,看看里面各个接口被访问的频率是多少,再根据访问频率的占比,去设置每个接口的TPS限流
1000 /4 = 250,也可以这样去设置