概述

  1. 官方网站

    Sentinel熔断与限流 - 图1

    随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。

  2. 基本概念

    Sentinel熔断与限流 - 图2

  3. 功能和设计理念

    • 流量控制

      Sentinel熔断与限流 - 图3

    • 熔断降级

      Sentinel熔断与限流 - 图4

      设计理念

      Sentinel熔断与限流 - 图5

    • 系统负载保护

      Sentinel熔断与限流 - 图6

  4. Sentinel是如何工作的

    Sentinel熔断与限流 - 图7

快速开始

Sentinel 的使用可以分为两个部分:

  • 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持(见 主流框架适配)。
  • 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。

运行控制台

  1. 下载控制台jar包
  2. 运行控制台

    默认端口号8080,建议本地运行。

    假如Sentinel控制台运行在服务器,需要监控的程序运行在本机。会存在通信问题。

    Sentinel熔断与限流 - 图8

  3. 登录页面

    用户名密码默认sentinel

    Sentinel熔断与限流 - 图9

Sentinel核心库

  • 创建一个模块并使用Sentinel核心库和控制台对其进行监控

    1. 创建Module

      创建一个带有Sentinel功能的Module

      Sentinel熔断与限流 - 图10

    2. 修改pom依赖

      引入Sentinel,并使用Nacos作为服务注册和发现

  1. <dependencies>
  2. <!--SpringCloud ailibaba nacos -->
  3. <dependency>
  4. <groupId>com.alibaba.cloud</groupId>
  5. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  6. </dependency>
  7. <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
  8. <dependency>
  9. <groupId>com.alibaba.csp</groupId>
  10. <artifactId>sentinel-datasource-nacos</artifactId>
  11. </dependency>
  12. <!--SpringCloud ailibaba sentinel -->
  13. <dependency>
  14. <groupId>com.alibaba.cloud</groupId>
  15. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  16. </dependency>
  17. <!--openfeign-->
  18. <dependency>
  19. <groupId>org.springframework.cloud</groupId>
  20. <artifactId>spring-cloud-starter-openfeign</artifactId>
  21. </dependency>
  22. <!-- SpringBoot整合Web组件+actuator -->
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-web</artifactId>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.springframework.boot</groupId>
  29. <artifactId>spring-boot-starter-actuator</artifactId>
  30. </dependency>
  31. </dependencies>
  1. 编写配置文件

    Sentinel熔断与限流 - 图11

  2. 主程序类

    Sentinel熔断与限流 - 图12

  3. 应用程序

    Sentinel熔断与限流 - 图13

  4. 测试

    直接请求此接口,可以在控制台看到监控数据

    Nacos显示的服务信息

    Sentinel熔断与限流 - 图14

    Sentinel控制台显示的信息

    Sentinel熔断与限流 - 图15

对快速开始示例的分析

  • 参考阿里 Sentinel 源码解析,在此强烈推荐
  • 首先为什么普通的Controller方法称为资源?

    我们并未像Sentinel官网实例代码中定义资源,为什么可以对其进行监控??

    Sentinel熔断与限流 - 图16

    首先在,在Sentinel启动的时候会进行自动装配

    Sentinel熔断与限流 - 图17

    其中SentinelWebAutoConfiguration就是用于配置Web请求的

    注入一个对象,其中配置了拦截器,拦截所有的请求

    Sentinel熔断与限流 - 图18

    初始化完成之后,我们发送请求,

    首先对我们的请求进行拦截,ApplicationFilterChain是FilterChain的具体实现

    Sentinel熔断与限流 - 图19

    Sentinel熔断与限流 - 图20

    然后进入到CommonFilter中的doFilter方法中

    Sentinel熔断与限流 - 图21

    由于是第一次调用ContextUtil方法,所以需要先完成加载连接初始化过程

    其中的静态代码块就会被执行。

    Sentinel熔断与限流 - 图22

    由于我们没有显示调用ContextUtil.enter方法,所以初始化之后,默认的树结构是

    Sentinel熔断与限流 - 图23

    初始化完成之后,执行我们在doFilter中调用的enter方法

    过程就是创建一个EntranceNode然后添加到树结构中,名为sentinel_web_servlet_context

    Sentinel熔断与限流 - 图24

    此时的树结构

    Sentinel熔断与限流 - 图25

    执行完之后继续回到doFilter方法中,接下来会执行SphU.entry方法

    Sentinel熔断与限流 - 图26

    过程中会将请求包装成ResourceWrapper类型,name属性为请求的路径

    Sentinel熔断与限流 - 图27

    下面使用的文章中的内容

    最终会来到CtSph#entryWithPriority方法,这个方法是 Sentinel 的骨架,非常重要。

    Sentinel熔断与限流 - 图28

    如果某个Slot拒绝执行请求,将抛出BlockException异常,catch之后会抛出此异常。后面会演示默认的异常。

    最终链路图如下

    Sentinel熔断与限流 - 图29

