Spring Cloud Alibaba Sentinel 用法

Spring Cloud Alibaba Sentinel 用法

1、服务器雪崩

在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。 由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩效应” 。

服务器一步步雪崩的流程如下:

1

2、常见解决方案

要防止雪崩的扩散,我们就要做好服务的容错,容错说白了就是保护自己不被猪队友拖垮的一些措施, 下面介绍常见的服务容错思路和组件。

常见的容错思路有隔离、超时、限流、熔断、降级这几种。

2.1、隔离

比如服务 A 内总共有100个线程, 现在服务A可能会调用服务 B,服务 C,服务 D.我们在服务A进行远程调用的时候,给不同的服务分配固定的线程,不会把所有线程都分配给某个微服务. 比如调用服务 B 分配30个线程,调用服务 C 分配30个线程,调用服务 D 分配40个线程. 这样进行资源的隔离,保证即使下游某个服务挂了,也不至于把服务 A 的线程消耗完。比如服务 B 挂了,这时候最多只会占用服务 A 的30个线程,服务 A 还有70个线程可以调用服务 C 和服务 D。

隔离的流程如下图:

1

2.2、超时

在上游服务调用下游服务的时候,设置一个最大响应时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程。

2

2.3、限流

限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。

3

2.4、熔断

当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。

服务熔断一般有三种状态:

  1. 熔断关闭状态(Closed):服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。
  2. 熔断开启状态(Open):后续对该服务接口的调用不再经过网络,直接执行本地的 fallback 方法。
  3. 半熔断状态(Half-Open):尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断关闭状态。
4

2.5、降级

降级也就是服务降级,当我们的服务器压力剧增为了保证核心功能的可用性 ,而选择性的降低一些功能的可用性,或者直接关闭该功能。这就是典型的丢车保帅了。 就比如贴吧类型的网站,当服务器吃不消的时候,可以选择把发帖功能关闭,注册功能关闭,改密码,改头像这些都关了,为了确保登录和浏览帖子这种核心的功能。

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 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:

arch

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

熔断降级
什么是熔断降级

除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。

image
熔断降级设计理念

在限制的手段上,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, 输入用户名密码登录后界面如下:

image-20230809170125300

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 控制台与微服务的通信流程如下图:

1

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

image-20230810001654152

既然接口正常访问,那么接下来就是查看控制台是否有显示该接口了。

image-20230810002031107

然后我们可以在 Sentinel 控制台当中对限流、熔断、热点参数、授权等进行细粒度的配置。一个很好的原则是:约定>配置>编码。

6、Sentinel 工作主流程

在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)。这些插槽有不同的职责,例如:

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

总体的框架如下:

arch overview

Sentinel 将 ProcessorSlot 作为 SPI 接口进行扩展(1.7.2 版本以前 SlotChainBuilder 作为 SPI),使得 Slot Chain 具备了扩展的能力。您可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。

Slot Chain SPI

7、Sentinel 规则配置

7.1、流量控制

流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。同一个资源可以创建多条限流规则。

一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:

  • resource:资源名,即限流规则的作用对象
  • count: 限流阈值
  • grade: 限流阈值类型(QPS 或并发线程数)
  • limitApp: 流控针对的调用来源,若为 default 则不区分调用来源
  • strategy: 调用关系限流策略
  • controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)

流量控制主要有两种统计类型,一种是统计并发线程数,另外一种则是统计 QPS。类型由 FlowRulegrade 字段来定义。其中,0 代表根据并发数量来限流,1 代表根据 QPS 来进行流量控制。其中线程数、QPS 值,都是由 StatisticSlot 实时统计获取的。

7.1.1、并发线程数控制

并发数控制用于保护业务线程池不被慢调用耗尽。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。

7.1.2、QPS流量控制

当 QPS 超过某个阈值的时候,则采取措施进行流量控制。流量控制的效果包括以下几种:直接拒绝Warm Up匀速排队

  1. 直接拒绝:是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException

  2. Warm Up:即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。详细文档可以参考 流量控制 - Warm Up 文档

    image
  3. 匀速排队:严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考 流量控制 - 匀速器模式

