概述

Sentinel,阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。分布式系统的流量防卫兵。

特征:

  • 丰富的应用场景:秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
  • 完备的实时监控:实时的监控功能。通过控制台可以看到接入应用的单台机器秒级数据,甚至500台以下规模的集群的汇总运行情况
  • 广泛的开源生态:提供开箱即用的与其它开源框架/库的整合模块,如SpringCloud、Dubbo、gRPC。只需要引入相应的依赖并进行简单配置即可快速地接入Sentinel
  • 完善的SPI扩展点:提供简单易用、完善的SPI扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源

Sentinel分为两个部分:

  • 核心库:Java客户端,不依赖任何框架或库,能运行于所有Java运行时环境,对Dubbo、Spring Cloud等框架也有较好的支持
  • 控制台:Dashboard,基于Spring Boot开发,打包后可以直接运行。

实战

安装Sentinel Dashboard

Sentinel提供一个轻量级的控制台,具备机器发现、单机资源实时监控、集群资源汇总及规则管理等功能。从GitHub Release下载最新版,启动命令:java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar

浏览器访问http://localhost:8080/,默认用户名密码:sentinel/sentinel。进入后会发现只有一个服务实例,也就是sentinel-dashboard本身

服务容错框架Sentinel入门_系统保护

接入Dashboard

引入依赖:

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

需要想要应用出现在Sentinel Dashboard监控列表里面,可以在应用配置文件里增加如下配置:

spring:
  cloud:
    sentinel:
      transport:
        port: 9999 # 跟控制台交流的端口,随意指定一个未使用的端口即可
        dashboard: localhost:8080 # 指定控制台服务的地址

实时监控

簇点链路

服务容错框架Sentinel入门_响应时间_02


服务容错框架Sentinel入门_系统保护_03

问题:

  1. 如何屏蔽这些静态路径URL?
  2. sentinel_default_context是什么?

机器列表

服务容错框架Sentinel入门_sentinel_04


服务容错框架Sentinel入门_系统保护_05


使用的版本号:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>0.2.1.RELEASE</version>
</dependency>

后升级到

<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
   <version>2.1.4.RELEASE</version>
</dependency>

服务容错框架Sentinel入门_限流_06


手动移除,刷新页面:

服务容错框架Sentinel入门_系统保护_07


另外有一个服务分子是0,不难分析出此服务已下线:

服务容错框架Sentinel入门_限流_08


问题:

  1. 没有一键移除功能吗?
  2. 每次都要手动移除吗?
  3. 已经下线的服务,怎么从dashboard页面移除?

参考Sentinel/wiki/控制台#控制台配置项

但是,并没有解决问题。

集群流控

原理

项目结构

  • sentinel-core:核心模块,限流、降级、系统保护等
  • sentinel-dashboard:控制台模块,sentinel客户端可视化管理
  • sentinel-transport:传输模块,提供基本的监控服务端和客户端的API接口,以及一些基于不同库的实现
  • sentinel-extension:扩展模块,主要对DataSource进行部分扩展实现
  • sentinel-adapter:适配器模块,主要实现对一些常见框架的适配
  • sentinel-demo:样例模块
  • sentinel-benchmark:基准测试模块,对核心代码的精确性提供基准测试

概念:

  • 资源:Sentinel要保护的东西
  • 规则:用来定义如何进行保护资源

容错功能,主要体现为下面这三个:

  • 流量控制
    流量控制,它用于调整网络包的数据。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel作为一个调配器,可以根据需要把随机的请求调整成合适的形状
  • 熔断降级
    当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
    Sentinel对这个问题采取两种手段:
  1. 通过并发线程数进行限制
    Sentinel通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
  2. 通过响应时间对资源进行降级
    除了对并发线程数进行控制以外,Sentinel还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复
  • 系统负载保护
    Sentinel同时提供系统维度的自适应保护能力。当系统负载较高的时候,如果还持续让请求进入可能会导致系统崩溃,无法响应。在集群环境下,会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,Sentinel提供对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求

