先说结论:Sentinel 是面向微服务、分布式系统的流量治理组件,核心就三件事:限流、熔断降级、系统保护。微服务里真正让人头疼的不是功能开发,而是流量一上来、下游一慢、某个接口一抖动,整个链路跟着挂。很多人把“限流”简单理解成 Redis 计数器,但 Sentinel 做得更靠业务侧,能在接口、方法、资源维度做精细化保护。如果你正准备给 Spring Cloud 项目接入流量防护,或者面试时被问到“为什么需要限流和熔断”,下面可以按落地顺序看一遍。
这类组件最值得先看的不是功能列表,而是能不能在普通环境里稳定跑起来。Sentinel 本身是一套 Java 组件,加上一个独立控制台,配合 Spring Cloud Alibaba 使用很常见。下面从问题场景、环境准备、本地 Demo、参数设置、生产化注意事项、常见排错六个方向展开。
1. 先搞清楚 Sentinel 到底解决什么问题
1.1 微服务里的流量不是均匀的
微服务架构下,一个用户请求往往不是只到一个服务就结束。以常见的电商下单链路为例,请求链路可能是:
网关 -> 用户服务 -> 订单服务 -> 库存服务 -> 支付服务
一次下单可能要经过 5 到 10 次内部调用。任何一个依赖变慢,都会拖慢当前服务。真正的风险往往不在自己代码,而在下游:库存服务数据库连接池满了,订单服务调用库存的线程集体卡住,订单接口响应时间从 20ms 变成 2 秒,网关层也开始排队,用户侧表现为页面转圈、按钮没反应。
流量上来的时候,最怕的不是 CPU 被打满,而是线程池、连接池被慢请求占满。请求等不到资源,新的请求又不断进来,服务会变成一个“假死”状态:进程还在,但已经处理不了正常请求。
所以微服务不能只在自己的服务内部做优化,还要在外层做防护。防护手段就是限流、熔断、降级。
1.2 限流、熔断、降级分别指什么
这三件事经常放在一起说,但作用对象不同。
限流,限制进入当前服务的流量。比如某个下单接口最多只能扛 1000 QPS,那就只放 1000 过去,超过的直接返回“系统繁忙”。目的是保护自己,避免被瞬时流量打爆。
熔断,停止对失败下游的调用。比如订单服务调用支付服务,支付服务连续异常率达到 50%,那订单服务就主动切断一段时间,不再发起支付调用。目的是防止一个下游故障把整个调用链拖垮。
降级,是熔断后或压力过高时执行的兜底逻辑。比如查库存失败,先返回一个缓存库存;支付服务不可用,先返回“稍后重试”。降级不追求完全正确,追求的是在故障时让系统还能给出一个可用结果。
一句话概括:限流管入口,熔断管出口,降级管失败后的表现。
1.3 Sentinel 和常见限流方案比,差异在哪
很多人问“Redis 限流功能怎么实现”,也确实会自己做一套:incr + expire做固定窗口,zset做滑动窗口,Lua 脚本做令牌桶。这些都是可行方案,在网关层、单机工具里很实用。
但 Sentinel 和它们的定位不完全一样。
Redis 限流更偏向全局计数、简单计数器,适合做跨多实例的“总量控制”。Sentinel 更偏向业务侧的精细化保护,它关心的不只是“每秒进来多少”,还包括某个方法调用是否异常、某个资源是否慢、某个下游是否应该熔断、当前系统负载是否过高。
差异点可以列成这几点:
- 资源粒度不同。可以给一个 URL 限流,也可以给一个方法、一个业务操作限流。
- 规则类型不同。支持流控规则、熔断规则、热点参数规则、系统保护规则、授权规则。
- 有控制台。可以看到每个资源的实时 QPS、RT、异常数,也能动态改规则。
- 和 Spring Cloud 生态集成好。可以配合 Nacos、Apollo 做规则持久化。
- 有结果兜底。被限流后可以返回自己的 block 逻辑,而不是直接抛异常。
所以实际项目里常见组合是:网关层用 Nginx 或网关限流做第一道防线,业务层用 Sentinel 做接口和依赖保护,某些跨实例的全局计数再用 Redis 实现。它们不是互相替代,而是不同层级的配合。
2. 动手前先备好环境
2.1 本地验证需要准备哪些条件
第一次学 Sentinel,不需要高配置服务器,一台普通开发机就够了。重点是把环境版本理清。
这里最容易踩的坑是版本。Sentinel 在 Spring Cloud Alibaba 里有对应版本,Spring Boot 2.x、3.x 的依赖坐标也不一样。不要只看网上的一段依赖就复制,要确认你的 Spring Boot 版本能匹配。
| 验证项 | 建议 | 原因 |
|---|---|---|
| JDK | 8、11 或 17,以依赖版本要求为准 | Sentinel 是 Java 组件,运行时依赖 JDK |
| 构建工具 | Maven 3.6+ 或 Gradle 对应版本 | 引入依赖和打包需要 |
| Spring Boot | 2.x 或 3.x,匹配 Spring Cloud Alibaba 版本 | 版本不匹配会出现注入失败 |
| 本地端口 | Dashboard 占用 8080,客户端传输占用 8719 | 端口冲突会导致节点不显示 |
| 数据库 | 本地测试可以先不连 | 限流熔断不依赖数据库 |
注意:如果你用的是低版本 Spring Boot,但引入的是新版 Spring Cloud Alibaba,启动时经常报ClassNotFoundException或者NoSuchMethodError。看到这类报错,不要先怀疑 Sentinel,先看版本对照。
2.2 下载并启动 Sentinel 控制台
Sentinel 控制台是一个独立 Web 应用,你可以在官方 GitHub Releases 里下载对应 jar,也可以从 Maven 仓库找。这里不写具体版本号,因为版本更新较快,落地时以你项目的依赖版本为准。
下载完成后,放到一个独立目录,然后启动:
java -Dserver.port=8080 \ -Dcsp.sentinel.dashboard.server=localhost:8080 \ -Dproject.name=sentinel-dashboard \ -jar sentinel-dashboard.jar启动成功后在浏览器访问:
http://localhost:8080默认账号密码是sentinel / sentinel。
登录后你会看到一个空的控制台。没有应用接入前,左侧菜单里基本看不到数据。这里要说清楚:Sentinel 控制台只管展示和下发规则,真正做限流熔断的是你的业务应用。
2.3 业务应用接入 Sentinel
如果是 Spring Cloud Alibaba 项目,最常见的是引入这个依赖:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>版本一般由父工程的 Spring Cloud Alibaba BOM 统一管理,不单独写死更安全。如果你不用 Spring Cloud,只想要 Sentinel 核心能力,也可以只引sentinel-core和sentinel-transport-simple-http,但配置和规则下发达方式会更手动一些,适合偏底层的用法。
接入后配置application.yml:
spring: application: name: order-service cloud: sentinel: transport: dashboard: localhost:8080 port: 8719 eager: true server: port: 8081注意两点。
第一,spring.cloud.sentinel.transport.port: 8719是业务应用和控制台通信的端口,不是服务和服务的调用端口。假如你的机器上有多个 Sentinel 客户端,端口不能都一样。
第二,eager: true表示应用启动后主动连接控制台。如果不开启,Sentinel 的懒加载机制会等到第一次接口访问后才注册,导致你明明启动了应用,控制台里却看不到节点。
接入后启动应用,再调用任意一个接口,然后回到控制台“机器管理”页面,应该能看到order-service这个应用。如果看不到,优先确认 8719 是否被占用、应用进程是否真的起来、接口是否真的被调用过。
3. 从一个真实 Demo 跑通“先限流,再熔断”
3.1 先写一个可被 Sentinel 保护的接口
演示时可以直接在 Controller 上加@SentinelResource,给这个资源起一个稳定的资源名。
@RestController public class OrderController { @GetMapping("/order/create") @SentinelResource(value = "createOrder", blockHandler = "createOrderBlock") public String createOrder() { return "order created"; } public String createOrderBlock(BlockException ex) { return "请求太频繁,请稍后再试"; } }这里的关键点是@SentinelResource的value,它才是规则真正作用的资源名。你把规则配置在接口地址/order/create上没有用,要配置在资源名createOrder上。
blockHandler是限流或熔断后的兜底方法。方法签名要和原方法保持一致,区别是多一个BlockException参数。不写这个兜底时,请求被拦下会返回默认的Blocked by Sentinel,这个也算正常现象,不是 Bug,但生产环境建议自己提供可读的提示信息。
3.2 在控制台配置一个最简单的限流规则
登录控制台,进入左侧菜单“流量控制”,点击“新增流控规则”。
- 资源名:
createOrder - 针对来源:默认
- 阈值类型:QPS
- 单机阈值:
5 - 流控效果:直接拒绝
保存后,规则会下发到order-service。再用命令连续请求接口:
for i in $(seq 1 20); do curl -s http://localhost:8081/order/create echo "" done因为阈值只有 5 QPS,后面大部分请求会返回:
请求太频繁,请稍后再试这里要注意,普通for循环在本地可能并发不够高,但如果接口响应够快,20 次连续请求也足够触发限流。如果没触发,先看控制台“实时监控”里是否有数据,再看规则是否真正下发了。
3.3 熔断规则怎么验证
熔断规则针对的是下游调用失败,不是入口流量。为了在本地模拟,可以在接口里加一个异常分支,比如:
@GetMapping("/order/create") @SentinelResource(value = "createOrder", blockHandler = "createOrderBlock") public String createOrder() { if (System.currentTimeMillis() % 3 == 0) { throw new RuntimeException("下游服务异常"); } return "order created"; }然后在“熔断降级”菜单新增规则:
- 资源名:
createOrder - 熔断策略:异常比例
- 比例阈值:
0.5 - 最小请求数:
20 - 统计时长:
1 秒 - 熔断时长:
10 秒
当 1 秒内请求数达到 20,并且异常比例超过 50%,熔断器会打开。之后的 10 秒内,对该资源的访问会直接走blockHandler,返回“请求太频繁,请稍后再试”。
这个例子里用的是人为抛异常来模拟下游故障,真正项目里不要用异常做业务判断,而是把 Sentinel 配置在调用下游 RPC 的方法上。熔断的目标是让“调用一个不稳定服务”这个动作快速失败,而不是让它消耗资源继续等待。
3.4 怎么判断 Demo 是否成功
验证一个限流熔断 Demo,不看一条请求,看三点:
| 验证点 | 判断标准 |
|---|---|
| 是否有限流日志 | 请求被拦后,sentinel-block.log会有记录 |
| 控制台实时监控是否跳动 | 资源 QPS、RT、异常数有变化 |
| 触发和恢复是否符合预期 | 限流后恢复请求能成功,熔断窗口结束后能重新放量探测 |
如果限流规则一直不生效,优先看资源名是不是写错了。如果熔断规则不生效,先看最小请求数有没有达到,再看异常比例阈值是否合理。
4. 关键参数和判断标准
4.1 流控规则参数别乱调
流量控制规则里,最常用的字段是这几个。
| 参数 | 含义 | 常见配置建议 |
|---|---|---|
| resource | 被保护的资源名 | 和@SentinelResource的 value 保持一致 |
| grade | 阈值类型,QPS 或并发线程数 | 入口接口用 QPS,线程池紧张时关注并发线程数 |
| count | 阈值大小 | 根据压测结果设置,不要拍脑袋 |
| controlBehavior | 流控效果,直接拒绝、预热、排队 | 普通接口直接拒绝,突发热点用预热 |
| warmUpPeriodSec | 预热时长 | 适合缓存刚启动、加载慢的场景 |
| maxQueueingTimeMs | 排队等待最大时长 | 适合允许延迟的写操作,但不适合高并发读接口 |
我一般建议刚开始只用“直接拒绝 + QPS”组合。这个组合最容易观察,出现限流也最直观。预热和排队需要更细的容量评估,不要一上来就开。
判断一个接口阈值是否合理,可以分三步:
- 先压测得到单机稳定 QPS。
- 取稳定值的 70% 到 80% 作为限流阈值。
- 灰度观察误杀比例,再慢慢调整。
只调大阈值不压测,限流就成了摆设。阈值太低又会把正常用户挡住,所以每个接口最好单独评估,不要所有接口共用一个值。
4.2 熔断规则重点看半开恢复
熔断规则有几种维度:慢调用比例、异常比例、异常数。配置时先看清当前规则需要填的是 RT 阈值还是比例阈值。
| 参数 | 作用 |
|---|---|
| 统计时长 | 在多久时间窗口内做统计 |
| 最小请求数 | 请求量太小时不触发熔断,避免偶发异常误伤 |
| 比例阈值 | 异常比例或慢调用比例达到多少开始熔断 |
| 熔断时长 | 熔断打开后,持续多久不调用下游 |
| 半开探测 | 熔断时间结束后,放少量请求试水,成功则恢复,失败则继续熔断 |
这里最容易被忽略的是“最小请求数”。如果一个接口平时请求量很低,偶发一次异常就熔断,会导致服务频繁断开。设置最小请求数,是为了让熔断建立在足够的样本上。
熔断恢复不是“到了时间就一定恢复”。到了时间窗口后,Sentinel 会进入半开状态,放少量请求过去。如果下游还是失败,熔断会再次打开。所以排查“熔断恢复不了”时,先看下游到底恢复没有,再看规则里的时间内和探测请求是否合理。
4.3 热点参数规则和系统保护规则
除了普通流控和熔断,Sentinel 还支持热点参数规则和系统保护规则。
热点参数规则适合这种情况:同一个接口,不同参数维度的流量差异很大。比如秒杀场景下,商品 A 的请求量远高于商品 B,你不能只给整个接口限流,因为整体限流会把商品 B 的正常流量也挡住。热点参数规则可以针对某个参数值单独设阈值,比如 userId 维度、商品 skuId 维度,做到精准控制。
系统保护规则基于整体系统指标,比如 CPU 使用率、系统 Load、平均 RT、入口 QPS、线程数。这类规则适合放在入口资源上,防止单个接口的流量把整台机器拖垮。
对新手来说,先不要急着配系统保护规则。系统规则触发后影响范围很大,如果阈值设得太低,会出现“所有接口都被拦”的误伤。先从单接口的 QPS 流控和异常比例熔断开始,跑稳定了再往上加系统保护。
5. 批量服务场景下的接入注意事项
5.1 每个实例的限流状态是独立的
这是一个非常重要、但很多人会忽略的点。
Sentinel 默认的限流阈值是“单机维度”,不是集群总量。假如订单服务有 4 个实例,每台实例配置 QPS 为 100,那系统整体最多能放 400 进来,不是 100。
如果你的目的是保护某一台实例不被打满,单机维度是对的。如果目的是控制某个接口的总流量,比如上游渠道最多只能承受 200 QPS,那不能只靠单机规则凑,需要做集群流控或借助网关、Redis 做全局计数。
所以接入之前要先想清楚:你要限制的是单台能力,还是服务整体能力?这个判断错了,规则再多也没用。
5.2 规则不能只写在控制台
通过控制台配置规则很方便,问题在于规则是存在内存里的。应用重启后,控制台手动添加的规则会丢失。
生产环境更稳妥的做法是把规则放到配置中心,比如 Nacos、Apollo、Zookeeper。Sentinel 支持通过数据源动态拉取规则。以 Nacos 为例,常见配置思路是:
spring: cloud: sentinel: datasource: flow: nacos: server-addr: 127.0.0.1:8848 dataId: order-service-flow-rules groupId: DEFAULT_GROUP rule-type: flowrule-type可以是flow、degrade、system、authority、param-flow,分别对应不同类型规则。这样规则变更走配置中心,应用能实时收到更新,重启也不会丢。
这里不建议把规则改成代码里直接写死。代码写规则适合学习 Demo,生产环境下一旦阈值要调整,你总不能为了改一个数字重新发一次版本。
5.3 日志、监控和告警要提前接好
Sentinel 会输出一些关键日志,默认路径一般在用户目录下的logs/csp里:
${user.home}/logs/csp/sentinel-block.log ${user.home}/logs/csp/sentinel-record.logsentinel-block.log记录了所有被限流、熔断、系统保护拦截的请求。遇到线上问题,先看这个日志,能直接告诉你拦截原因,比自己猜要快得多。
控制台适合观察实时指标,但不太适合做长期监控。生产环境建议:
- 把 block 日志接入统一的日志平台。
- 对关键资源的 QPS、异常比例、熔断次数做好监控告警。
- 规则变更要有记录,避免有人偷偷调大阈值后出问题。
接入 Sentinel 不是把依赖引进来就结束了。日志、监控、告警、规则持久化,这些才是一个流量治理组件是否真正落地的标准。
6. 常见报错和排查顺序
6.1 为什么显示 Blocked by Sentinel,但 QPS 阈值没到?
这个问题很常见,但不一定是流控规则误判。
Blocked by Sentinel是 Sentinel 在没配置兜底方法时的默认返回。它可能来自多种规则:
- 流量控制规则
- 熔断降级规则
- 热点参数规则
- 系统保护规则
- 授权规则
比如你只配置了 QPS 限流 5,如果当前机器的 CPU Load 很高,系统保护规则可能先触发。又比如接口有异常比例熔断,请求不是被限流拦的,而是被熔断拦的,但返回文本都是同一个。
排查时先看sentinel-block.log,里面会记录被拦截资源的名称和拦截规则类型,比看返回内容准确。
6.2 控制台看不到应用节点
出现这个现象,按顺序排查:
- 应用是否真的启动了,启动日志里有没有报错。
- 是否调用了接口,Sentinel 懒加载,没调用就不注册。
- 客户端通信端口 8719 是否被占用。
- 控制台地址配置是否正确,不是把
spring.cloud.sentinel.transport.dashboard配成自己的业务端口。 - 防火墙是否拦截了 8080 和 8719。
最容易被忽略的是第二点:应用启动后,你只是登录了控制台,但业务应用没产生任何流量,控制台里当然没有节点。先访问一次接口,再回控制台刷新。
6.3 熔断一直不恢复
熔断一直不恢复,原因通常有两种。
一种是下游服务确实还没恢复。半开探测的请求依然失败,熔断器会再次打开,这是正常表现。你要做的是去修下游,而不是改大熔断时长。
另一种是规则统计问题。比如最小请求数设置太高,导致熔断状态判断不准确;或者统计时长太短,样本不稳定。
遇到这种情况,不建议直接删规则。先看下游成功率,再看 block 日志里的触发时间,最后再调参数。
6.4 排查顺序不要乱
遇到 Sentinel 相关问题,我建议按这个顺序来:
- 先看现象:是返回了 block 文案,还是接口超时,还是服务直接启动失败?
- 再找日志:优先看
sentinel-block.log,然后是应用日志。 - 再看资源名:规则里的 resource 和代码里的资源名是否一致,这是最常见的低级错误。
- 再看阈值类型:是 QPS 还是并发线程数,是异常比例还是慢调用比例,别只改 count。
- 再看环境:实例数量、端口、配置中心是否连上。
- 最后才怀疑工具本身。
实际踩过几次之后就会发现,很多问题不是 Sentinel 功能不行,而是资源名写错了、规则没持久化、版本不匹配、端口被占用这些外围因素。
限流和熔断不是越严越好。阈值设得太低,正常用户会被误杀;设得太高,服务该保护的时候保护不住。实际落地时,我一般会先用压测把单机上限摸出来,再按 70% 到 80% 的容量设置限流阈值,熔断则优先关注异常比例和慢调用。先把一条资源调稳,再复制到其他接口。如果你的服务还在单机阶段,可以先用 Redis 简单计数或者网关层限制;一旦进入微服务架构、服务间调用变多,再上 Sentinel 这类组件,价值会明显很多。