Sentinel工作主要流程

  • 弄清了我们的请求如何变为Sentinel的资源之后,我们再看官网的原理部分

    每一个请求都会对应到一个资源(EntranceNode,用于构成树形结构)以及一个Entry

    Sentinel熔断与限流 - 图30

    然后创建的Entry中会有多个插槽,对当前的请求进行处理,如果某个插槽抛出了异常,就表示此请求将要被熔断降级处理

    Sentinel熔断与限流 - 图31

资源和规则

我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。使用 Sentinel 来进行资源保护,主要分为几个步骤:

  1. 定义资源
  2. 定义规则
  3. 检验规则是否生效

先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。

  • 定义资源的方式

    定义资源的方式有:默认框架适配,抛出异常的方式定义资源(try catch),注解支持,返回BOOlean的方式定义资源,异步调用支持

    Sentinel熔断与限流 - 图32

    Sentinel熔断与限流 - 图33

  • 定义规则:Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。

    • Sentinel 支持以下几种规则:流量控制规则熔断降级规则系统保护规则来源访问控制规则热点参数规则
    • 下面细说。

流量控制规则

  • DashBoard中的流控功能页面内

    Sentinel熔断与限流 - 图34

    来源就是

    Sentinel熔断与限流 - 图35

  • 概述

    Sentinel熔断与限流 - 图36

  • 基于QPS流量控制

    基于每秒查询率(QPS,Queries-per-second)的演示

    Sentinel熔断与限流 - 图37

    表示的意思是:每秒的请求数超过5个的时候,就直接失败。也就是抛出FlowException(默认,可以配置)

    Sentinel熔断与限流 - 图38

    Sentinel熔断与限流 - 图39

    基于QPS的流控效果有三种

    Sentinel熔断与限流 - 图40

    • 快速失败

      当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出**FlowException**这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时

      如上演示

    • Warm Up

      该方式主要用于系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。

      通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮的情况。

      应用场景:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。

      Sentinel熔断与限流 - 图41 在预热时间段内,能够处理的QPS从【阈值/3(固定值3,冷加载因子)】逐渐增长到阈值

      Sentinel熔断与限流 - 图42

      比如如下配置,当QPS达到3(10/3)的时候,流量控制开始介入,在5s的时间内,使其QPS达到10

      Sentinel熔断与限流 - 图43

      演示,刚开始的时候很容易降级,后面越来越不容易降级(未超过阈值)

      Sentinel熔断与限流 - 图44


  • 排队等待

    这种方式严格控制了请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

    这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

    Sentinel熔断与限流 - 图45Sentinel熔断与限流 - 图46

  • 基于线程数的流量控制

    线程数限流用于保护业务线程数不被耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。

    为应对高线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离),或者使用信号量来控制同时请求的个数(信号量隔离)。这种隔离方案虽然能够控制线程数量,但无法控制请求排队时间。当请求过多时排队也是无益的,直接拒绝能够迅速降低系统压力。

    Sentinel线程数限流不负责创建和管理线程池,而是简单统计当前请求上下文的线程个数,如果超出阈值,新的请求会被立即拒绝。 Sentinel熔断与限流 - 图47

    设置同时执行此业务代码的线程数上限!超过就直接失败。这样避免了业务线程的大量创建。

    Sentinel熔断与限流 - 图48

    Sentinel熔断与限流 - 图49


  • 基于调用关系的流量控制

    即流控模式,基于QPS和线程数都适用

    Sentinel熔断与限流 - 图50

    调用关系包括调用方、被调用方;方法又可能会调用其它方法,形成一个调用链路的层次关系。Sentinel 通过 NodeSelectorSlot 建立不同资源间的调用的关系,并且通过 ClusterNodeBuilderSlot 记录每个资源的实时统计信息。

    有了调用链路的统计信息,我们可以衍生出多种流量控制手段。

    1. 根据调用方限流(直接)

      ContextUtil.enter(resourceName, origin) 方法中的 origin 参数标明了调用方身份。这些信息会在 ClusterBuilderSlot 中被统计。

      针对来源:default表示不区分调用者,来自任何调用者的请求都将进行限流统计。如果这个资源名的调用总和超过了这条规则定义的阈值,则触发限流。

      Sentinel熔断与限流 - 图51

      {some_origin_name}:表示针对特定的调用者,只有来自这个调用者的请求才会进行流量控制

      other:表示针对**{some_origin_name}** 以外的其余调用方的流量进行流量控制。

      优先级:同一个资源名可以配置多条规则,规则的生效顺序为:{some_origin_name} > other > default

    2. 根据调用链路入口限流(链路)

      Sentinel熔断与限流 - 图52

      比如

      Sentinel熔断与限流 - 图53

      /testC和/testD 都调用sayHello

      这里配置入口资源/testC

      表示从/testC入口访问的sayHello达到QPS为5时直接失败,而不对/testD进行限制

      需要手动配置关闭链路聚合,参考

    3. 具有关联关系的资源流量控制(关联)

      当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。

      当关联的资源达到限流条件时,开启限流,适合做应用让步。例如为一个查询的接口添加关联流控,关联资源为一个更新的接口,当更新的接口达到阈值时,开启查询接口的限流,为更新接口让步服务器资源。

      Sentinel熔断与限流 - 图54

      可以看到/testA的QPS是超不过5000的,更多的资源倾斜给了B

      Sentinel熔断与限流 - 图55

