Sentinel 服务保护
# Sentinel 服务保护
简介
- 阿里 Sentinel (opens new window),相比 Nginx 更加细粒度
- 流量控制、隔离降级、授权规则、规则持久化
# 一、基础与安装
# 1. Sentinel 简介
Sentinel 是由阿里巴巴开源的一个专门用来解决微服务架构中流量控制问题的工具。想象一下,当你在高峰时段上网,流量猛增时,网络突然变慢甚至瘫痪。Sentinel 的作用就是帮助系统应对这种流量激增的情况,防止服务崩溃。它通过多种手段来保护系统,包括流量控制、熔断(让出问题的部分暂时“休息”)、降级处理等,确保你的服务能够平稳运行。
你可以将 Sentinel 想象为一名负责交通的“调度员”,时刻监控着系统的流量情况,并在必要时刻对流量进行控制和疏导,避免系统被过量的请求压垮。
# 2. 什么是雪崩问题?如何解决?
“雪崩问题”可以简单理解为,当一个微服务出错时,它就像雪崩一样,可能连锁反应导致整个系统崩溃。举个例子:想象你在登山时,一个小雪团开始滑动,最后引发了一场巨大的雪崩,毁掉了整座山。微服务架构中,当某个服务失效时,其他依赖这个服务的模块也可能跟着失效,形成雪崩效应。
# 如何解决?
故障后的纠错措施:当服务出错后,系统可以通过以下方式进行“止损”:
- 超时处理:当服务没有及时响应时,系统自动中断该服务。
- 线程隔离:将出问题的服务隔离开,避免影响其他服务。
- 熔断降级:当一个服务多次失败时,暂停对该服务的调用,待其恢复后再重新接入。
故障前的预防措施:为了防止故障发生,可以通过流量控制工具(例如 Sentinel)来限制进入系统的请求数量,确保系统不会被突如其来的流量冲垮。
# 3. 常见服务保护技术对比
技术 | 功能 | 适用场景 |
---|---|---|
限流 | 控制请求流量 | 当系统面对突发流量时,比如双十一秒杀活动。 |
熔断 | 防止服务雪崩 | 当某个服务出现故障时,避免故障扩散到其他服务。 |
降级 | 降低服务质量 | 在系统负载过高的情况下,降低一些非核心功能的优先级,比如延迟部分不重要的服务请求。 |
就像《冰与火之歌》里提到的:“风暴来临时,狼群最强的狼会守护其他狼。” 这些技术正是守护系统的“狼”,当风暴(流量高峰或故障)来袭时,它们可以保护系统不至于被彻底击垮。
1. 隔离策略
- Sentinel:使用信号量隔离,即通过控制信号量(类似于同时允许的最大并发请求数),防止服务过载,确保系统稳定。
- Hystrix:可以选择线程池隔离或信号量隔离。线程池隔离会为每个服务请求创建独立的线程,从而避免某个服务请求长时间占用资源。
2. 熔断降级策略
- Sentinel:基于慢调用比例或异常比例进行熔断。当服务响应过慢或者错误率达到设定阈值时,Sentinel 会触发熔断,阻止请求继续流入不稳定的服务,保护系统。
- Hystrix:基于失败比率进行熔断。如果服务失败率超过设定值,就会触发熔断机制。
3. 实时指标实现
- Sentinel:采用滑动窗口来统计实时指标,帮助准确地了解服务的健康状况。滑动窗口可以持续更新过去一段时间内的统计数据。
- Hystrix:同样使用滑动窗口(基于 RxJava 的实现),用于追踪请求的成功率、失败率等指标。
4. 规则配置
- Sentinel:支持多种数据源,允许通过不同方式配置规则,比如文件、数据库、甚至通过配置中心。开发者可以灵活选择适合的方式来配置和管理流控规则。
- Hystrix:规则配置相对简单,通常是通过插件的形式进行配置。
5. 扩展性
- Sentinel:具有多个扩展点,开发者可以自定义扩展 Sentinel,满足特定业务需求。
- Hystrix:提供扩展能力,但以插件的形式提供,扩展方式没有 Sentinel 灵活。
6. 基于注解的支持
- Sentinel:提供良好的注解支持,可以通过简单的注解方式,快速实现限流和熔断功能,开发体验更好。
- Hystrix:也支持注解,但在灵活性和便利性上略逊于 Sentinel。
7. 限流功能
- Sentinel:可以基于 QPS(每秒请求数)进行限流,同时支持根据服务之间的调用关系进行限流。比如,当某个服务被过多访问时,可以限制它的调用,保护其他服务。
- Hystrix:不支持限流,仅提供熔断功能,无法像 Sentinel 那样细粒度地控制流量。
8. 流量整形
- Sentinel:支持流量整形功能,可以实现慢启动,即在系统启动时缓慢增加流量,防止突然涌入的大量请求导致系统崩溃。还支持匀速排队模式,在流量高峰期平滑处理请求。
- Hystrix:不支持流量整形,没有相关功能。
9. 系统自适应保护
- Sentinel:具备系统保护功能,根据系统的负载和性能动态调整流量策略,避免系统崩溃。
- Hystrix:不支持系统自适应保护,只能基于固定的熔断策略进行处理。
10. 控制台
- Sentinel:提供开箱即用的控制台,可以对流量进行实时监控和管理,支持秒级监控、查看规则、以及自动发现机器等功能,便于用户进行系统调优。
- Hystrix:控制台功能不完善,仅提供简单的监控功能,无法像 Sentinel 一样具备丰富的管理能力。
11. 常见框架的适配
- Sentinel:支持多种框架,如 Servlet、Spring Cloud、Dubbo、gRPC 等,适配性广泛。
- Hystrix:支持 Servlet 和 Spring Cloud Netflix,适配范围相对较窄。
小结
- Sentinel 更适合需要灵活流控、丰富功能扩展,并希望有强大实时监控能力的系统。
- Hystrix 虽然成熟,但功能相比 Sentinel 更加单一,扩展性和监控功能较弱,更适合简单熔断需求的场景。
# 4. 基本概念
资源:在 Sentinel 中,资源是它监控的对象,几乎可以是系统中的任何代码片段。比如某个 API、一个数据库查询、或者外部服务调用。资源是通过 Sentinel API 来进行标记和监控的。举个例子,当你访问某个电商网站时,商品详情页面的 API 就是一个资源,Sentinel 会对它进行监控,防止它被过量请求压垮。
规则:Sentinel 允许开发者为每个资源设定一系列规则。比如为某个 API 设置一个访问上限,或者为某个服务设定熔断策略。当这些规则触发时,Sentinel 会根据规则采取行动,以保障系统稳定。
# 5. 流控降级与容错标准
流控降级与容错的核心在于三部分:
Rule = 目标 + 策略 + 降级后的动作
每个规则包含:
- 控制的目标(比如哪个 API 或服务)
- 使用的策略(限流、熔断、降级等)
- 降级后的处理动作(可以是简单的拒绝请求,也可以是返回一个默认值)
这就像一个足球队在比赛时,如果主力球员受伤,教练可以立刻替换球员,保证比赛继续进行。
# 6. Sentinel 的核心功能
Sentinel 提供了一套完整的流量控制和故障处理机制,主要包括以下几项功能:
- 流量控制:通过设定请求上限,确保系统不会被过量请求压垮。比如电商大促时,防止某个商品页面因过多访问而宕机。
- 熔断降级:当某个服务变得不稳定时,Sentinel 可以暂时停止调用它,等待它恢复后再重新接入。就像“熔断器”一样,防止系统进一步恶化。
- 热点参数限流:对于特定的热点参数进行限流。比如限制某个特定商品 ID 在短时间内的查询次数,避免某个商品被过度访问。
- 系统保护:根据系统的整体负载情况,动态调整流量策略,防止系统在高峰时崩溃。
总结起来,Sentinel 就像是微服务架构中的“安全气囊”,在平时你可能察觉不到它的存在,但在关键时刻,它会在后台悄悄保护你的系统,确保其稳定运行。
# 7. Sentinel 安装步骤
Sentinel 提供了一个控制台应用,专门用于集中管理和监控微服务的流量控制规则。以下是安装和启动 Sentinel 控制台的详细步骤。
# 1. 下载 Sentinel 控制台
首先,前往 GitHub Sentinel Releases (opens new window) 页面,找到最新版本的 Sentinel 控制台,下载其 jar 包。这个 jar 包是一个 Spring Boot 应用程序,下载后可以直接运行。
# 2. 启动 Sentinel 控制台
下载完成后,通过命令行启动控制台。启动时可以指定控制台的端口号以及登录的用户名和密码。以下是启动命令的示例:
java -Dserver.port=8090 \
-Dsentinel.dashboard.auth.username=sentinel \
-Dsentinel.dashboard.auth.password=123456 \
-jar sentinel-dashboard-1.8.6.jar
2
3
4
命令说明:
-Dserver.port=8090
:指定控制台的端口为 8090(默认端口是 8080)。-Dsentinel.dashboard.auth.username=sentinel
和-Dsentinel.dashboard.auth.password=123456
:设置控制台的用户名和密码。-jar sentinel-dashboard-1.8.6.jar
:这是你下载的 Sentinel 控制台的 jar 文件。
注意:这里设置的端口和用户名、密码是为了访问控制台时使用的,不是用于控制微服务之间通信的。
# 3. 访问 Sentinel 控制台
成功启动控制台后,打开浏览器,输入地址 http://localhost:8090
,使用你在启动命令中设置的用户名 sentinel
和密码 123456
登录。此时你应该可以看到 Sentinel 的管理界面。
# 8. 在项目中集成 Sentinel
要在微服务项目中使用 Sentinel,需要将它的依赖库引入项目,并配置与控制台的通信地址。以下是具体的步骤。
# 1. 引入 Sentinel 依赖
在你的项目中(比如 Spring Boot 项目),你需要在 pom.xml
文件中添加 Sentinel 相关的依赖。这个依赖将 Sentinel 与 Spring Cloud 整合,帮助你实现流量控制和熔断降级功能。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2
3
4
# 2. 配置 Sentinel 控制台地址
接下来,你需要在 application.yml
配置文件中,设置 Sentinel 控制台的地址。这样你的微服务可以与控制台进行通信,并允许你通过控制台动态管理流量控制规则。
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090 # 这里填写控制台的地址
2
3
4
5
配置说明:
dashboard: localhost:8090
:这个地址是你在本地启动的 Sentinel 控制台的地址。如果控制台运行在远程服务器上,这里需要填写该服务器的 IP 和端口。
# 3. 启动微服务
一旦完成以上配置,启动你的微服务。在启动后,访问一次服务的 API(例如调用一个 Controller),这时 Sentinel 会开始对该服务进行监控,并将流量信息发送到控制台。
总结
通过简单的几个步骤,你就可以在你的微服务项目中集成 Sentinel:
- 下载并启动 Sentinel 控制台:下载 jar 文件,使用命令行启动控制台,设置好端口号和登录的用户名、密码。
- 引入 Sentinel 依赖:在项目中添加 Sentinel 的 Maven 依赖,集成 Spring Cloud。
- 配置与控制台的通信地址:在
application.yml
文件中配置 Sentinel 控制台地址,确保服务与控制台能通信。 - 启动服务并管理规则:访问你的服务后,Sentinel 就会开始监控服务,并通过控制台管理流量控制规则。
这样,你就能通过 Sentinel 控制台实时监控和管理你的微服务系统,确保系统的稳定性和可靠性。
# 二、簇点链路
# 1. 什么是簇点链路?
簇点链路可以理解为项目中的服务调用链路,每个被监控的接口都称为一个资源。在项目中,每个接口或方法都可以被视为一条链路上的一个节点,而 Sentinel 的作用就是监控这些节点,帮助我们对服务的调用流量进行管理。
默认情况下,Sentinel 会自动监控 Spring MVC 中每个端点(例如在 Controller
中的方法)。这些端点会被视为系统中的“资源”,在调用时可以执行以下 4 种关键操作:
- 流控:限制请求流量,防止系统被突发的大量请求压垮。
- 降级:熔断和降级处理,确保在高并发或异常情况下系统仍能稳定运行。
- 热点限流:对某些常用或热门的参数(如某商品 ID)进行限流,避免单一热点资源被过度访问。
- 授权:管理访问权限,控制不同用户或服务对资源的访问权限。
# 2. 注意事项
默认情况下,Sentinel 只会监控 Controller
层的方法,也就是项目中的 HTTP 请求端点。如果你想监控其他层次的方法(例如 Service
层的业务逻辑),需要进行额外配置。
# 1. 关闭 Sentinel 的上下文整合模式
Sentinel 默认会把所有 Controller
层的方法整合成一条统一的调用链,这种模式适合简单的场景。如果想要对 Service
层的方法进行更细致的监控,就需要关闭这种默认的整合模式,允许 Sentinel 监控每个方法形成独立的调用链。
可以在 application.yml
文件中通过以下配置来关闭上下文整合模式:
spring:
cloud:
sentinel:
web-context-unify: false # 关闭上下文整合模式,允许多链条监控
2
3
4
解释:
web-context-unify: false
:关闭这个整合模式后,Sentinel 将会对每个方法形成独立的调用链,从而实现更精细化的监控。
# 2. 使用 @SentinelResource
注解标记资源
如果想要监控 Service
层或者其他非 Controller
层的方法,需要通过 @SentinelResource
注解来手动标记这些方法为资源。
以下是一个 Service
层方法的示例:
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;
@Service
public class GoodsService {
@SentinelResource("queryGoods") // 将该方法标记为资源,资源名称为 "queryGoods"
public void queryGoods() {
// 模拟商品查询业务逻辑
System.out.println("查询商品信息");
}
}
2
3
4
5
6
7
8
9
10
11
12
解释:
@SentinelResource("queryGoods")
:通过这个注解将queryGoods
方法标记为 Sentinel 资源,方便在控制台中监控和管理。
# 3. 在 Sentinel 控制台查看监控结果
配置完成并启动项目后,Sentinel 会开始监控被标记的资源。你可以在 Sentinel 控制台中查看所有被监控资源的流控、降级、热点参数和授权等操作信息。
一旦某个资源被监控,你可以在控制台中为它设置流控、降级等规则,确保系统在高流量或故障情况下仍然能够稳定运行。
总结
通过监控项目中的簇点链路,Sentinel 可以帮助你更加细粒度地管理服务调用链中的每个资源。在默认情况下,Sentinel 只监控 Controller
层的端点。如果你希望对 Service
层的方法进行监控,可以通过以下步骤实现:
- 关闭默认的上下文整合模式,允许多个独立的链路进行监控。
- 使用
@SentinelResource
注解手动标记需要监控的方法。
通过这些配置,开发者可以更加灵活地设置流控、降级等保护规则,从而提升系统的稳定性。
# 三、流控模式
# 1. Sentinel 提供的 3 种限流模式
Sentinel 通过三种主要的限流模式来控制资源的访问,以确保系统不会因为流量过大而崩溃。
# 1.1 直接限流(默认模式)
在 直接限流 模式下,Sentinel 只监控当前资源的请求数。如果请求量超过了你设定的阈值,Sentinel 会立即限制这个资源的访问,确保不会有更多请求进入。简单来说,Sentinel 在监控到某个接口被访问的次数过多时,直接进行限流。
# 1.2 关联限流
关联限流 是一种更高级的限流方式。它会监控另一个资源的访问情况,并根据这个资源的访问量来决定是否限流当前资源。比如,当接口 a
的请求量达到阈值时,你可以设置让接口 b
被限流。这样可以保护系统中的关键资源,优先保证重要接口的运行。
例如:
- 端点
a
和端点b
是两个不同的接口,当a
的请求量过多时,你可以设置b
的访问受a
的影响。当a
被访问过多时,b
会自动被限流。
# 1.3 链路限流
链路限流 是针对特定的调用路径进行限流。假设你有多个服务调用同一个资源(例如 Service C
),你可以针对不同的调用链路进行限流。例如,Controller A
和 Controller B
都调用 Service C
,你可以设置只对从 Controller A
调用 Service C
的请求进行限流,而不影响 Controller B
对 Service C
的调用。通过这种方式,可以更加精准地控制不同调用路径上的流量。
# 1.4 流控模式图示
以下是不同流控模式的图示,帮助你理解它们如何作用于系统中的资源:
# 2. 关联限流配置
在实际应用中,关联限流可以帮助你优先保护重要的资源。当关联资源的请求达到设定的阈值时,其他资源将被限流。例如,你可以配置当 update
接口的请求量过多时,限制 query
接口的请求,这样 update
作为更重要的接口会优先被保障。
配置步骤:
- 选择需要关联限流的资源。
- 配置关联的资源名称,即哪个资源会影响当前资源的限流。
- 设置触发关联限流的阈值,例如关联资源的访问量达到多少时开始限流。
- 配置被限流资源的返回策略,比如当限流发生时,抛出异常或返回默认数据。
# 3. 链路限流配置
链路限流用于对不同的调用路径进行限流管理。它适合那些调用链比较复杂的场景,比如你想对某些特定调用路径的流量进行限制,而不影响其他路径的流量。
链路限流配置说明:
- 可以指定某个特定的调用链来限流,比如你可以限制某个请求从
A
到C
的访问量,而不限制B
到C
的访问。 - 当链路的请求量达到设定的阈值时,Sentinel 会对该链路上的请求进行限流。
当链路限流触发时,系统会返回一个错误信息或默认数据,避免请求过多时系统崩溃。
# 4. 代码配置示例
除了在 Sentinel 控制台中配置流控规则,你也可以通过代码灵活地实现流控管理。下面是一个通过代码配置关联限流和链路限流的示例:
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;
@Service
public class TestService {
@SentinelResource(value = "testResource", blockHandler = "handleBlock")
public void testMethod() {
try (Entry entry = SphU.entry("testResource")) {
// 模拟业务逻辑
System.out.println("执行业务逻辑");
} catch (BlockException ex) {
// 处理被限流后的逻辑
System.err.println("限流发生:" + ex.getMessage());
}
}
// 限流处理逻辑
public void handleBlock(BlockException ex) {
System.out.println("资源被限流:" + ex.getMessage());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
代码说明:
- 通过
@SentinelResource
注解来标记某个方法为资源,并指定一个blockHandler
方法来处理限流后的情况。 - 在方法内部,使用
SphU.entry("testResource")
进入资源监控,如果请求量超过阈值,Sentinel 会抛出BlockException
,并触发handleBlock
方法进行限流处理。
总结
- Sentinel 提供了三种流控模式:直接限流、关联限流 和 链路限流,可以根据不同的业务需求选择合适的限流方式。
- 通过关联限流,你可以优先保护重要资源;通过链路限流,可以对复杂调用链进行精细化的流量控制。
- 流控规则可以通过 Sentinel 控制台进行配置,也可以通过代码灵活实现。
Sentinel 的这些流控功能帮助我们在高并发环境下保持系统的稳定性,防止资源被过度使用导致系统崩溃。
# 四、流控效果
在流控过程中,Sentinel 提供了三种不同的流控效果,用来处理系统的流量压力。每种流控效果适用于不同的业务场景,帮助系统在高并发情况下保持稳定性。
# 1. 快速失败(默认效果)
- 描述:快速失败 是 Sentinel 的默认流控效果。它的工作原理类似于漏桶算法,当请求的 QPS(每秒查询数)超过你设定的阈值时,系统会立即拒绝新的请求,返回错误信息。也就是说,超过阈值的请求会被快速丢弃,不会排队或等待。
- 适用场景:这种流控方式适合对响应时间敏感的场景。例如,当系统负载过高时,不需要处理过多的请求,可以直接拒绝并迅速返回错误信息,防止系统进一步被拖垮。
简要理解:当系统检测到请求过多时,直接“拦住”一部分请求,避免系统过载。比如在秒杀活动中,如果访问量过大,系统可以快速拒绝一些请求,避免服务器崩溃。
# 2. Warm Up(预热)
- 描述:Warm Up(预热)机制适用于系统刚启动的时候,防止突发流量过早涌入导致系统崩溃。它会逐步提高 QPS 阈值,开始时请求量限制在设定阈值的 1/3,随着时间的推移逐渐升高,直到达到设定的最大阈值。这有助于让服务在冷启动时有一个“预热”阶段,避免突然的流量冲击。
- 适用场景:这种流控效果适用于那些刚启动的服务,或者刚恢复的服务,这些服务可能在启动初期没有能力承受大量的流量,需要逐渐增加请求量。常见场景如新服务上线,或者宕机恢复后的系统。
简要理解:服务刚上线时不堪重负,预热模式就像缓慢加速的汽车,一开始控制流量较少,随着时间逐步放宽请求限制。
# 3. 排队等待
- 描述:排队等待 是基于令牌桶算法的一种流控效果,它允许请求进入一个队列,然后按照设定的 QPS 限制一个一个处理请求。对于超过阈值的请求,系统不会立即拒绝,而是让这些请求排队。如果等待时间超过设定的超时时间,系统才会拒绝该请求。
- 适用场景:适用于需要平稳处理流量的场景,例如你希望控制请求处理的节奏,而不是在流量高峰时直接拒绝请求。这样可以保证系统不会被突发流量压垮,同时尽可能多地处理请求。
简要理解:当请求量超过限度时,不直接拒绝,而是让请求排队处理,像排队买票一样,控制请求的处理速度。如果等待时间太长,才会拒绝。
# 五、热点参数限流
# 1. 什么是热点参数限流?
热点参数限流 是 Sentinel 提供的一种更细粒度的流量控制方式,它针对接口请求中具体的参数进行统计和限流,而不仅仅是针对整个接口的流量进行限制。想象一下,一个接口可能会接受不同的参数,有些参数的请求次数特别多,造成了压力。热点参数限流就是为了应对这种情况,针对这些“热点”参数进行限流。
例如:对于一个查询商品详情的接口,不同商品 ID 的请求量可能差别很大。某些热门商品(例如特定 ID)可能会受到很多用户的访问,这时你可以为这些特定参数设定限流,防止系统因为某个参数被过度请求而崩溃。
# 2. 配置热点参数限流
在 Sentinel 中,配置热点参数限流非常灵活。你可以为每个接口的不同参数配置独立的限流规则。如下图所示,你可以指定不同参数的限流策略,针对不同的参数值进行控制。
# 3. 注意事项
- 热点参数限流只能在标记了
@SentinelResource
的资源上生效。也就是说,只有当你使用@SentinelResource
注解标记了某个接口,Sentinel 才能对其进行热点参数的限流。如果你仅仅使用 Spring MVC 的控制器方法而没有用注解标记,热点限流规则是不会生效的。
# 4. 代码示例
假设你有一个 /hot
接口用于获取“热门榜单”数据,我们可以通过 @SentinelResource
注解来标记这个接口为热点资源:
@RestController
public class HotParamController {
/**
* 热点限流示例接口
* @return 热门榜单数据
*/
@SentinelResource("hot") // 标记该接口为热点资源
@GetMapping("/hot")
public String hot() {
return "hot榜单";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
说明:通过 @SentinelResource("hot")
注解,我们告诉 Sentinel 该方法是一个受保护的资源,允许对其参数进行热点限流。
# 5. 配置示例
在实际配置中,你可以指定对 /hot
资源的第一个参数(0 号参数)进行限流,比如限制其每秒只能接受 5 次请求。如下图所示:
此外,你还可以为特定的参数值设置“例外阈值”。比如在上图中,我们为参数值 101
设置了更高的限流阈值:每秒允许 10 次请求。这意味着,当用户请求的参数值为 101
时,限流阈值会更高,而其他参数则仍遵循默认的限制。
# 6. 关键点
- 0 号参数:代表请求的第一个参数。比如在请求 URL
/hot?id=101
中,id=101
就是 0 号参数。 - 例外配置:你可以为特定的参数值设置例外的限流规则,确保这些参数有不同的限流策略。例如,在上图中,参数值
101
被允许的请求次数比其他参数更多。
总结
- 热点参数限流 允许你为接口中的具体参数设置限流规则,从而实现更加精准的流量控制。特别适用于一些接口的参数请求量分布不均的场景。
- 通过配置“例外阈值”,你可以优先处理某些重要的请求,确保系统在高负载情况下仍能保证关键业务的流畅运行。
- 要使用热点限流,务必为接口使用
@SentinelResource
进行标记,这样 Sentinel 才能生效。
热点参数限流是一个强大的工具,它可以帮助你在流量高峰时保持系统的稳定,同时保护重要资源不被过度请求。
# 六、授权规则
# 1. 什么是授权规则?
授权规则 是 Sentinel 中用于控制微服务访问权限的规则。通过设置黑名单或白名单,可以决定哪些请求可以访问服务,哪些请求会被拒绝。授权规则的常见应用场景包括:
- 服务鉴权:例如,一个微服务只允许网关访问,而不希望外部用户直接访问,这时可以通过设置白名单来控制。
- 请求头验证:在微服务之间的调用中,通过网关传递特定的请求头,并在微服务中验证这个请求头是否符合授权规则。只有符合规则的请求才能继续访问服务。
# 2. 实现步骤
# 步骤 1:配置请求解析类
在微服务中,首先需要创建一个自定义的 RequestOriginParser
类,用来解析每个请求的来源。这个类负责检查请求头中的特定信息(比如某个自定义的字段),然后根据这些信息判断请求是否被允许访问。
下面是一个 RequestOriginParser
的示例代码,它会从请求头中获取名为 cipher
的参数,作为判断请求来源的依据:
package com.example.security;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* 自定义请求解析类,解析请求的来源
*/
@Component
public class HeaderOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// 从请求头中解析 "cipher" 参数
String cipher = request.getHeader("cipher");
// 如果请求头中没有 "cipher" 参数,返回 "blank"
if (StringUtils.isEmpty(cipher)) {
return "blank"; // 表示该请求无效
}
return cipher; // 返回请求来源的识别码
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
说明:这个类会解析每个请求的 cipher
参数。如果请求头中没有携带 cipher
参数,解析器会返回 "blank"
,表明该请求没有被授权。
# 步骤 2:在 Sentinel 控制台中设置授权规则
登录到 Sentinel 控制台,选择目标微服务,在授权规则中进行以下设置:
- 设置请求头的参数名称,例如将
cipher
设置为一个特定值,如myPassword
。 - 指定允许的请求来源,即只有符合该参数值的请求才能通过验证。
# 步骤 3:在网关中配置请求头
在网关中配置一个自动添加请求头的规则,让所有通过网关的请求都附加上特定的请求头。这样,只有通过网关的请求才能携带正确的请求头,从而通过微服务的授权检查。
在 application.yml
文件中为网关添加以下配置:
spring:
cloud:
gateway:
default-filters:
# 每次通过网关发送请求时,自动添加一个名为 "cipher" 的请求头,值为 "myPassword"
- AddRequestHeader=cipher,myPassword
2
3
4
5
6
说明:这条配置让网关在转发请求时,自动加上 cipher=myPassword
的请求头信息。
# 3. 实现效果
通过以上配置,可以实现以下访问控制效果:
直接访问微服务(未经过网关):
如果直接通过微服务的端口进行访问,因请求中没有携带正确的
cipher
请求头,Sentinel 会拒绝这个请求,返回未授权的错误信息。http://localhost:8088/order/101
1通过网关访问微服务:
当通过网关访问时,由于网关配置了自动添加
cipher
请求头的规则,请求将携带正确的cipher=myPassword
值,能够顺利通过授权规则,访问微服务。http://localhost:10010/order/101?authorization=admin
1
# 4. 总结
授权规则可以帮助你有效地控制微服务的访问权限,防止未经授权的请求访问服务。通过在网关中配置自动添加的请求头,结合 RequestOriginParser
的解析功能,能够实现灵活的访问控制策略。以下是实现授权控制的关键点:
- RequestOriginParser:解析请求的来源,判断请求是否带有正确的授权信息。
- AddRequestHeader:在网关中自动为每个请求添加特定的请求头,确保所有通过网关的请求能够满足授权规则。
通过这些配置,你可以有效地限制直接访问微服务的请求,从而提高系统的安全性。
# 七、自定义异常处理
# 1. 什么是自定义异常处理?
在使用 Sentinel 进行限流、熔断降级或授权控制时,默认的响应是 Blocked by Sentinel (flow limiting)
。这样的信息对用户来说非常不友好,难以理解发生了什么。因此,我们可以为不同的异常类型设置自定义的响应内容,根据实际情况给出更明确的提示,提升用户的体验。
# 2. 常见的异常类型
Sentinel 提供了多种异常类型,每种类型对应不同的限流、降级或授权规则。以下是常见的异常类型及它们对应的场景:
异常类型 | 说明 |
---|---|
FlowException | 触发流控规则时抛出的异常 |
DegradeException | 触发熔断降级规则时抛出的异常 |
ParamFlowException | 触发热点参数限流规则时抛出的异常 |
SystemBlockException | 触发系统保护规则时抛出的异常 |
AuthorityException | 触发授权规则时抛出的异常 |
# 3. 如何实现自定义异常处理?
你可以通过自定义 BlockExceptionHandler
来处理不同类型的异常,并返回符合场景的响应内容。这个处理器可以根据异常的种类,返回对应的提示信息和状态码。
实现步骤:
- 创建一个类,实现
BlockExceptionHandler
接口。 - 在
handle
方法中,根据不同的异常类型返回不同的响应。
代码示例:
package com.example.sentinel.exception;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定义 Sentinel 异常处理器
*/
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
// 初始化一个默认提示信息和状态码
String message = "系统繁忙,请稍后再试";
int status = HttpServletResponse.SC_TOO_MANY_REQUESTS; // 429 状态码(Too Many Requests)
// 根据不同异常类型自定义提示信息
if (e instanceof FlowException) {
message = "请求被限流了,请稍后再试";
} else if (e instanceof ParamFlowException) {
message = "热点参数限流,请稍后再试";
} else if (e instanceof DegradeException) {
message = "请求被降级了";
} else if (e instanceof AuthorityException) {
message = "访问未授权";
status = HttpServletResponse.SC_UNAUTHORIZED; // 401 状态码(Unauthorized)
}
// 设置响应的内容类型及编码
response.setContentType("application/json;charset=UTF-8");
response.setStatus(status);
// 返回自定义的错误信息
response.getWriter().write("{\"message\": \"" + message + "\", \"status\": " + status + "}");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
代码说明:
- 这个类实现了
BlockExceptionHandler
接口,并在handle
方法中处理不同类型的异常。 - 根据不同类型的异常(如
FlowException
、ParamFlowException
等),返回相应的提示信息。例如:- 触发限流时,返回“请求被限流了”。
- 触发热点参数限流时,返回“热点参数限流”。
- 授权失败时,返回“访问未授权”并设置状态码为
401
。
- 返回的响应格式是 JSON,并包含提示信息和 HTTP 状态码。
# 4. 效果展示
自定义异常处理器会在微服务触发 Sentinel 的限流、降级或授权规则时返回更友好的提示信息。例如:
限流触发: 当请求超出了流控限制时,用户将看到提示 "请求被限流了,请稍后再试"。
{ "message": "请求被限流了,请稍后再试", "status": 429 }
1
2
3
4热点参数限流触发: 当某个参数的请求超过限流阈值时,用户会收到提示 "热点参数限流,请稍后再试"。
{ "message": "热点参数限流,请稍后再试", "status": 429 }
1
2
3
4授权失败: 如果请求没有通过授权验证,系统将返回 "访问未授权" 并将状态码设置为
401
。{ "message": "访问未授权", "status": 401 }
1
2
3
4
总结
通过自定义 Sentinel 的异常处理逻辑,你可以:
- 根据不同的异常类型,返回更友好的提示信息。
- 改善用户体验,让用户能够更清楚地了解请求失败的原因。
- 通过灵活的响应状态码(如
429 Too Many Requests
或401 Unauthorized
),帮助用户和开发者快速识别问题。
通过这种方式,你不仅可以让系统在出现异常时更加可靠,还能为用户提供有用的反馈信息,避免因默认的错误提示影响体验。
# 八、规则持久化
# 1. 什么是规则持久化?
Sentinel 默认情况下把限流、熔断等规则保存在内存中,但这有一个问题:当服务重启时,所有配置都会丢失。为了避免这种情况,我们可以把 Sentinel 的规则存储到外部存储中,比如 Nacos、Redis、ZooKeeper 等。这种将规则保存到外部存储的过程就叫做规则持久化。通过规则持久化,即使服务重启,配置也不会丢失,还可以实现动态更新。
# 2. 规则持久化的 3 种模式
Sentinel 提供了三种不同的规则持久化模式,用来保证配置的安全性和动态性:
原始模式(默认模式):默认情况下,Sentinel 会将规则保存在内存中,重启服务后这些规则将会丢失。适用于临时测试场景。
Pull 模式:在这种模式下,Sentinel 客户端会从外部配置中心主动拉取最新的规则配置。配置可以保存在本地文件、数据库或远程配置中心,客户端定期拉取更新配置。这种模式的核心是客户端主动去“拉”最新的规则。
Push 模式:在这种模式下,配置中心(例如 Nacos)会主动推送规则到 Sentinel 客户端。其他客户端通过监听配置中心的规则变化,实现配置的实时更新。这种方式可以让规则更快速地应用于系统中。
下图展示了三种模式的对比:
# 3. 规则持久化的注意事项
虽然 Sentinel 支持 Push 模式的规则持久化,但官方的开源版本并没有直接提供这一功能。如果需要使用 Push 模式,你可以通过以下两种方式实现:
- 自己扩展 Sentinel,添加支持 Push 模式的功能。
- 使用阿里云提供的商业版服务,商业版 Sentinel 提供了更多的扩展能力,包括规则的 Push 持久化功能。
注意:如果你的系统对实时性要求不高,Pull 模式已经能够很好地满足规则持久化需求。
# 4. 规则持久化配置示例
接下来我们以 Nacos 作为配置中心,演示如何配置规则持久化。
使用 Nacos 作为配置中心
Nacos 是阿里巴巴提供的一种开源配置管理工具,我们可以使用它来持久化 Sentinel 的规则。以下是将规则持久化到 Nacos 的配置步骤:
- 配置文件:在你的
application.yml
中,指定 Nacos 作为 Sentinel 的数据源:
spring:
cloud:
sentinel:
datasource:
ds:
nacos:
server-addr: localhost:8848 # Nacos 服务地址
dataId: sentinel-rules # 规则的唯一标识
groupId: DEFAULT_GROUP # Nacos 配置的组ID
data-type: json # 规则的数据格式,使用JSON
rule-type: flow # 规则的类型,如流控规则
2
3
4
5
6
7
8
9
10
11
- 规则存储:在 Nacos 中,你可以把 Sentinel 的规则保存为 JSON 格式。Nacos 会作为存储配置的数据库,客户端会自动从 Nacos 获取这些规则并应用到服务中。
通过这个配置,当你更新 Nacos 中的规则时,Sentinel 客户端会自动拉取最新的规则,并动态更新系统中的限流、降级规则。
# 5. 规则持久化的好处
通过规则持久化,你可以实现以下效果:
- 避免数据丢失:即使服务重启,规则也不会丢失,因为它们保存在外部的存储中。
- 规则动态更新:无需重启服务,你可以直接在 Nacos 或其他配置中心修改规则,客户端会自动拉取并应用最新的配置。
- 系统更稳定:规则持久化和动态更新提高了系统在高并发场景下的稳定性,防止因配置丢失导致的不必要风险。
通过将规则持久化到外部配置中心(如 Nacos),你可以确保服务在重启后仍能保持一致的流控和降级策略,同时允许动态调整配置,从而提高系统的灵活性和稳定性。