Sentinel 进阶教程 - 中级篇(2024 年)
大纲
- Sentinel 入门教程 - 基础篇(2020 年)
- Sentinel 入门教程 - 中级篇(2020 年)
- Sentinel 入门教程 - 整合篇(2020 年)
- Sentinel 进阶教程 - 基础篇(2024 年)
- Sentinel 进阶教程 - 中级篇(2024 年)
- Sentinel 进阶教程 - 整合篇(2024 年)
前言
官方资源
版本说明
在本文的所有案例中,各个组件统一使用以下版本:
组件 | 版本 | 说明 |
---|---|---|
Spring Boot | 3.2.0 | |
Spring Cloud | 2023.0.0 | |
Spring Cloud Alibaba | 2022.0.0.0 | |
Sentinel Dashboard | 1.8.7 |
代码下载
- 本文完整的案例代码可以从 这里 下载得到。
Sentinel 注解支持
官方文档
@SentiinelResource 的概述
@SentiinelResource
是 Sentinel 官方提供的一个流量防卫防护组件注解,用于指定防护资源,对配置的资源进行流量控制、熔断降级等功能。@SentiinelResource
注解的底层源码和注释如下:
1 | @Target({ElementType.METHOD, ElementType.TYPE}) |
@SentiinelResource 的使用
默认不使用注解的行为表现
案例目标
Sentinel 使用接口的 URL 地址作为资源名进行限流 + 返回默认的限流提示。
- Java 接口代码
1 | @RestController |
- Sentinel 控制台添加流控规则
- 通过浏览器快速多次访问
/rateLimit/byUrl
接口时,会返回默认提示信息Blocked by Sentinel (flow limiting)
,说明接口被限流了。
提示
在 Sentinel 控制台添加流控规则时,资源名默认就可以是请求的接口路径(URL),可以自行修改。同一微服务应用内,资源名必须唯一。不同微服务应用之间,资源名可以重复。
使用注解自定义限流的提示
案例目标
Sentinel 按照资源名称进行限流 + 返回自定义的限流提示。
若不希望 Sentinel 使用默认的限流提示 Blocked by Sentinel (flow limiting)
,而是想返回自定义限流的提示,可以使用 @SentiinelResource
注解 的 blockHandler
属性来实现。
- Java 接口代码
1 | @RestController |
- Sentinel 控制台添加流控规则
- 通过浏览器快速多次访问
/rateLimit/byResource
接口时,会返回自定义提示信息目前访问人数较多,请稍后再试!
,说明接口被限流了。
使用注解自定义降级处理逻辑
案例目标
Sentinel 按照资源名称进行限流 + 返回自定义的限流提示 + 服务降级处理(Fallback)。
使用 Sentinel 的时候,若希望在接口调用抛出业务异常(不包括 BlockException 异常)时,执行指定的降级处理逻辑,可以使用 @SentiinelResource
注解 的 fallback
属性来实现。特别注意,这里的降级处理只是在接口调用抛出业务异常时,简单执行指定的降级处理逻辑(比如返回兜底数据),并没有实现熔断的功能。若需要使用熔断功能,可以使用 Sentinel 提供的 熔断规则。
- Java 接口代码
1 | @Slf4j |
- Sentinel 控制台添加流控规则
- 通过浏览器快速多次访问
/rateLimit/doAction/1
接口时,会返回自定义提示信息目前访问人数较多,请稍后再试!
,说明接口频繁调用时,成功被限流了。 - 通过浏览器单次访问
/rateLimit/doAction/0
接口时,会返回自定义的降级处理结果服务出错啦,请稍后再试!
,说明调用接口抛出业务异常(不包括 BlockException)时,成功被降级处理了。
使用总结
@SentinelResource
注解的blockHandler
属性,主要针对 Sentinel 配置了规则后出现的违规情况(比如触发了流控规则、熔断规则、热点规则等)进行处理。@SentinelResource
注解的fallback
属性,主要针对程序在运行时抛出了业务异常(不包括 BlockException 异常),需要进行降级处理的情况。@SentinelResource
注解的blockHandler
和fallback
属性可以共存,也就是可以互相配合使用。
Sentinel 热点规则
官方文档
热点规则
热点规则的概述
何为热点?热点即经常访问的数据。在很多时候,我们希望统计某些热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 使用商品 ID 作为参数,统计一段时间内最常购买的商品 ID,并进行限制。
- 使用用户 ID 作为参数,针对一段时间内频繁访问的用户 ID,进行限制。
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制方式,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU(最长时间未使用)策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。值得一提的是,热点参数限流支持集群模式。
LRU 算法与 LFU 算法
LRU (Least Recently Used)
:根据最近使用的顺序来淘汰数据,即淘汰最长时间未被访问的数据。LFU (Least Frequently Used)
:根据数据被访问的频率来淘汰数据,即淘汰访问频率最低的数据。
热点规则的添加
在 Sentinel 控制台里,添加热点规则的步骤如下:
热点参数规则(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 | 集群流控相关配置 |
热点规则的使用
- Java 接口代码
1 | @Slf4j |
- Sentinel 控制台添加热点规则
特别注意
在 Sentinel 控制台添加热点规则时,资源名必须是 @SentinelResource
注解的 value
属性的值,不能是接口的 URL 地址,否则热点参数限流不会生效。
- 测试案例代码
- (1) 通过浏览器快速多次访问
/testHotKey?p1=abc
接口,发现会返回自定义的限流提示信息hot key rate limit
,说明热点参数限流生效。 - (2) 通过浏览器快速多次访问
/testHotKey?p1=abc&p2=efg
接口,发现也会返回自定义的限流提示信息hot key rate limit
,说明只要请求含有指定的参数,热点参数限流都会生效。 - (3) 通过浏览器快速多次访问
/testHotKey?p2=efg
接口,发现返回的结果都是success
,说明只要请求不含有指定的参数,即使不断访问接口也不会触发热点参数限流。
- (1) 通过浏览器快速多次访问
参数例外项配置
参数例外项的概述
在上述案例中,演示了接口携带第一个参数 p1
,当 QPS 超过 1 秒 1 次时,接口马上被限流。但是,面对复杂易变的业务需求,往往会有特殊情况需要额外处理。
- 正常限流
- 接口携带第一个参数
p1
,当 QPS 达到预设阀值时立刻被限流。
- 接口携带第一个参数
- 特殊限流
- 希望当
p1
参数是某个特殊值时,QPS 到达预设阀值后热点规则突然例外(失效),它的限流阀值跟平时不一样。 - 比如:当
p1
参数的值等于 5 时,QPS 阀值可以允许达到 200 或者其他值。
- 希望当
参数例外项的使用
- Java 接口代码
1 | @Slf4j |
- Sentinel 控制台添加热点规则 + 参数例外项
- 测试案例代码
- (1) 通过浏览器快速多次访问
/testHotKey?p1=abc
接口,当 QPS 达到超过 1 秒 1 次时,发现会返回自定义的限流提示信息hot key rate limit
,说明普通的热点参数限流生效。 - (2) 通过浏览器快速多次访问
/testHotKey?p1=mnt
接口,当 QPS 达到超过 1 秒 5 次时,才会返回自定义的限流提示信息hot key rate limit
,说明参数例外项的热点参数限流生效。
- (1) 通过浏览器快速多次访问
特别注意
使用参数例外项时,参数必须是基本类型或者 String 类型。
Sentinel 授权规则
官方文档
授权规则的概述
在很多时候,往往需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 提供的授权规则(也叫黑白名单控制)来实现。授权规则根据资源的请求来源(Origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求都通过。
提示
调用方信息是通过 ContextUtil.enter(resourceName, origin)
方法中的 origin
参数传入。
授权规则的添加
在 Sentinel 控制台里,添加热点规则的步骤如下:
授权规则(AuthorityRule)非常简单,主要有以下配置项:
属性 | 说明 | 默认值 |
---|---|---|
resource | 资源名,即限流规则的作用对象。 | |
limitApp | 对应的黑名单 / 白名单,不同 origin 用 , 分隔,如 appA,appB 。 | |
strategy | 限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式。 | AUTHORITY_WHITE |
授权规则的使用
- Java 接口的代码
1 | @Slf4j |
- 自定义请求来源转换器,需要实现
RequestOriginParser
接口,目的是告知 Sentinel 从哪里获取请求来源
1 | @Component |
- Sentinel 控制台添加授权规则
- 测试案例代码
- (1) 通过浏览器访问
/empower?serverName=appC
接口,会返回正确结果success
。 - (2) 通过浏览器访问
/empower?serverName=appA
接口,发现会返回Blocked by Sentinel (flow limiting)
,说明授权规则生效了。 - (3) 通过浏览器访问
/empower?serverName=appB
接口,发现会返回Blocked by Sentinel (flow limiting)
,说明授权规则生效了。
- (1) 通过浏览器访问
Sentinel 配置规则持久化
由于 Sentinel 控制台重启后,已配置的规则就会丢失(默认存储在内存中),因此生产环境需要将配置规则持久化。比如,将流控规则持久化进 Nacos 保存后,只要 Nacos 里面的配置信息不删除,Sentinel 的流控规则就会持续有效。Sentinel 官方推荐注册动态规则源(如 Nacos 配置中心)来实现动态推送,比如 GatewayRuleManager.register2Property (property)
。Sentinel 配置规则持久化有以下几种方案:
- (1) 持久化方案一:在业务模块(包含 Sentinel 客户端)中引入
sentinel-datasource-nacos
依赖,并将 Sentinel 配置规则添加到 Nacos 配置中心。 - (2) 持久化方案二:改造 Sentinel Dashboard 项目,使其支持通过 Sentinel Dashboard 界面将流量控制配置规则存储到 Nacos。
- (3) 持久化方案三:使用 Sentinel 提供的 API 来自定义配置规则,也就是说通过代码的方式定义(写死)Sentinel 配置规则,比如
GatewayRuleManager.loadRules (rules)
,缺点是配置规则不支持实时更新。由于此方案的灵活性较差,因此使用得比较较少。
持久化方案一
方案使用介绍
- 根据 Sentinel 官方文档,当业务应用(包含 Sentinel 客户端)使用 Nacos 作为配置规则的数据源时,通常的工作流程是业务应用启动时从 Nacos 读取规则,同时 Sentinel 控制台也可以展示配置规则。如果在 Sentinel 控制台中修改了规则,默认情况下,Sentinel 控制台会将配置规则保存在自己的内存中,而不是回写到 Nacos。因此,这些修改不会持久化到 Nacos,当业务应用重启后会再次从 Nacos 读取原始配置,导致 Sentinel 控制台的配置规则修改丢失。
- 正确的做法应该是,在 Nacos 中修改配置规则,这样 Sentinel 客户端会监听 Nacos 的配置变化,自动更新本地规则,实现实时更新。同时,Sentinel 控制台也能展示最新的规则,但配置规则的修改仍需通过 Nacos 进行,以确保持久化和同步。
- 特别注意,Sentinel 与 Nacos 是否支持双向同步取决于具体的实现。有些情况下,可能通过改造代码(定制开发),让 Sentinel 控制台将修改的规则写回 Nacos 中,但这并不是默认的行为。
引入依赖坐标
在需要使用 Sentinel 进行流量控制的业务模块中,添加以下依赖:
1 | <!-- Sentinel --> |
提示
如果在业务系统中,已经使用了 Nacos 作为服务注册中心或者配置中心,则项目无需做任何改动,只需要正常引用上面的 Maven 依赖和添加下面的 YML 配置信息即可实现 Sentinel 配置规则持久化。
添加测试代码
1 | @Slf4j |
添加 YML 配置信息
特别注意
- Sentinel 网关流控规则的数据源类型是
gw-flow
,若将网关流控规则的数据源类型指定为flow
则不会生效,这定义在com.alibaba.cloud.sentinel.datasource.RuleType
枚举类中。
1 | spring: |
上面配置的 rule-type
参数的值来自 com.alibaba.cloud.sentinel.datasource.RuleType
枚举类,常用的值有以下几个:
上面配置的 datasource
可以有多个,可以理解为允许有多个不同类型的控制规则(如流量规则、熔断规则、热点规则等),如下图所示:
Nacos 添加流控规则
提示
- 这里只简单演示如何将 Sentinel 的流控规则配置信息持久化到 Nacos 中,如果是持久化熔断规则或者热点规则等其他配置信息,具体的 JSON 配置内容请自行查阅官方文档。
首先将 Sentinel 流控规则的配置信息转换为 JSON 配置内容:
1 | [ |
Sentinel 流控规则的 JSON 配置内容说明:
参数 | 说明 |
---|---|
resource | 资源名称 |
limitApp | 来源应用 |
grade | 阈值类型,0 表示并发线程数,1 表示 QPS |
count | 单机阈值 |
strategy | 流控模式,0 表示直接,1 表示关联,2 表示链路 |
controlBehavior | 流控效果,0 表示快速失败,1 表示 Warm Up,2 表示排队等待 |
clusterMode | 是否集群 |
然后将 Sentinel 流控规则的 JSON 配置内容添加到 Nacos 中:
最后在 Nacos 中 Sentinel 流控规则的配置信息如下:
案例代码测试
- (1) 启动微服务应用。
- (2) 通过浏览器访问微服务应用的
/rateLimit/byUrl
接口,等待几秒中,让 Sentinel 控制台发现微服务应用的存在。 - (3) 通过浏览器访问 Sentinel 控制台的管理页面,点击
流控规则
菜单项,即可以看到在 Nacos 中添加的流控规则配置信息(如下图所示)。如果看不到对应的配置信息,可以多刷新几次页面试试。
- (4) 通过浏览器快速多次访问
/rateLimit/byUrl
接口,当 QPS 达到超过 1 秒 1 次时,接口会返回默认提示信息Blocked by Sentinel (flow limiting)
,说明 Sentinel 的流控规则生效了。 - (5) 重启微服务应用,再次通过浏览器快速多次访问
/rateLimit/byUrl
接口,当 QPS 达到超过 1 秒 1 次时,接口仍然会被限流。
持久化方案二
方案介绍
在企业级生产环境中,往往需要改造 Sentinel Dashboard 项目,使其支持通过 Sentinel Dashboard 界面将流量控制配置规则存储到 Nacos,改造步骤可以参考以下教程:
- 基于 Sentinel 1.8.6,实现限流规则双向持久化到 Nacos
- Sentinel Dashboard 改造支持规则配置持久化至 Nacos
- Sentinel Dashboard 改造实现规则持久化到 Nacos
- Sentinel Dashboard 中修改规则同步到 Nacos
值得一提的是,还可以直接使用 Dante Cloud 改造后发布的 Sentinel Dashboard 镜像,它基于最新版的 Spring Cloud Alibaba Sentinel Dashboard 扩展改造而来,支持微服务流量监控数据持久化存储到 Influxdb 时序数据库,还支持通过 Sentinel Dashboard 界面将流量控制配置规则存储到 Nacos 中。Dante Cloud 改造后发布的 Sentinel Dashboard 镜像,时序数据存储支持 Influxdb 1.x
版本,Nacos 目前仅支持 2.x
版本。默认使用 Sentinel Dashboard 原有内存方式存储,可通过配置参数动态开启或者关闭 Influxdb 和 Nacos 存储机制。
预览: