Spring Cloud Alibaba Sentinel 用法
Spring Cloud Alibaba Sentinel 用法
1、服务器雪崩
在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。 由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩效应” 。
服务器一步步雪崩的流程如下:
2、常见解决方案
要防止雪崩的扩散,我们就要做好服务的容错,容错说白了就是保护自己不被猪队友拖垮的一些措施, 下面介绍常见的服务容错思路和组件。
常见的容错思路有隔离、超时、限流、熔断、降级这几种。
2.1、隔离
比如服务 A 内总共有100个线程, 现在服务A可能会调用服务 B,服务 C,服务 D.我们在服务A进行远程调用的时候,给不同的服务分配固定的线程,不会把所有线程都分配给某个微服务. 比如调用服务 B 分配30个线程,调用服务 C 分配30个线程,调用服务 D 分配40个线程. 这样进行资源的隔离,保证即使下游某个服务挂了,也不至于把服务 A 的线程消耗完。比如服务 B 挂了,这时候最多只会占用服务 A 的30个线程,服务 A 还有70个线程可以调用服务 C 和服务 D。
隔离的流程如下图:
2.2、超时
在上游服务调用下游服务的时候,设置一个最大响应时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程。
2.3、限流
限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。
2.4、熔断
当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
服务熔断一般有三种状态:
- 熔断关闭状态(Closed):服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。
- 熔断开启状态(Open):后续对该服务接口的调用不再经过网络,直接执行本地的 fallback 方法。
- 半熔断状态(Half-Open):尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断关闭状态。
2.5、降级
降级也就是服务降级,当我们的服务器压力剧增为了保证核心功能的可用性 ,而选择性的降低一些功能的可用性,或者直接关闭该功能。这就是典型的丢车保帅了。 就比如贴吧类型的网站,当服务器吃不消的时候,可以选择把发帖功能关闭,注册功能关闭,改密码,改头像这些都关了,为了确保登录和浏览帖子这种核心的功能。
3、Sentinel 介绍
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
3.1、Sentinel 特征
Sentinel 具有以下特征:
- 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
- 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
3.2、Sentinel 组成部分
- 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持(见 主流框架适配)。
- 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。
3.3、Sentinel 基本概念
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
3.4、Sentinel 功能和设计理念
流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
流量控制有以下几个角度:
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
- 运行指标,例如 QPS、线程池、系统负载等;
- 控制的效果,例如直接限流、冷启动、排队等。
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
熔断降级
什么是熔断降级
除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。
熔断降级设计理念
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。
Hystrix 通过线程池的方式,来对依赖(在我们的概念中对应资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本,还需要预先给各个资源做线程池大小的分配。
Sentinel 对这个问题采取了两种手段:
- 通过并发线程数进行限制
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
- 通过响应时间对资源进行降级
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
系统负载保护
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
3.5、Sentinel 与其他类似组件比较
Sentinel | Hystrix | Resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
实时统计实现 | 滑动窗口(Leaparray) | 滑动窗口(基于 RxJava) | Ring Bit Buffer |
动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
限流 | 基于QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 | 简单的 Rate Limiter 模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 | 不提供控制台,,可对接其他监控系统 |
4、Sentinel 控制台
4.1、 概述
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。这里,我们将会详细讲述如何通过简单的步骤就可以使用这些功能。
Sentinel 控制台包含如下功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
注意:Sentinel 控制台目前仅支持单机部署。Sentinel 控制台项目提供 Sentinel 功能全集示例,不作为开箱即用的生产环境控制台,若希望在生产环境使用请根据文档自行进行定制和改造。
4.2、获取 Sentinel 控制台
您可以从 release 页面 下载最新版本的控制台 jar 包。
您也可以从最新版本的源码自行构建 Sentinel 控制台:
- 下载 控制台 工程
- 使用以下命令将代码打包成一个 fat jar:
mvn clean package
4.3、 启动
注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。
使用如下命令启动控制台:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
其中 -Dserver.port=8080
用于指定 Sentinel 控制台端口为 8080
。
从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel
。可以参考 鉴权模块文档 配置用户名和密码。
访问 localhost:8080
, 输入用户名密码登录后界面如下:
5、集成Sentinel
5.1、引入依赖
如果要在您的项目中引入 Sentinel,使用 group ID 为 com.alibaba.cloud
和 artifact ID 为 spring-cloud-starter-alibaba-sentinel
的 starter。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
5.2、编写测试接口
下面是测试的一个例子:
@RestController
@RequestMapping("/test")
public class SentinelController {
@RequestMapping("/info")
public String info(){
return "sentinel success";
}
}
5.3、配置 application.yml
server:
port: 9005
spring:
application:
name: test-sentinel
cloud:
sentinel:
transport:
port: 8770
dashboard: localhost:8080 # 指定控制台服务的地址
# 自动初始化
eager: true
这里的 spring.cloud.sentinel.transport.port
端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。
Sentinel 控制台与微服务的通信流程如下图:
Spring Cloud Alibaba Sentinel 提供了这些配置选项:
配置项 | 含义 | 默认值 |
---|---|---|
spring.application.name or project.name |
Sentinel项目名 | |
spring.cloud.sentinel.enabled |
Sentinel自动化配置是否生效 | true |
spring.cloud.sentinel.eager |
是否提前触发 Sentinel 初始化 | false |
spring.cloud.sentinel.transport.port |
应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer | 8719 |
spring.cloud.sentinel.transport.dashboard |
Sentinel 控制台地址 | |
spring.cloud.sentinel.transport.heartbeat-interval-ms |
应用与Sentinel控制台的心跳间隔时间 | |
spring.cloud.sentinel.transport.client-ip |
此配置的客户端IP将被注册到 Sentinel Server 端 | |
spring.cloud.sentinel.filter.order |
Servlet Filter的加载顺序。Starter内部会构造这个filter | Integer.MIN_VALUE |
spring.cloud.sentinel.filter.url-patterns |
数据类型是数组。表示Servlet Filter的url pattern集合 | /* |
spring.cloud.sentinel.filter.enabled |
Enable to instance CommonFilter | true |
spring.cloud.sentinel.metric.charset |
metric文件字符集 | UTF-8 |
spring.cloud.sentinel.metric.file-single-size |
Sentinel metric 单个文件的大小 | |
spring.cloud.sentinel.metric.file-total-count |
Sentinel metric 总文件数量 | |
spring.cloud.sentinel.log.dir |
Sentinel 日志文件所在的目录 | |
spring.cloud.sentinel.log.switch-pid |
Sentinel 日志文件名是否需要带上 pid | false |
spring.cloud.sentinel.servlet.block-page |
自定义的跳转 URL,当请求被限流时会自动跳转至设定好的 URL | |
spring.cloud.sentinel.flow.cold-factor |
WarmUp 模式中的 冷启动因子 | 3 |
spring.cloud.sentinel.zuul.order.pre |
SentinelZuulPreFilter 的 order | 10000 |
spring.cloud.sentinel.zuul.order.post |
SentinelZuulPostFilter 的 order | 1000 |
spring.cloud.sentinel.zuul.order.error |
SentinelZuulErrorFilter 的 order | -1 |
spring.cloud.sentinel.scg.fallback.mode |
Spring Cloud Gateway 流控处理逻辑 (选择 redirect or response ) |
|
spring.cloud.sentinel.scg.fallback.redirect |
Spring Cloud Gateway 响应模式为 'redirect' 模式对应的重定向 URL | |
spring.cloud.sentinel.scg.fallback.response-body |
Spring Cloud Gateway 响应模式为 'response' 模式对应的响应内容 | |
spring.cloud.sentinel.scg.fallback.response-status |
Spring Cloud Gateway 响应模式为 'response' 模式对应的响应码 | 429 |
spring.cloud.sentinel.scg.fallback.content-type |
Spring Cloud Gateway 响应模式为 'response' 模式对应的 content-type | application/json |
请注意。这些配置只有在 Servlet 环境下才会生效,RestTemplate 和 Feign 针对这些配置都无法生效。
5.4、查看控制台
启动服务,访问 http://localhost:9005/test/info
:
既然接口正常访问,那么接下来就是查看控制台是否有显示该接口了。
然后我们可以在 Sentinel 控制台当中对限流、熔断、热点参数、授权等进行细粒度的配置。一个很好的原则是:约定>配置>编码。
6、Sentinel 工作主流程
在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)。这些插槽有不同的职责,例如:
NodeSelectorSlot
负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;ClusterBuilderSlot
则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;StatisticSlot
则用于记录、统计不同纬度的 runtime 指标监控信息;FlowSlot
则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;AuthoritySlot
则根据配置的黑白名单和调用来源信息,来做黑白名单控制;DegradeSlot
则通过统计信息以及预设的规则,来做熔断降级;SystemSlot
则通过系统的状态,例如 load1 等,来控制总的入口流量;
总体的框架如下:
Sentinel 将 ProcessorSlot
作为 SPI 接口进行扩展(1.7.2 版本以前 SlotChainBuilder
作为 SPI),使得 Slot Chain 具备了扩展的能力。您可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。
7、Sentinel 规则配置
7.1、流量控制
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。同一个资源可以创建多条限流规则。
一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:
resource
:资源名,即限流规则的作用对象count
: 限流阈值grade
: 限流阈值类型(QPS 或并发线程数)limitApp
: 流控针对的调用来源,若为default
则不区分调用来源strategy
: 调用关系限流策略controlBehavior
: 流量控制效果(直接拒绝、Warm Up、匀速排队)
流量控制主要有两种统计类型,一种是统计并发线程数,另外一种则是统计 QPS。类型由 FlowRule
的 grade
字段来定义。其中,0 代表根据并发数量来限流,1 代表根据 QPS 来进行流量控制。其中线程数、QPS 值,都是由 StatisticSlot
实时统计获取的。
7.1.1、并发线程数控制
并发数控制用于保护业务线程池不被慢调用耗尽。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。
7.1.2、QPS流量控制
当 QPS 超过某个阈值的时候,则采取措施进行流量控制。流量控制的效果包括以下几种:直接拒绝、Warm Up、匀速排队。
-
直接拒绝:是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出
FlowException
。 -
Warm Up:即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。详细文档可以参考 流量控制 - Warm Up 文档。
-
匀速排队:严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考 流量控制 - 匀速器模式。
7.1.3、针对来源(调用方)的流控配置
default
:表示不区分调用者,来自任何调用者的请求都将进行限流统计。如果这个资源名的调用总和超过了这条规则定义的阈值,则触发限流。{some_origin_name}
:表示针对特定的调用者,只有来自这个调用者的请求才会进行流量控制。例如NodeA
配置了一条针对调用者caller1
的规则,那么当且仅当来自caller1
对NodeA
的请求才会触发流量控制。other
:表示针对除{some_origin_name}
以外的其余调用方的流量进行流量控制。例如,资源NodeA
配置了一条针对调用者caller1
的限流规则,同时又配置了一条调用者为other
的规则,那么任意来自非caller1
对NodeA
的调用,都不能超过other
这条规则定义的阈值。
同一个资源名可以配置多条规则,规则的生效顺序为:{some_origin_name} > other > default
注意:调用来源的数目不要太多(一般不要超过几百个),否则内存占用会非常多(调用来源的统计节点最大数目=资源数目*来源数目)。
7.1.4、流控模式配置
直接
:针对资源本身,接口达到限流条件时,直接限流。链路
:Sentinel 允许只根据某个入口的统计信息对资源限流。比如存在不同的调用链路A、B,我们设置从节点a(a是调用链路A当中的一个节点)过来的调用,将被记录到统计信息当中,那么调用链路B上过来的调用将不被记录到统计信息当中。关联
:当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_db
和write_db
这两个资源分别代表数据库读写,我们可以给read_db
设置限流规则来达到写优先的目的。
7.1.5、测试
1、Sentinel 控制台添加流控规则
在这里给接口 /test/info
添加最简单的限流规则: 1 秒的 QPS 阈值为 3,超过则拒绝新的请求。
2、下载 jmeter
为了更加方便的测试接口,这里用到了 jmeter
压力测试工具,点击这里下载压缩包。
下载完解压进入 bin 目录,双击 ApacheJMeter.jar
启动程序。
3、创建线程组
4、创建请求
5、添加结果树
6、执行并查看结果
可以成功看到第四次的请求直接被拒绝:
Sentinel 控制台同样可以看到监控:
7.2、熔断降级
7.2.1、熔断策略
Sentinel 提供以下几种熔断策略:
- 慢调用比例 (
SLOW_REQUEST_RATIO
):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。 - 异常比例 (
ERROR_RATIO
):当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是[0.0, 1.0]
,代表 0% - 100%。 - 异常数 (
ERROR_COUNT
):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(
BlockException
)不生@SentinelResource
注解会自动统计业务异常,无需手动调用。
熔断降级规则(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 引入) |
7.2.2、@SentinelResource 注解介绍
由于熔断降级功能需要借助 @ SentinelResource 实现异常处理及切换降级方法,这里粗略介绍。
@SentinelResource
用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource
注解包含以下属性:
value
:资源名称,必需项(不能为空)entryType
:entry 类型,可选项(默认为EntryType.OUT
)blockHandler
/blockHandlerClass
:blockHandler
对应处理BlockException
的函数名称,可选项。blockHandler 函数访问范围需要是public
,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException
。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定blockHandlerClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。fallback
/fallbackClass
:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要和原函数一致,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。 - fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback
(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要为空,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。 - defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore
(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
1.8.0 版本开始,defaultFallback
支持在类级别进行配置。
注:1.6.0 之前的版本 fallback 函数只针对降级异常(
DegradeException
)进行处理,不能针对业务异常进行处理。
7.2.3、测试
1、编写接口
/**
* 测试熔断降级
*
* @return
* @throws InterruptedException
*/
@RequestMapping("/fusing")
@SentinelResource(value = "testFusing", fallback = "backupHandler")
public String fusing() throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
return "sentinel access success";
}
/**
* 降级处理
*
* @return
*/
public String backupHandler() {
return "sentinel backup";
}
2、Sentinel 添加熔断降级规则
对 /fusing
接口添加熔断降级规则:请求响应时长大于 500 毫秒 的比例大于 10% 且 最小请求数达到 5 时,触发熔断,5s 内的方法都改为请求降级方法。
3、Jmeter 测试
jmeter 线程组添加10个线程,1s 内同时请求该接口,达到上述熔断规则的条件,触发熔断:
7.3、热点参数限流
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
7.3.1、热点参数规则配置
热点参数规则(ParamFlowRule
)类似于流量控制规则(FlowRule
):
属性 | 说明 | 默认值 |
---|---|---|
resource | 资源名,必填 | |
count | 限流阈值,必填 | |
grade | 限流模式 | QPS 模式 |
durationInSec | 统计窗口时间长度(单位为秒),1.6.0 版本开始支持 | 1s |
controlBehavior | 流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持 | 快速失败 |
maxQueueingTimeMs | 最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持 | 0ms |
paramIdx | 热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置 |
|
paramFlowItemList | 参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型和字符串类型 |
|
clusterMode | 是否是集群参数流控规则 | false |
clusterConfig | 集群流控相关配置 |
7.2、测试
1、编写 /test/hotParam/{number}
测试接口
/**
* 测试热点参数限流
*
* @param number
* @return
*/
@RequestMapping(value = "/hotParam")
@SentinelResource(value = "hotParam", blockHandler = "hotParamHandler")
public String hotParam(Integer number) {
return "sentinel hotParam:" + number;
}
/**
* 热点参数限流处理
*
* @param number
* @return
*/
public String hotParamHandler(Integer number, BlockException e) {
return "hotParam Exception:" + number;
}
2、Sentinel 控制台添加热点参数规则:
对传入的第 1 个参数进行限流处理:限制 1 秒 QPS 上限 为 5,当传入的第 1 个参数的值为 1时,限制其 1 秒 QPS 上限 为 5。
3、Jmeter测试
当 传入的参数值为 1 时,只有前两个请求正常:
当传入的参数为 2 时, 前面 5个请求正常:
7.4、系统规则
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN
),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则支持以下的模式:
- Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的
maxQps * minRt
估算得出。设定参考值一般是CPU cores * 2.5
。 - CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
- 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
以下是 Sentinel 控制台增加系统规则的界面:
7.5、授权规则
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的黑白名单控制的功能。黑白名单根据资源的请求来源(origin
)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
黑白名单规则(AuthorityRule
)非常简单,主要有以下配置项:
resource
:资源名,即限流规则的作用对象limitApp
:对应的黑名单/白名单,不同 origin 用,
分隔,如appA,appB
strategy
:限制模式,AUTHORITY_WHITE
为白名单模式,AUTHORITY_BLACK
为黑名单模式,默认为白名单模式。
以下是 Sentinel 控制台增加授权规则的界面:
7.6、集群流控
假设我们希望给某个用户限制调用某个 API 的总 QPS 为 50,但机器数可能很多(比如有 100 台)。这时候我们很自然地就想到,找一个 server 来专门来统计总的调用量,其它的实例都与这台 server 通信来判断是否可以调用。这就是最基础的集群流控的方式。
另外集群流控还可以解决流量不均匀导致总体限流效果不佳的问题。假设集群中有 10 台机器,我们给每台机器设置单机限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机维度去限制的话会无法精确地限制总体流量。而集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。
集群流控中共有两种身份:
- Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端结果,决定是否限流。
- Token Server:即集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)。
7.6.1、启动方式
-
独立模式(Alone),即作为独立的 token server 进程启动,独立部署,隔离性好,但是需要额外的部署操作。独立模式适合作为 Global Rate Limiter 给集群提供流控服务。
-
嵌入模式(Embedded),即作为内置的 token server 与服务在同一进程中启动。在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不佳,需要限制 token server 的总 QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。
对于开源版而言,我们可以直接在控制台当中进行相应的配置。
下图是 Sentinel 控制台 Token Server 的界面:
下图是 Sentinel 控制台 Token Client 的界面:
8、Sentinel + Nacos 动态规则扩展
8.1、DataSource 扩展介绍
Sentinel 提供两种方式修改规则:
- 通过 API 直接修改 (
loadRules
) - 通过
DataSource
适配不同数据源修改
手动修改规则(硬编码方式)一般仅用于测试和演示,生产上一般通过动态规则源的方式来动态管理规则。
DataSource
扩展常见的实现方式有:
- 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
- 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。
Sentinel 目前支持以下数据源扩展:
在这里我们使用 Nacos 作为数据源,关于 Nacos 的搭建参考文章 Spring Cloud Alibaba Nacos 入门。
8.2、引入依赖
Nacos 是阿里中间件团队开源的服务发现和动态配置中心。Sentinel 针对 Nacos 作了适配,底层可以采用 Nacos 作为规则配置数据源。使用时只需添加以下依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
8.3、添加配置
application.yml 添加以下配置:
server:
port: 9005
spring:
application:
name: test-sentinel
cloud:
nacos:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
eager: true
datasource:
# 名字随便起
ds1:
nacos:
server-addr: ${spring.cloud.nacos.server-addr}
dataId: ${spring.application.name}-flow
groupId: DEFAULT_GROUP
# 规则类型,这里是限流规则
#取值见: org.springframework.cloud.alibaba.sentinel.datasource.RuleType
rule-type: flow
8.4、nacos 添加规则配置
在 Nacos
中添加一个 DataID 为 test-sentinel-flow
的规则配置,配置信息如下:
[
{
"resource": "/test/info",
"limitApp": "default",
"grade": 1,
"count": 2,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
关于配置信息的说明:
resource
: 资源名grade
: 熔断策略,支持慢调用比例(0)/异常比例(1)/异常数策略(2)count
: 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值timeWindow
: 熔断时长,单位为 sminRequestAmount
: 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)statIntervalMs
: 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)slowRatioThreshold
: 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
以下是 Nacos
的配置截图:
8.5、启动并测试
启动 Nacos
、Sentinel
,访问接口正常:
检查 Sentinel 控制台,看是否有收到 Nacos 推送的规则信息:
到这里 Nacos
的数据源便配置完毕了。
参考资料:
- https://juejin.cn/post/7001296810102751262?searchId=20230802225018B88F03AC205A08EB8127
- https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
- https://juejin.cn/post/6844903838231576589
- https://sentinelguard.io/zh-cn/docs/quick-start.html
- https://juejin.cn/post/6890074100111425544
- https://cloud.tencent.com/developer/article/1492093
- https://juejin.cn/post/6890342340104454158#heading-2