熔断降级

  • 除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。
  • 一个服务常常会调用别的模块,被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
  • 复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

熔断策略

新建一个客户端程序,调用服务端的代码

客户端

Sentinel熔断与限流 - 图56

Sentinel熔断与限流 - 图57

  1. 慢调用比例

    选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。

    当单位统计时长(**statIntervalMs**)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。

    经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

    Sentinel熔断与限流 - 图58

    如上配置表示:

    在统计时长1s内,当请求数量超过5个,并且其中慢调用(请求响应时长超过1s)的个数大于所有统计时长1s内所有请求的20%的时候,就对/consumer/sayhello/进行熔断,熔断时长为10s

    注意:最小请求数

    Sentinel熔断与限流 - 图59 服务端

    Sentinel熔断与限流 - 图60

    熔断规则

    Sentinel熔断与限流 - 图61

    使用Jmeter进行测试

    2s内发送20个请求,sleep时长为2s。

    Sentinel熔断与限流 - 图62

    Sentinel熔断与限流 - 图63

    Jmeter结束后立即进行浏览器访问,可以发现sleep为1s,没有超过最大响应时间也会被降级

    Sentinel熔断与限流 - 图64

    经过熔断时长5s后,进入到恢复状态,请求响应时间没有超过最大响应时间可以正常访问;否则继续熔断(这里没有测试出效果)

    Sentinel熔断与限流 - 图65


  1. 异常比例

    当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。

    经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

    Sentinel熔断与限流 - 图66

    比如,当1s内的请求进来10个,其中异常的请求数量大于50%,那么就进入熔断

  2. 异常数

    当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

    Sentinel熔断与限流 - 图67

    比如,当1s内进来20个请求,其中有10个请求出现了异常,那么会进入熔断

  3. 注意:注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。开源整合模块,如 Sentinel Dubbo Adapter, Sentinel Web Servlet Filter 或 @SentinelResource 注解会自动统计业务异常,无需手动调用。

热点参数限流

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。

热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

Sentinel熔断与限流 - 图68

Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。

  • 案例演示

    Sentinel熔断与限流 - 图69

    热点参数限流

    Sentinel熔断与限流 - 图70

    Sentinel熔断与限流 - 图71

    测试

    Sentinel熔断与限流 - 图72

    Sentinel熔断与限流 - 图73

  • 高级选项

    参数例外项:在基础配置之上对参数的具体值进行限制

    Sentinel熔断与限流 - 图74

    测试

    Sentinel熔断与限流 - 图75

系统自适应保护

  • Sentinel 系统自适应保护从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
  • 系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
    系统规则支持以下的阈值类型:
    • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5
    • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
    • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
    • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
    • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

      Sentinel熔断与限流 - 图76

注解支持

  • @SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。注解方式埋点不支持 private 方法。
  • blockHandler降级处理方法

    blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException

    blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

    Sentinel熔断与限流 - 图77

    测试

    Sentinel熔断与限流 - 图78

    抛出的FlowException是BlockException的子类

    Sentinel熔断与限流 - 图79

  • fallback异常处理方法

    默认 fallback 函数可以针对所以类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。

    当然不包括限流抛出的BlockException

    Sentinel熔断与限流 - 图80

  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

  • 特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级并且抛出异常同时发生,只会进入 blockHandler 处理逻辑
  • 若未配置 blockHandlerfallbackdefaultFallback,则被限流降级时会将 BlockException 直接抛出

Sentinel规则持久化

Sentinel 的理念是开发者只需要关注资源的定义,当资源定义成功后可以动态增加各种流控降级规则。Sentinel 提供两种方式修改规则:

  • 通过 API 直接修改 (loadRules)
  • 通过 DataSource 适配不同数据源修改

上述 loadRules() 方法只接受内存态的规则对象,但更多时候规则存储在文件、数据库或者配置中心当中。DataSource 接口给我们提供了对接任意配置源的能力。相比直接通过 API 修改规则,实现 DataSource 接口是更加可靠的做法。

  • 通过Nacos来持久化Sentinel规则

    由于在Sentinel Dashboard配置的规则只是内存态的,只要Sentinel客户端一启动,所有的配置就会消失。

    所以可以将配置持久化,以便再次启动的时候,可以从持久化的数据中加载以便再次进行配置

    详见官网 实现监听功能==