Sentinel限流熔断
开篇:如何防止一个慢接口拖垮整个系统?
想象一下,你住在一栋大楼里,大楼只有一根总水管。某天五楼的住户打开水龙头忘了关,水压骤降,整栋楼都没水用了。
微服务系统中也有类似的问题。服务 A 调用服务 B,服务 B 又调用服务 C。如果服务 C 响应变慢,服务 B 的线程就会被大量阻塞等待,进而拖垮服务 B,然后服务 A 也跟着挂掉。这种"一个慢接口导致整条链路崩溃"的现象,叫做 服务雪崩。
我们没办法保证每个服务永远不出问题,但我们可以做好防御:限流、熔断、降级。
Sentinel 就是阿里巴巴开源的一款面向分布式服务架构的流量治理组件,专门用来解决这类问题。
一、常见容错思路
在正式介绍 Sentinel 之前,先来看几种通用的容错方案,理解它们的核心思想。
1. 隔离
把系统按模块划分,模块之间相对独立。就像船舱的水密隔间,一个隔间进水不会导致整艘船沉没。微服务架构中,线程池隔离和信号量隔离是两种常见的实现方式。
2. 超时
给每次远程调用设置一个最大等待时间。超过这个时间就主动断开,释放线程资源,不会傻等下去。这是最简单也最基础的容错手段。
3. 限流
控制单位时间内允许通过的请求数。好比高速公路入口的匝道信号灯,车太多时让你等一等,避免高速公路堵成停车场。
4. 熔断
当下游服务持续出错时,上游服务暂时停止调用它。就像家里的电路保险丝,电流过大时自动断开,保护整个电路不被烧毁。
5. 降级
调用失败时不直接报错,而是返回一个兜底结果。比如推荐服务挂了,就给用户展示一个默认的热门列表,总比白屏好。
以上五种手段往往组合使用,而 Sentinel 对其中的限流、熔断、降级三个能力提供了开箱即用的支持。
二、限流算法详解
限流的核心问题是:如何精确地控制单位时间内通过的请求数量? 业界有四种经典算法,各有优劣。
2.1 计数器固定窗口
最朴素的思路:维护一个计数器,每来一个请求就加 1,超过阈值就拒绝。每到时间窗口结束就清零。
假设阈值 100 请求/秒:
|--- 第1秒 (计数0~100) ---|--- 第2秒 (计数归零) ---|问题:如果前一秒的后 500ms 来了 99 个请求,后一秒的前 500ms 又来了 99 个请求,实际上在 1 秒内通过了 198 个请求,远超阈值。这就是"窗口边界突刺"问题。
2.2 计数器滑动窗口
把一个大窗口拆成多个小格子(比如 1 秒拆成 5 个 200ms 的格子),每过一个格子就向前滑动。统计的是最近 5 个格子的总和。
|--200ms--|--200ms--|--200ms--|--200ms--|--200ms--|
↑ 窗口每次向右滑动一格,统计最近 5 格的总请求数格子越细,统计越精确,但也越复杂。Sentinel 的 QPS 限流默认就采用滑动窗口算法,内部使用 LeapArray 数据结构来实现高效的滑动统计。
2.3 漏桶算法
把请求想象成水,先倒进一个桶里,桶底有个固定大小的孔,水以恒定速率流出。桶满了,新来的水就溢出(丢弃)。
特点:输出速率恒定,能很好地平滑突发流量。但缺点也很明显——即使系统有余力处理突发请求,漏桶也不允许,因为出水速度是固定的。
Sentinel 的"排队等待"流控效果就是基于漏桶算法实现的。
2.4 令牌桶算法
系统以恒定速率向桶中放入令牌。每个请求必须拿到一个令牌才能通过,拿不到就排队或拒绝。桶满了多余的令牌就丢弃。
和漏桶的关键区别:令牌桶允许一定程度的突发流量。如果桶里攒了一些令牌,突然来一波请求可以立刻消耗掉这些令牌,不用排队。
Sentinel 的 Warm Up(预热)流控效果就是基于令牌桶算法实现的。
四种算法对比
| 算法 | 原理 | 突发流量处理 | Sentinel 中的应用 |
|---|---|---|---|
| 固定窗口 | 按时间窗口计数 | 有边界突刺问题 | - |
| 滑动窗口 | 细粒度滑动计数 | 较好 | 默认 QPS 限流 |
| 漏桶 | 恒定速率放行 | 完全平滑,不允许突发 | 排队等待效果 |
| 令牌桶 | 恒定速率发令牌 | 允许一定突发 | Warm Up 预热效果 |
三、熔断降级:三态模型
熔断器有三种状态,就像交通信号灯一样控制着请求的通行:
- Closed(关闭):正常状态,请求正常通过,同时在后台持续统计失败率和慢调用率。
- Open(打开):触发熔断后进入此状态,所有请求直接拒绝,执行降级逻辑(fallback)。
- Half-Open(半开):熔断时间到了之后,放一小部分请求试探。如果成功率达标就恢复正常(回到 Closed),否则继续熔断(回到 Open)。
Sentinel 支持三种熔断策略:
| 策略 | 触发条件 | 典型场景 |
|---|---|---|
| 慢调用比例 | 响应时间超过阈值的请求比例过高 | 下游服务变慢 |
| 异常比例 | 异常请求占比超过阈值 | 下游服务不稳定 |
| 异常数 | 异常请求的绝对数量超过阈值 | 低流量下的异常监控 |
注意:熔断规则中还有一个 minRequestAmount(最小请求数)参数,请求数达不到这个值时即使异常率超标也不会触发熔断,避免小样本误判。
四、整合 Spring Boot
4.1 引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>4.2 配置文件
spring:
cloud:
sentinel:
transport:
port: 9999 # 与控制台通信的端口,选一个未使用的即可
dashboard: localhost:8080 # 控制台地址4.3 启动控制台
# 下载 jar 包后直接启动
java -Dserver.port=8080 -jar sentinel-dashboard-1.8.1.jar访问 http://localhost:8080,默认账号密码都是 sentinel。第一次访问某个接口后,对应的资源才会在控制台中出现(Sentinel 采用懒加载机制)。
五、Sentinel 规则配置
5.1 流控规则
流控规则的核心参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
| resource | 资源名,即限流的作用对象 | - |
| grade | 阈值类型:QPS 或并发线程数 | QPS |
| count | 限流阈值 | - |
| strategy | 限流策略:直接、关联、链路 | 直接 |
| controlBehavior | 流控效果:快速失败、Warm Up、排队等待 | 快速失败 |
三种流控策略:
- 直接:当前资源达到阈值就限流,最简单直接。
- 关联:当关联资源达到阈值时,限流当前资源。典型场景:读写互斥时,写接口压力大了就限制读接口,让写操作优先完成。
- 链路:只统计从指定入口进来的流量。粒度比"直接"更细,适合区分不同来源的请求。
三种流控效果:
- 快速失败:超过阈值直接拒绝,抛出
FlowException。底层用滑动窗口算法。 - Warm Up(预热):刚开始阈值是设定值的 1/3,在指定时间内慢慢升到最大值。避免冷系统被突发流量冲垮。底层用令牌桶算法。
- 排队等待:请求以均匀速度通过,超出的排队;超过最大等待时间则丢弃。底层用漏桶算法。
5.2 热点参数限流
热点参数限流是一种更细粒度的规则,可以针对请求中的某个参数值进行限流。
比如一个商品查询接口,某个爆款商品 ID 的请求量特别大,就可以单独对这个参数值做限流,而不影响其他商品的正常查询。
@SentinelResource("queryGoods")
public String queryGoods(@RequestParam Long goodsId) {
// 业务逻辑
}在控制台的"热点规则"中,可以针对 goodsId 的特定值(如 1001)设置单独的阈值。这在秒杀、热点新闻等场景中非常实用。
六、规则持久化
Sentinel 的规则默认存储在内存中,重启就没了。生产环境必须做持久化,有三种方式:
| 模式 | 机制 | 优点 | 缺点 |
|---|---|---|---|
| 原始模式 | 内存存储 | 简单,无依赖 | 重启丢失,不建议生产使用 |
| Pull 模式 | 客户端定期从文件/数据库拉取 | 简单,规则持久化 | 实时性差,一致性弱 |
| Push 模式 | 配置中心(Nacos/ZK)主动推送 | 实时性好,一致性强 | 需要额外的配置中心 |
生产环境推荐 Push 模式,将规则存储在 Nacos 等配置中心中,修改后实时推送到所有客户端。
需要注意的是,Push 模式需要修改 Sentinel Dashboard 源码或使用社区已有的改造版本,原生 Dashboard 的规则推送是直接推到客户端内存的。
七、Sentinel vs Hystrix
| 对比项 | Sentinel | Hystrix |
|---|---|---|
| 维护状态 | 阿里持续维护 | Netflix 已停止维护 |
| 隔离策略 | 信号量隔离(轻量) | 线程池隔离 + 信号量隔离 |
| 熔断策略 | 慢调用比例/异常比例/异常数 | 基于异常比例 |
| 流控 | 基于 QPS,支持多种流控效果 | 有限的流量控制 |
| 实时监控 | 自带 Dashboard | 需要搭配 Hystrix Dashboard |
| 规则配置 | 支持动态数据源(Nacos/ZK) | 需要代码或配置文件 |
| 扩展性 | SPI 扩展,非常灵活 | 插件机制,灵活度一般 |
一句话总结:Hystrix 已经停更,Sentinel 是当前 Spring Cloud Alibaba 生态的首选流量治理方案。
八、常见面试题精选
Q1:什么是服务雪崩?如何防止?
服务雪崩是指一个服务的故障沿着调用链逐层传播,最终导致整个系统瘫痪。防止手段包括超时设置、线程隔离、限流、熔断和降级。Sentinel 通过流控规则和熔断规则来防止雪崩。
Q2:Sentinel 的滑动窗口是怎么实现的?
Sentinel 使用 LeapArray 数据结构实现滑动窗口。它将一个统计窗口(如 1 秒)划分为多个小窗口(默认 2 个 500ms),通过 CAS 操作更新当前小窗口的计数。统计时累加所有小窗口的数据。这比固定窗口更精确,避免了边界突刺问题。
Q3:熔断器的三种状态是什么?状态间如何转换?
Closed(正常通行)、Open(全部拒绝)、Half-Open(放少量请求试探)。当失败率超过阈值时 Closed 转为 Open;熔断时长结束后 Open 转为 Half-Open;Half-Open 中探测请求成功则回到 Closed,失败则回到 Open。
Q4:令牌桶和漏桶有什么区别?
核心区别在于对突发流量的处理。漏桶的出水速率恒定,完全平滑但不允许突发;令牌桶允许消耗累积的令牌来应对突发流量。Sentinel 中排队等待用漏桶,Warm Up 用令牌桶。
小结
Sentinel 是微服务架构中不可或缺的流量治理组件。它的核心能力可以归纳为三点:
- 限流:控制进入系统的流量,保护系统不被突发流量冲垮。四种经典算法各有侧重——固定窗口最简单,滑动窗口更精确,漏桶完全平滑,令牌桶兼顾平滑与突发。
- 熔断:当下游服务出问题时自动切断调用,防止雪崩。三态模型(Closed/Open/Half-Open)实现了"自动断开、定期试探、自动恢复"的完整闭环。
- 降级:提供兜底方案,保证核心链路可用。
记住三个比喻:限流是"入口保安",熔断是"电路保险丝",降级是"备用方案"。三者配合使用,才能构建出一个真正健壮的微服务系统。生产环境中别忘了做规则持久化,推荐 Push 模式配合 Nacos 使用。