高并发系统三大法宝:限流、熔断、降级 ,限流更是第一道防线。
线上流量突增、恶意请求、下游超时、链路雪崩......任何一种都能直接压垮服务。
而在 Java 微服务体系里,Sentinel 已经成为事实上的限流降级标准。
大多数人只停留在 @SentinelResource 简单使用,真正能吃透滑动窗口原理、流量统计模型、规则设计、生产避坑的并不多。
一、Sentinel 是什么?
Sentinel = 面向分布式服务的流量控制组件,以"流量"为切入点,保障服务稳定性。
核心能力:
- 限流(QPS/线程数)
- 熔断降级(RT/异常比例/异常数)
- 系统自适应限流
- 热点参数限流
- 黑白名单、授权控制
它不像 Hystrix 只做熔断,Sentinel 统计更精细、控制更精准、性能更高 ,单机可抗 10w+ QPS 无压力。
二、核心原理:Sentinel 整个流程是怎样的?
所有请求都会经过一条固定责任链 ProcessorSlotChain,顺序不可变:
- NodeSelectorSlot:构建资源调用链路树
- ClusterBuilderSlot:构建簇点、统计集群流量
- StatisticSlot :核心------滑动窗口实时统计
- SystemSlot:系统负载、CPU 阈值保护
- AuthoritySlot:黑白名单权限控制
- FlowSlot :限流规则判断
- DegradeSlot :熔断降级判断
任意一个 Slot 判定不通过,直接抛出 BlockException,实现快速失败。整个过程纯内存、无锁、异步统计、极高性能。
三、限流灵魂:滑动窗口实现原理
Sentinel 并没有用简单的"秒级计数器",而是使用 滑动时间窗口 LeapArray,彻底解决"边界突刺问题"。
1. 滑动窗口结构
默认规则:
- 统计周期:1s
- 拆分为 2 个样本窗口,每个 500ms
- 每个窗口记录:pass、block、RT、threadNum 等指标
结构可以理解为:
[ 窗口0 | 窗口1 ]
0~500ms 500~1000ms
2. 工作机制
- 根据当前时间戳,定位到对应小窗口
- 使用 CAS 无锁 原子递增计数
- 总 QPS = 所有窗口的和
- 时间推进时,旧窗口被重置复用
3. 为什么要滑动?
如果用固定 1s 窗口,会出现临界点突刺问题:
- 9:00:00.5 ~ 9:00:01.0 进来 1000
- 9:00:01.0 ~ 9:00:01.5 进来 1000
瞬间 2000 QPS,直接打挂服务。
滑动窗口能平滑统计,真正做到"每秒不超过阈值"。
4. 三种限流策略底层逻辑
- 控制 QPS
当前窗口总 passQPS > threshold → 直接拦截 - 控制线程数
当前并发线程数 > threshold → 拦截(适合慢调用) - 链路限流 / 关联限流
根据调用来源或关联资源判断,更细粒度控制
四、熔断降级原理
Sentinel 熔断基于三种策略:
- 平均 RT
持续 N 秒内 RT 超过阈值 → 熔断打开 - 异常比例
异常比例达到阈值 → 熔断 - 异常数
固定时间内异常数过多 → 熔断
熔断状态机:
- 关闭(Closed)
- 打开(Open)→ 直接拒绝
- 半开(Half-Open)→ 放少量请求探测,恢复则关闭
慢调用、下游不稳定、数据库抖动,都靠它保护系统。
五、SpringBoot 整合 Sentinel 实战
1. 引入 Maven
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.0.1.0</version>
</dependency>
2. 配置控制台(可视化监控)
yaml
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
web-context-unify: false
3. 代码使用(两种方式)
方式1:注解(最常用)
java
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/get")
@SentinelResource(
value = "user:get",
blockHandler = "blockHandler",
fallback = "fallback"
)
public Result get(Long id) {
// 正常业务
return Result.success();
}
// 限流/限流专用
public Result blockHandler(Long id, BlockException e) {
return Result.error("请求过于频繁,请稍后再试");
}
// 业务异常降级
public Result fallback(Long id, Throwable e) {
return Result.error("服务异常,已降级");
}
}
方式2:原生 API(底层原理)
java
try (Entry entry = SphU.entry("user:get")) {
// 业务逻辑
} catch (BlockException e) {
// 被限流/降级
}
六、热点参数限流
针对某个参数限流,比如:
- 单个用户 ID 访问频率限制
- 单个商品 ID 防刷
使用:
java
@GetMapping("/hot")
@SentinelResource("hot")
public String hot(@RequestParam("id") Long id) {
return "ok";
}
在 Sentinel 控制台配置热点规则:
- 参数索引:0
- 阈值:100 QPS
效果:同一个 id 每秒最多 100 次请求。
七、生产环境最佳实践
1. 限流规则设计原则
- 网关层:整体入口限流
- 服务层:核心接口单独限流
- 下游弱依赖:熔断降级
- 读接口:限 QPS
- 写/慢接口:限线程数
2. 线程池 + Sentinel 配合
- 高并发 I/O 接口:虚拟线程 + Sentinel
- 避免线程池耗尽 + 限流双重保护
3. 规则持久化
生产不能用内存模式,重启丢失规则。
推荐:
- Nacos 持久化
- Apollo 持久化
4. 避免无效限流
- 资源名必须统一
- 不要嵌套过多
@SentinelResource - blockHandler 必须快速返回,不要逻辑过重
5. 系统保护规则
- load 阈值
- cpu 阈值
- 平均 RT
自动保护系统,防止打满宕机。
八、典型避坑
- blockHandler 与 fallback 分不清
- blockHandler:限流、降级、系统保护触发
- fallback:业务异常触发
- 不设置规则 = 不限流
- 嵌套调用导致链路统计异常
- 网关与微服务重复限流
一般只在网关或服务其中一层做 - 规则设置过严导致正常流量被误杀
压测后再上生产阈值
九、总结
Sentinel 之所以成为微服务标配,在于:
- 滑动窗口保证统计精准
- 纯内存无锁 CAS 保证高性能
- 限流 + 熔断 + 降级 + 热点 + 系统保护一体
- 轻量级、无侵入、可监控