规则

Sentinel支持5种规则:

流控规则

监控应用流量的QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

服务容错框架Sentinel入门_响应时间_09


阈值类型/单机阈值:

  • QPS:当调用该接口的QPS达到阈值的时候,进行限流
  • 并发线程数:当调用该接口的线程数达到阈值的时候,进行限流

sentinel共有三种流控模式:

  • 直接(默认):接口达到限流条件时,开启限流
  • 关联:当关联的资源达到限流条件时,开启限流,适合做应用让步
  • 链路:当从某个接口过来的资源达到限流条件时,开启限流。有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。

流控效果

  • 快速失败:默认的,也是最简单的,直接失败抛出异常,不做任何额外的处理
  • Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的1/3,然后慢慢增长直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景
  • 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待;它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。

降级规则

也叫熔断规则,Sentinel提供三个衡量条件:

  • 平均响应时间:当资源的平均响应时间超过阈值(以ms为单位)之后,资源进入准降级状态。如果接下来1s内持续进入5个请求,它们的RT都持续超过这个阈值,那么在接下的时间窗口(以s为单位)之内,就会对这个方法进行服务降级。
  • 异常比例:当资源的每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的时间窗口(以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0, 1.0]
  • 异常数:当资源近1分钟的异常数目超过阈值之后会进行服务降级。由于统计时间窗口是分钟级别的,若时间窗口小于60s,则结束熔断状态后仍可能再进入熔断状态。

热点规则

热点参数流控规则是一种更细粒度的流控规则,它允许将规则具体到参数上。参数例外项允许对一个参数的具体值进行流控

授权规则

需要根据调用来源来判断该次请求是否允许放行,这时候可以使用Sentinel的来源访问控制的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过:

  • 若配置白名单,则只有请求来源位于白名单内时才可通过;
  • 若配置黑名单,则请求来源位于黑名单时不通过,其余的请求通过。

系统规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体Load、RT、入口QPS、CPU使用率和线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量(进入应用的流量)生效。

  • Load(仅对Linux/Unix-Like机器生效):当系统load1超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的maxQps * minRt计算得出。设定参考值一般是CPU cores * 2.5
  • RT:当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口QPS:当单台机器上所有入口流量的QPS达到阈值即触发系统保护。
  • CPU使用率:当单台机器上所有入口流量的CPU使用率达到阈值即触发系统保护。

规则持久化

Sentinel的理念是开发者只需要关注资源的定义,当资源定义成功,可以动态增加各种流控、降级规则。

Sentinel提供两种方式修改规则:

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

可以通过Dashboard来为每个Sentinel客户端设置各种各样的规则,这些规则默认是存放在内存中,所以需要将其持久化。

通过API修改规则比较直观:

FlowRuleManager.loadRules(List<FlowRule> rules); // 修改流控规则
DegradeRuleManager.loadRules(List<DegradeRule> rules); // 修改降级规则
SystemRuleManager.loadRules(List<SystemRule> rules); // 修改系统规则

DataSource扩展

上述loadRules()方法只接受内存态的规则对象,但应用重启后内存中的规则就会丢失,更多的时候规则最好能够存储在文件、数据库或者配置中心中。
DataSource接口提供对接任意配置源的能力。相比直接通过API修改规则,实现DataSource接口是更加可靠的做法。
官方推荐通过控制台设置规则后将规则推送到统一的规则中心,用户只需要实现DataSource接口,来监听规则中心的规则变化,以实时获取变更的规则。

DataSource拓展常见的实现方式:

  • 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是SQL、文件,甚至是VCS等。这样做的方式是简单,缺点是无法及时获取变更;
  • 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用Nacos、Zookeeper等配置中心。这种方式有更好的实时性和一致性保证。

@SentinelResource

可用于指定出现异常时的处理策略。主要参数如下:

属性

作用

value

资源名称

entryType

entry类型,标记流量的方向,取值IN/OUT,默认OUT

