My logo
Published on

Sentinel原理和使用

总体的框架如下:

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顺序。

资源调用路径:

  1. odeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
  2. ClusterBuilderSlot 则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
  3. StatisticSlot 则用于记录、统计不同纬度的 runtime 指标监控信息;
  4. FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
  5. AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
  6. DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;
  7. 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说明默认值
highestSystemLoadload1 触发值,用于触发自适应控制阶段-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进行限流

  1. 必须要在spring cloud gateway工程里,引入sentinel的依赖
  2. 必须要在spring cloud gateway工程里,定义一些sentinel自己实现的gateway的filter一样的东西,让gateway收到请求之后,可以交给sentinel来做一个处理
  3. sentinel应该会按照自己默认的一个规则,把收到的请求自动的识别为一个一个的资源,所有接收到的HTTP请求的都会被识别为资源
  4. 打通跟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,也可以这样去设置