image
7.1.3、针对来源(调用方)的流控配置
  • default:表示不区分调用者,来自任何调用者的请求都将进行限流统计。如果这个资源名的调用总和超过了这条规则定义的阈值,则触发限流。
  • {some_origin_name}:表示针对特定的调用者,只有来自这个调用者的请求才会进行流量控制。例如 NodeA 配置了一条针对调用者caller1的规则,那么当且仅当来自 caller1NodeA 的请求才会触发流量控制。
  • other:表示针对除 {some_origin_name} 以外的其余调用方的流量进行流量控制。例如,资源NodeA配置了一条针对调用者 caller1 的限流规则,同时又配置了一条调用者为 other 的规则,那么任意来自非 caller1NodeA 的调用,都不能超过 other 这条规则定义的阈值。

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

注意:调用来源的数目不要太多(一般不要超过几百个),否则内存占用会非常多(调用来源的统计节点最大数目=资源数目*来源数目)。

7.1.4、流控模式配置
  • 直接:针对资源本身,接口达到限流条件时,直接限流。
  • 链路:Sentinel 允许只根据某个入口的统计信息对资源限流。比如存在不同的调用链路A、B,我们设置从节点a(a是调用链路A当中的一个节点)过来的调用,将被记录到统计信息当中,那么调用链路B上过来的调用将不被记录到统计信息当中。
  • 关联:当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_dbwrite_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的。
7.1.5、测试

1、Sentinel 控制台添加流控规则

在这里给接口 /test/info 添加最简单的限流规则: 1 秒的 QPS 阈值为 3,超过则拒绝新的请求。

image-20230810223053015

2、下载 jmeter

为了更加方便的测试接口,这里用到了 jmeter压力测试工具,点击这里下载压缩包

下载完解压进入 bin 目录,双击 ApacheJMeter.jar 启动程序。

image-20230810221448894

3、创建线程组

image-20230810233924526

4、创建请求

image-20230810234107888

5、添加结果树

image-20230810234313097

6、执行并查看结果

可以成功看到第四次的请求直接被拒绝:

image-20230810234655243

Sentinel 控制台同样可以看到监控:

image-20230810235132869

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 内的方法都改为请求降级方法。

image-20230811141418434

3、Jmeter 测试

jmeter 线程组添加10个线程,1s 内同时请求该接口,达到上述熔断规则的条件,触发熔断:

image-20230811143705662

7.3、热点参数限流

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

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

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

Sentinel Parameter Flow Control

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。

image-20230811172134089

3、Jmeter测试

当 传入的参数值为 1 时,只有前两个请求正常:

image-20230811172734719

当传入的参数为 2 时, 前面 5个请求正常:

image-20230811172941884

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 控制台增加系统规则的界面:

image-20230811173902135

7.5、授权规则

很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的黑白名单控制的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

黑白名单规则(AuthorityRule)非常简单,主要有以下配置项:

  • resource:资源名,即限流规则的作用对象
  • limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB
  • strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式。

以下是 Sentinel 控制台增加授权规则的界面:

image-20230811182141067

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 给集群提供流控服务。

    image

  • 嵌入模式(Embedded),即作为内置的 token server 与服务在同一进程中启动。在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不佳,需要限制 token server 的总 QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。

    image

对于开源版而言,我们可以直接在控制台当中进行相应的配置。

下图是 Sentinel 控制台 Token Server 的界面:

image-20230811182402419

下图是 Sentinel 控制台 Token Client 的界面:

image-20230811182502300

8、Sentinel + Nacos 动态规则扩展

8.1、DataSource 扩展介绍

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

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

手动修改规则(硬编码方式)一般仅用于测试和演示,生产上一般通过动态规则源的方式来动态管理规则。

DataSource 扩展常见的实现方式有:

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

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: 熔断时长,单位为 s
  • minRequestAmount: 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)
  • statIntervalMs: 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)
  • slowRatioThreshold: 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

以下是 Nacos的配置截图:

image-20230811214938752

8.5、启动并测试

启动 NacosSentinel,访问接口正常:

image-20230811215548282

检查 Sentinel 控制台,看是否有收到 Nacos 推送的规则信息:

e

到这里 Nacos的数据源便配置完毕了。

参考资料:

posted @ 2023-08-11 22:11  MyDistance  阅读(270)  评论(0编辑  收藏  举报