Sentinel
Sentinel 是面向分布式系统的流量治理组件,常用于限流、熔断降级、热点参数保护和系统自适应保护。它的目标不是让系统永远不出错,而是在流量过大或依赖异常时,保护核心服务不被拖垮。
本页负责从零建立概念和用法。CtSph、Context、Entry、节点树、Slot真实顺序、LeapArray窗口复用、Warm Up、匀速排队、集群流控、动态规则控制面、异步上下文和生产恢复请继续阅读:
一句话理解:Sentinel 负责决定一个请求能不能继续执行,以及失败时返回什么降级结果。
阅读入口:一次调用如何被规则拦截
按“资源埋点 → 规则匹配 → 滑动窗口统计 → 流控/熔断判断 → fallback”阅读。先分清限流、熔断和降级,再学习热点参数、集群流控和规则持久化。
为什么需要 Sentinel
| 场景 | 没有保护时 | 使用 Sentinel 后 |
|---|---|---|
| 秒杀接口突发流量 | 请求全部打进业务和数据库 | 超过阈值直接限流 |
| 下游服务变慢 | 调用线程堆积,拖垮上游 | 熔断一段时间,快速失败 |
| 某个用户疯狂刷接口 | 影响其他正常用户 | 按参数或用户限流 |
| 系统 CPU 过高 | 所有接口继续接流量 | 触发系统保护 |
请求处理流程
flowchart TD
A["请求进入接口"] --> B["识别 Sentinel 资源名"]
B --> C["统计实时 QPS、线程数、异常、耗时"]
C --> D["依次执行流控与熔断判断"]
D --> E["通过则执行业务,阻断则抛异常"]
E --> F["记录业务结果并退出资源"]Sentinel 的核心原理:资源、规则、统计、拦截
Sentinel 不是简单的 if (qps > 100) return。它会围绕“资源”维护实时统计,再用规则判断请求是否允许通过。
flowchart TD
A["进入受保护资源"] --> B["建立Context"]
B --> C["NodeSelector"]
C --> D["ClusterBuilder"]
D --> E["Statistic"]
E --> F["Authority"]
F --> G["System"]
G --> H["Flow"]
H --> I["CircuitBreaker"]
I --> J["执行业务或阻断"]学习时不用死背每个 Slot 的源码,但要理解这条主线:
先识别资源,再采集实时指标,再按规则判断是否放行。SlotChain 每一段到底在干什么
把 SlotChain 想成一条“请求安检通道”。请求不是直接进入业务方法,而是先经过多个检查点。每个检查点只负责一类事情,组合起来完成流量治理。
| Slot | 可以怎么理解 | 主要作用 | 如果没有它会怎样 |
|---|---|---|---|
NodeSelectorSlot | 建调用路径 | 记录当前资源在什么调用入口下被访问 | 分不清同一个资源从哪个入口进来 |
ClusterBuilderSlot | 建统计节点 | 为资源创建全局统计节点 ClusterNode | 无法聚合资源整体 QPS、异常、RT |
StatisticSlot | 计数器 | 统计通过、拒绝、异常、耗时、并发线程数 | 后续规则没有实时数据可判断 |
FlowSlot | 限流门卫 | 根据 QPS、线程数、关联资源等判断是否限流 | 大流量会全部打进业务 |
DegradeSlot | 熔断门卫 | 根据慢调用比例、异常比例、异常数判断是否熔断 | 下游持续慢时仍继续调用 |
SystemSlot | 系统保护 | 根据系统 load、CPU、入口 QPS、线程数保护整体系统 | 机器快被打满时还继续接流量 |
AuthoritySlot | 黑白名单 | 根据调用来源做简单授权控制 | 无法基于来源做拦截 |
关键是:StatisticSlot 通常既要在请求进入时记录线程数,也要在请求结束时记录耗时和异常。熔断规则并不是凭空判断,而是基于这些统计结果。
flowchart TD
A["请求进入资源"] --> B["前置统计并发线程数"]
B --> C["FlowSlot 判断是否限流"]
C --> D["DegradeSlot 判断是否熔断"]
D --> E["业务方法执行"]
E --> F["记录 RT、成功、异常"]
F --> G["更新滑动窗口指标"]如果面试问 Sentinel 原理,不要只说“它能限流熔断”。更好的回答是:
Sentinel 把接口、方法、外部调用抽象成资源,请求进入资源时会经过 SlotChain。SlotChain 先建立调用上下文和统计节点,再用滑动窗口统计 QPS、RT、异常、线程数,最后由 FlowSlot、DegradeSlot、SystemSlot 等规则判断是否放行。通过则执行业务,不通过抛出 BlockException,由 blockHandler 或统一异常处理返回限流降级结果。滑动窗口为什么能统计实时 QPS
限流和熔断都需要实时指标。Sentinel 会把一段时间切成多个小窗口,每个窗口记录请求数量、异常数、耗时等。
flowchart TD
A["1秒统计周期"] --> B["切分多个小窗口"]
B --> C["各桶记录通过、拒绝、异常和RT"]
C --> D["汇总最近周期内的有效桶"]当时间向前推进,旧窗口会被淘汰,新窗口加入。这样比“每秒整点清零”更平滑,不会在边界处出现统计跳变。
如果不了解滑动窗口,就很难解释为什么 Sentinel 能根据最近一段时间的异常比例、慢调用比例做熔断。
核心概念
| 概念 | 说明 |
|---|---|
| Resource | 受保护的资源,可以是接口、方法、外部调用 |
| Rule | 规则,例如 QPS 限流、慢调用熔断 |
| BlockException | Sentinel 拦截请求时抛出的异常 |
| Fallback | 业务异常或降级时返回的兜底结果 |
| Dashboard | Sentinel 控制台,用于查看资源和配置规则 |
常见规则
| 规则 | 解决的问题 | 示例 |
|---|---|---|
| 流控规则 | 控制 QPS 或并发线程数 | 登录接口每秒最多 100 次 |
| 熔断规则 | 下游慢或异常时快速失败 | 库存服务异常比例过高时熔断 |
| 热点参数规则 | 针对某个参数值单独限流 | 商品 ID 为爆款时限流 |
| 系统规则 | 根据系统负载保护整体服务 | CPU 或入口 QPS 超阈值 |
| 授权规则 | 简单黑白名单访问控制 | 只允许指定来源调用 |
流控规则讲细:QPS、并发、关联、链路
流控不是只有“每秒最多多少请求”。Sentinel 的流控可以按不同角度保护系统。
| 类型 | 判断依据 | 适合场景 | 例子 |
|---|---|---|---|
| QPS 限流 | 单位时间通过请求数 | 接口很快,但流量可能突增 | 查询接口每秒最多 500 次 |
| 并发线程数限流 | 当前正在执行的线程数 | 接口慢、导出、外部接口调用 | 导出接口最多同时 10 个 |
| 关联流控 | 关联资源压力过大时限制当前资源 | 保护写操作或核心资源 | 支付提交压力大时限制查询刷新 |
| 链路流控 | 只限制某个入口链路 | 同一方法被多个入口调用 | 管理端不限,开放接口限 |
QPS 限流和并发线程数限流怎么选
很多线上误配来自“慢接口只配 QPS”。例如一个导出接口每秒只有 5 个请求,但每个请求执行 60 秒,最终会同时占用 300 个执行位置。
并发数约等于 QPS * 平均耗时秒数如果接口平均耗时 60 秒,QPS 是 5:
并发数 = 5 * 60 = 300这时 QPS 看起来不高,但线程和连接已经被占满。慢接口应该优先考虑并发线程数限流,必要时改成异步任务。
flowchart TD
A["评估接口成本"] --> B["快接口重点看QPS"]
B --> C["慢接口重点看并发"]
C --> D["同时保护下游资源"]关联流控解决什么
关联流控常用于“保护核心写接口”。比如订单系统中,查询订单可以多一些,提交订单是核心。如果提交订单压力很大,就可以限制查询刷新,给提交订单让资源。
当 submitOrder 资源压力超过阈值时,限制 queryOrder 资源。这背后的思想是:系统资源有限,不能所有接口一视同仁。核心链路要优先保,非核心链路可以让路。
排队等待和快速失败
被限流时有两种常见处理:
| 处理方式 | 含义 | 适合场景 |
|---|---|---|
| 快速失败 | 超过阈值立即拒绝 | 秒杀、登录、查询、开放接口 |
| 匀速排队 | 请求排队按固定速度通过 | 消息发送、批量写入、削峰入库 |
匀速排队不是无限排队。队列等待时间过长,用户体验会很差,线程也可能被占住。对前端实时接口,通常更适合快速失败并提示稍后重试;对后台批处理,可以考虑排队或消息队列削峰。
限流、熔断、降级的工作差异
| 能力 | 触发依据 | 发生在什么时候 | 返回什么 |
|---|---|---|---|
| 限流 | QPS、并发线程数、热点参数超过阈值 | 请求进入时 | blockHandler 或统一限流响应 |
| 熔断 | 慢调用比例、异常比例、异常数超过阈值 | 一段统计窗口后 | 快速拒绝,避免继续调用不健康依赖 |
| 降级 | 限流/熔断/业务异常后的兜底 | 请求被拒或业务失败后 | 兜底结果 |
一句话:
限流挡住过量入口,熔断隔离不健康依赖,降级给调用方一个可接受的失败结果。熔断器状态流转
熔断器通常有三个状态:
| 状态 | 含义 |
|---|---|
| CLOSED | 正常放行,并统计调用结果 |
| OPEN | 熔断打开,直接拒绝请求 |
| HALF_OPEN | 过一段时间后试探放行少量请求 |
flowchart TD
A["CLOSED正常统计"] --> B["指标超阈值"]
B --> C["OPEN快速失败"]
C --> D["到期进入HALF_OPEN"]
D --> E["按探测结果转移状态"]这能避免下游已经故障时,上游继续把请求打过去。它牺牲一段时间的可用结果,换取系统整体稳定。
熔断规则讲细:慢调用、异常比例、异常数
熔断解决的不是“流量太大”,而是“依赖不健康”。依赖可能是 Feign 下游服务、数据库、Redis、ES、外部医院接口,也可能是本服务内部的慢方法。
| 熔断类型 | 判断方式 | 适合场景 |
|---|---|---|
| 慢调用比例 | 最近窗口内 RT 超过阈值的请求比例过高 | 下游变慢、数据库慢、外部接口慢 |
| 异常比例 | 最近窗口内异常请求比例过高 | 下游持续 500、业务异常激增 |
| 异常数 | 最近窗口内异常数量超过阈值 | 低 QPS 但异常很明显的接口 |
慢调用比例为什么很重要
异常并不是唯一风险。很多雪崩不是从报错开始,而是从“变慢”开始。
flowchart TD
A["下游响应从 50ms 变成 3s"] --> B["上游线程等待时间变长"]
B --> C["线程池逐渐被占满"]
C --> D["新请求排队"]
D --> E["更多请求超时和重试"]
E --> F["系统雪崩"]慢调用比例熔断可以在错误率大面积上升前先保护上游。比如:
RT 阈值: 1000ms
慢调用比例阈值: 50%
统计窗口: 10s
最小请求数: 20
熔断时长: 5s含义是:最近 10 秒内至少有 20 次请求,并且超过 1000ms 的请求比例达到 50%,就打开熔断 5 秒。5 秒内后续请求快速失败,不再继续打下游。
最小请求数为什么必要
如果没有最小请求数,一个接口刚好 2 次请求,1 次慢,就达到 50% 慢调用比例,立刻熔断,这显然不合理。
最小请求数用于避免样本太少导致误判:
| 最小请求数 | 风险 |
|---|---|
| 太小 | 容易误熔断 |
| 太大 | 低流量接口可能迟迟不触发保护 |
所以熔断规则要结合接口 QPS 设置。高 QPS 接口可以设置较高最小请求数;低 QPS 关键接口可以用异常数或较小窗口谨慎配置。
热点参数限流:为什么只保护某个参数
热点参数限流解决的是“总流量不高,但某个 key 特别热”。
典型场景:
| 场景 | 热点参数 |
|---|---|
| 爆款商品详情 | skuId |
| 某医院接口异常重试 | hospitalCode |
| 某租户批量导出 | tenantId |
| 某资产被频繁查询 | assetId |
如果只配接口总 QPS,可能出现:
接口总 QPS = 500,没有超过阈值
skuId=1001 的 QPS = 450,打爆缓存和数据库
其他商品几乎没人访问热点参数限流可以只限制 skuId=1001,不影响其他商品。
flowchart TD
A["请求进入商品详情"] --> B["提取 skuId"]
B --> C["按参数值独立统计"]
C --> D["只限制超过阈值的热点值"]这也是为什么 Redis 热 key、ES 热查询、单医院接口重试,都不能只看接口总流量。
热点参数规则怎么工作
热点参数限流不是只看接口总次数,而是把“参数位置 + 参数值”当成更细的统计维度。例如商品详情接口第 0 个参数是 skuId,Sentinel 会按每个 skuId 分别统计访问频率。
flowchart TD
A["请求进入 getProduct skuId=1001"] --> B["ParamFlowSlot提取参数"]
B --> C["定位参数索引 paramIdx=0"]
C --> D["按 skuId=1001 单独统计QPS"]
D --> E{"是否超过该参数阈值"}
E -- "否" --> F["继续执行业务"]
E -- "是" --> G["抛出ParamFlowException"]这样做的原因是:很多线上热点不是“接口整体热”,而是“某个值特别热”。如果只限制接口总 QPS,要么阈值太低误伤所有正常商品,要么阈值太高保护不了爆款商品。
| 配置项 | 含义 | 容易踩坑 |
|---|---|---|
| 资源名 | 被保护的方法或接口 | 和 @SentinelResource 的 value 不一致会不生效 |
| 参数索引 | 第几个参数作为热点 key | Controller、Service、Feign 参数顺序要确认 |
| 单机阈值 | 每个参数值在单实例上的通过量 | 多实例总量会乘以实例数 |
| 统计窗口 | 多长时间内统计热点 | 窗口太短抖动,太长恢复慢 |
| 例外项 | 给指定参数值单独阈值 | 爆款商品、大租户、重点医院可单独配置 |
热点参数限流不能替代 Redis 热 Key 治理。如果 skuId=1001 被限流后仍有大量请求命中缓存和数据库,还要配合本地缓存、请求合并、缓存预热、异步刷新、库存令牌和页面静态化。
热点参数商业示例:医院采集
医疗采集场景里,总采集 QPS 可能不高,但某一家医院接口异常慢,调度器和人工补采一直重试,最终拖垮全局采集线程池。这时可以把 hospitalCode 作为热点参数:
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
public class HospitalCollectService {
public String collect(String hospitalCode) {
Entry entry = null;
try {
entry = SphU.entry("hospital-collect", 1, hospitalCode);
return doCollect(hospitalCode);
} catch (BlockException ex) {
return "医院 " + hospitalCode + " 当前采集过载,已进入排队或补偿";
} finally {
if (entry != null) {
entry.exit(1, hospitalCode);
}
}
}
private String doCollect(String hospitalCode) {
return "collect " + hospitalCode;
}
}这个 Demo 表达的是核心原理:进入资源时带上热点参数,退出资源时也要带上相同参数数量。真实 Spring Cloud 项目通常用 @SentinelResource、Gateway Filter 或 Feign 适配器接入,不一定手写 SphU.entry()。
Spring Cloud 接入示例
依赖示例:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>配置示例:
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8858
port: 8719接口降级示例:
@RestController
public class OrderController {
@GetMapping("/orders/{id}")
@SentinelResource(
value = "getOrder",
blockHandler = "handleBlocked",
fallback = "handleFallback"
)
public String getOrder(@PathVariable Long id) {
if (id < 0) {
throw new IllegalArgumentException("invalid id");
}
return "order-" + id;
}
public String handleBlocked(Long id, BlockException ex) {
return "请求太频繁,请稍后再试";
}
public String handleFallback(Long id, Throwable ex) {
return "订单服务暂时不可用";
}
}区别:
blockHandler处理 Sentinel 规则拦截,例如限流。fallback处理业务异常或降级兜底。
blockHandler 和 fallback 签名要求
blockHandler 方法要额外接收 BlockException,参数列表要能和原方法匹配。
public String handleBlocked(Long id, BlockException ex) {
return "请求太频繁,请稍后再试";
}fallback 方法通常接收 Throwable。
public String handleFallback(Long id, Throwable ex) {
return "订单服务暂时不可用";
}如果方法签名不匹配,运行时可能找不到处理方法。生产项目里更推荐把降级方法放到单独类中,避免 Controller 变得臃肿。
商业场景:保护医疗采集链路
医疗采集平台常见保护点:
| 资源 | 风险 | Sentinel 规则 |
|---|---|---|
/collect/start | 人工或系统重复触发采集 | 按用户或医院限流 |
| 字典服务 Feign 调用 | 下游慢导致采集线程堆积 | 慢调用比例熔断 |
| 单医院数据拉取 | 某医院接口异常重试过多 | 热点参数限流,参数为 hospitalCode |
| 资产检索接口 | 高峰查询打爆 ES | QPS 限流 + 降级 |
| 导出接口 | 大导出占满线程 | 并发线程数限流 |
示例:按医院编码做热点参数限流。
@SentinelResource(
value = "collectByHospital",
blockHandler = "collectBlocked"
)
public String collectByHospital(String hospitalCode) {
return collector.collect(hospitalCode);
}
public String collectBlocked(String hospitalCode, BlockException ex) {
return "医院 " + hospitalCode + " 当前采集请求过多,请稍后重试";
}这样某一个医院接口异常时,不会把所有采集线程都占满。
限流和熔断的区别
flowchart TD
A["先判断问题来源"] --> B["过量流量使用限流"]
B --> C["不健康依赖使用熔断"]| 对比 | 限流 | 熔断 |
|---|---|---|
| 触发原因 | 请求量超过阈值 | 慢调用、异常比例、异常数超过阈值 |
| 保护对象 | 当前服务和下游资源 | 调用链路上的依赖 |
| 典型返回 | “请求过多” | “服务暂时不可用” |
阈值怎么设置
不要凭感觉写阈值。推荐步骤:
- 压测接口,得到单实例可承受 QPS、平均耗时、P95 耗时。
- 结合实例数量,计算总容量。
- 为核心接口预留安全余量。
- 先在测试环境验证规则。
- 上线后观察监控,再逐步调整。
例如单实例稳定承受 200 QPS,部署 3 个实例,总容量约 600 QPS。考虑安全余量,可以先把入口限流设为 450 到 500 QPS,再根据监控调整。
阈值设置的细化方法
QPS 限流
适合请求很短、线程占用不高的接口。设置时要看单实例容量。
单实例稳定 QPS = 压测得到的 P95 可接受情况下吞吐
集群总阈值 = 单实例稳定 QPS * 实例数 * 安全系数安全系数通常不要取 1,可以先用 0.7 到 0.8。
并发线程数限流
适合慢接口、导出、外部接口调用。一个接口 QPS 不高,但每次执行 30 秒,也可能占满线程。
并发数 = QPS * 平均响应时间秒数如果接口每秒 10 个请求,每个请求平均 5 秒,那么大约会占 50 个并发执行位置。
慢调用比例熔断
适合保护下游依赖。比如字典服务正常 50ms 返回,如果最近一段时间超过 1s 的请求比例很高,就说明下游不健康,应短暂熔断。
系统规则:为什么不是接口级限流
流控规则保护某个资源,系统规则保护整台应用实例。它关注的是“机器或进程整体是否快扛不住了”,例如 CPU、系统负载、入口 QPS、总线程数、平均 RT。
flowchart TD
A["请求进入任意入口资源"] --> B["读取系统实时指标"]
B --> C{"CPU、Load、线程数或入口QPS是否超阈值"}
C -- "否" --> D["继续资源级规则判断"]
C -- "是" --> E["触发SystemBlockException"]系统规则适合做最后一道保护线,但不要把它当成精确容量治理。原因是系统指标往往比较粗:
| 指标 | 保护意图 | 风险 |
|---|---|---|
| Load | 机器运行队列和CPU压力 | 容器环境下和宿主机指标可能有偏差 |
| CPU usage | CPU打满时拒绝新请求 | 短抖动容易误伤,需要结合窗口观察 |
| 入口 QPS | 控制整个应用入口流量 | 无法区分核心接口和非核心接口 |
| 线程数 | 避免全局并发过高 | 慢接口和快接口混在一起 |
| 平均 RT | 整体响应变慢时保护 | 平均值可能掩盖P99尾延迟 |
商业项目里,系统规则通常作为兜底:
- Gateway 或入口层做租户、用户、接口级限流。
- 服务层对核心资源做 QPS、并发、热点参数和熔断。
- 系统规则在 CPU、Load 或总入口流量异常时兜底拒绝。
- 拒绝时返回明确错误码,不要伪装成业务成功。
如果只依赖系统规则,问题会很粗糙:一个低价值导出接口把 CPU 打满时,系统规则可能把下单接口也一起拦住。更好的做法是先把导出接口做并发限制、异步化和独立线程池,再让系统规则兜底。
集群流控:单机阈值和全局阈值的区别
单机限流只知道本实例流量。部署多个实例时,总通过量大约等于单机阈值乘以实例数。比如每台 200 QPS,5 台就是 1000 QPS。如果下游数据库只能承受 600 QPS,扩容应用后反而可能把数据库打爆。
flowchart TD
A["多个应用实例"] --> B["各自本地限流"]
B --> C["总流量随实例数增加"]
C --> D["共享下游数据库或第三方被打满"]
A --> E["集群流控Token Server"]
E --> F["按全局配额发放令牌"]集群流控的目标是把“全局额度”集中裁决。各实例向 Token Server 请求令牌,拿到令牌才放行。它适合租户总额度、第三方接口总额度、数据库总写入额度这类不能随实例数线性放大的资源。
| 方案 | 优点 | 代价 | 适合 |
|---|---|---|---|
| 单机限流 | 简单、无中心依赖、延迟低 | 总量随实例数变化,负载不均会误差 | 单实例容量保护、普通接口 |
| 集群流控 | 更接近全局配额 | Token Server 成为新依赖,需要超时和降级策略 | 第三方额度、租户合同额度、共享数据库保护 |
| Gateway 全局限流 | 入口统一,便于按用户/租户 | 绕过Gateway的内部调用保护不到 | 外部API、统一入口 |
| Redis Lua 限流 | 跨实例共享状态,实现灵活 | Redis热点和网络依赖 | 中低频全局额度、登录验证码 |
集群流控也不是银弹。Token Server 不可用时,要提前定义 Fail-open 还是 Fail-closed:
| 业务 | 推荐倾向 |
|---|---|
| 普通查询 | 可短时间 Fail-open,但启用本地保守阈值 |
| 短信、验证码、登录风控 | 更偏 Fail-closed 或降级排队 |
| 支付、库存、扣费 | 不能靠流控决定成功,必须回到业务状态机 |
| 第三方有硬额度接口 | 优先 Fail-closed,避免超额被封禁 |
Warm Up 和匀速排队怎么选
限流效果也分不同流控行为。
| 行为 | 原理 | 适合 | 不适合 |
|---|---|---|---|
| 快速失败 | 超过阈值立即拒绝 | 实时接口、秒杀、登录、查询 | 必须全部处理的后台任务 |
| Warm Up | 阈值从较低值逐步升高 | 冷启动、缓存预热、JIT预热 | 突发但必须立即吃满容量的系统 |
| 匀速排队 | 按固定间隔放行请求 | 消息发送、异步入库、削峰写入 | 用户实时请求、长时间排队 |
Warm Up 的意义是防止新实例刚启动就吃满流量。新实例可能还没完成 JIT、连接池、缓存、线程池预热,直接接满流量会让 P99 飙升。滚动发布时,Warm Up、Nacos 权重、Readiness 和连接池预热应配合使用。
匀速排队适合把突发请求“摊平”,但必须有最大等待时间。否则请求虽然没有被拒绝,却一直占用线程,最后还是拖垮服务。实时接口一般宁可快速失败,也不要让用户等很久。
规则持久化
控制台临时配置的规则如果不持久化,应用重启后会丢失。生产环境要接入 Nacos、Apollo、ZooKeeper 或文件数据源。
flowchart TD
A["Sentinel Dashboard"] --> B["修改规则"]
B --> C["推送到 Nacos"]
C --> D["应用监听规则变化"]
D --> E["本地生效"]
E --> F["应用重启后重新从 Nacos 拉取"]为什么控制台规则不能只存在内存
Sentinel Dashboard 默认更像“规则管理入口”,不是天然的强持久化配置中心。如果规则只存在应用内存或控制台临时推送,重启后可能丢失。
生产规则链路应该是:
flowchart TD
A["运维或开发修改规则"] --> B["规则写入 Nacos / Apollo"]
B --> C["应用监听配置变化"]
C --> D["Sentinel 本地规则管理器更新"]
D --> E["新请求按新规则判断"]规则应该纳入配置管理和发布流程,至少要做到:
| 要求 | 原因 |
|---|---|
| 规则有持久化来源 | 应用重启不丢规则 |
| 规则有环境隔离 | 测试环境规则不能影响生产 |
| 规则有审批或变更记录 | 防止误把限流阈值改太小 |
| 规则有回滚方案 | 错误规则可以快速恢复 |
| 规则和监控联动 | 规则是否生效要能观察 |
OpenFeign 接入 Sentinel 怎么理解
Feign 调用下游时,Sentinel 可以把 Feign 方法或目标服务当成资源进行保护。下游变慢或异常时,上游不应该无限等待和重试,而应该快速失败、降级或记录补偿。
flowchart TD
A["订单服务调用 StockClient.lock"] --> B["Feign 代理"]
B --> C["Sentinel判断"]
C --> D["通过后选择库存实例"]
D --> E["HTTP客户端执行调用"]
E --> F["记录RT与调用结果"]
F --> G["阻断或失败按语义处理"]配置示例:
feign:
sentinel:
enabled: trueFeign Client 示例:
@FeignClient(
name = "stock-service",
fallbackFactory = StockClientFallbackFactory.class
)
public interface StockClient {
@PostMapping("/stocks/lock")
Result<Void> lock(@RequestBody LockStockCommand command);
}降级工厂:
@Component
public class StockClientFallbackFactory implements FallbackFactory<StockClient> {
@Override
public StockClient create(Throwable cause) {
return command -> {
log.warn("锁库存调用失败, requestNo={}, cause={}",
command.getRequestNo(), cause.toString());
return Result.fail("库存服务繁忙,请稍后重试");
};
}
}写操作要特别注意:fallback 不能返回成功。锁库存、支付、发货这类操作失败后,应该返回失败、进入待确认状态或记录补偿任务。
生产排查:Sentinel 拦截了请求怎么办
线上看到“接口被限流”或“走了降级”,不要只把阈值调大。先判断是哪类规则拦截。
flowchart TD
A["请求被Sentinel拦截"] --> B["识别具体异常类型"]
B --> C["检查对应规则与实时指标"]
C --> D["对照实例、版本和发布时间"]
D --> E["判断误配置还是真实过载"]排查证据:
| 证据 | 说明 |
|---|---|
| 资源名 | 哪个接口或方法被保护 |
| 规则类型 | 流控、熔断、热点、系统、授权 |
| 当前 QPS 和通过 QPS | 是否超过阈值 |
| block QPS | 每秒被拒多少 |
| RT、P95、P99 | 是否慢调用变多 |
| 异常比例和异常数 | 是否下游错误激增 |
| 线程池和连接池 | 是否等待资源 |
| 下游日志和 traceId | 是否真正打到下游 |
常见误判:
| 现象 | 不要立刻做什么 | 正确方向 |
|---|---|---|
| 被限流 | 不要只把阈值调大 | 先确认容量、热点 key、是否异常重试 |
| 被熔断 | 不要只关熔断 | 查下游慢 SQL、GC、线程池、网络 |
| fallback 返回很多 | 不要以为业务成功 | 看 fallback 是否代表失败、是否需要补偿 |
| block QPS 很高 | 不要只怪 Sentinel | 可能入口流量、重试、爬虫、批任务异常 |
常见错误
| 错误 | 后果 | 建议 |
|---|---|---|
| 所有接口共用一个资源名 | 规则互相影响 | 每个关键接口使用清晰资源名 |
| 降级结果和正常结果格式不同 | 前端处理混乱 | 统一响应结构和错误码 |
| 只配置限流不做提示 | 用户体验差 | 返回明确“稍后重试” |
| 阈值凭感觉 | 要么无效,要么误伤 | 根据压测和监控设置 |
| 规则没有持久化 | 应用重启后规则丢失 | 接入 Nacos、Apollo 等规则源 |
练习
- 给一个查询接口加
@SentinelResource。 - 配置 QPS 为 1 的流控规则,连续刷新观察限流结果。
- 模拟下游接口慢调用,配置熔断规则。
- 把降级返回改成统一 JSON 结构。
- 思考哪些接口应该限流,哪些接口不应该被简单限流。
小结
Sentinel 的核心是流量治理。限流解决“流量太大”,熔断解决“依赖不健康”,热点参数保护解决“局部热点”。真正落地时,规则要来自压测和监控,降级返回要符合业务语义,规则还要持久化,否则重启后保护能力会丢失。