blockHandler

处理BlockException的函数名称,函数要求:

1. 必须是public

2. 返回类型 参数与原方法一致

3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置blockHandlerClass,并指定blockHandlerClass里面的方法

blockHandlerClass

存放blockHandler的类,对应的处理函数必须static修饰

fallback

用于在抛出异常的时候提供fallback处理逻辑。fallback函数可以针对所有类型的异常(除exceptionsToIgnore里面排除掉的异常类型)进行处理。函数要求:

1. 返回类型与原方法一致

2. 参数类型需要和原方法相匹配

3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass,并指定fallbackClass里面的方法。

fallbackClass

存放fallback的类。对应的处理函数必须static修饰

defaultFallback

通用的fallback逻辑。默认fallback函数可以针对所有类型的异常进行处理。若同时配置fallback和defaultFallback,以fallback为准。函数要求:

1. 返回类型与原方法一致

2. 方法参数列表为空,或有一个Throwable类型的参数。

3. 默认需要和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass,并指定fallbackClass里面的方法。

exceptionsToIgnore

指定排除掉哪些异常。排除的异常不会计入异常统计,也不会进入fallback逻辑,而是原样抛出。

exceptionsToTrace

需要trace的异常

源码分析

Node

节点

作用

StatisticNode

执行具体的资源统计操作

DefaultNode

该节点持有指定上下文中指定资源的统计信息,当在同一个上下文中多次调用entry方法时,该节点可能下会创建有一系列的子节点。另外每个DefaultNode中会关联一个ClusterNode

ClusterNode

该节点中保存资源的总体的运行时统计信息,包括rt,线程数,qps等等,相同的资源会全局共享同一个ClusterNode,不管他属于哪个上下文

EntranceNode

该节点表示一棵调用链树的入口节点,通过他可以获取调用链树中所有的子节点

Slot

每种Slot的功能职责:

  • NodeSelectorSlot:负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
  • ClusterBuilderSlot:用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
  • StatisticsSlot:用于记录,统计不同维度的 runtime 信息;
  • SystemSlot:通过系统的状态,如load1等,来控制总的入口流量;
  • AuthoritySlot:根据黑白名单,来做黑白名单控制;
  • FlowSlot:用于根据预设的限流规则,以及前面slot统计的状态,来进行限流;
  • ParamFlowSlot:
  • DegradeSlot:通过统计信息,以及预设的规则,来做熔断降级;
  • LogSlot:

每个Slot执行完业务逻辑处理后,会调用fireEntry()方法,该方法将会触发下一个节点的entry方法,下一个节点又会调用其fireEntry(),以此类推直到最后一个Slot,由此就形成Sentinel的责任链。

对比

框架

Sentinel

Hystrix

resilience4j

隔离策略

信号量隔离(并发线程数限流)

线程池隔离/信号量隔离

信号量隔离

熔断降级策略

基于响应时间、异常比率、异常数

基于异常比率

基于异常比率、响应时间

实时统计实现

滑动窗口(LeapArray)

滑动窗口(基于RxJava)

Ring Bit Buffer

动态规则配置

支持多种数据源

支持多种数据源

有限支持

扩展性

多个扩展点

插件的形式

接口的形式

基于注解的支持

支持

支持

支持

限流

基于QPS,支持基于调用关系的限流

有限的支持

Rate Limiter

流量整形

支持预热模式、匀速器模式、预热排队模式

不支持

简单的Rate Limiter模式

系统自适应保护

支持

不支持

不支持

控制台

提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等

简单的监控查看

不提供控制台,可对接其它监控系统

对比Hystrix

原则是一致的:当一个资源出现问题时,让其快速失败,不要波及到其它服务。

但是在限制的手段上,采取完全不一样的方法:

  • Hystrix采用的是线程池隔离的方式。优点:实现资源之间的隔离;缺点:增加线程切换的成本。
    Sentinel采用的是通过并发线程的数量和响应时间来对资源做限制。

参考