Sentinel从入门到实战:流量卫兵守护你的微服务
一、为什么需要限流组件?
在分布式系统和微服务架构日益普及的今天,流量控制已经成为保障系统稳定性的核心手段。让我们先看一个真实的生产案例:
1.1 真实案例:某电商平台崩溃事故
2023年双11大促期间,某中型电商平台在秒杀活动开启后5分钟内系统全面崩溃。事后分析发现:
- 流量峰值:正常QPS约500,秒杀开始瞬间飙升至50000+
- 系统表现:所有服务实例CPU 100%,内存溢出,数据库连接池耗尽
- 影响范围:不仅秒杀服务崩溃,连带影响首页、浏览、下单等所有核心功能
- 直接损失:约300万交易额无法完成,品牌声誉受损
无限流保护的系统
图1:无限流保护的系统架构 - 流量冲击场景
如上图所示,没有限流保护的系统面临多重问题:
① 资源耗尽问题当突发流量到来时,系统会按照"先来先服务"的原则处理请求。流量超出系统承载能力后:
- CPU持续高负载,上下文切换频繁
- 内存快速分配导致GC压力增大,最终OOM
- 数据库连接池被占满,新请求无法获取连接
② 雪崩效应微服务架构中,服务间存在依赖关系。当下游服务因流量过大而响应缓慢或失败时:
- 上游服务持有的连接/线程无法释放,资源逐渐耗尽
- 故障会沿着调用链向上传播,最终导致整个系统崩溃
- 一个服务的故障可能影响整个业务链路
③ 用户体验恶化
- 正常用户的请求无法得到及时响应
- 页面长时间加载或直接报错
- 用户流失,信任度下降
1.2 传统解决方案的局限性
面对流量冲击,传统方案通常包括:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 垂直扩容 | 简单直接 | 成本高,有上限,无法应对瞬时流量 |
| 缓存 | 减轻数据库压力 | 缓存击穿/穿透/雪崩问题,热点数据难以处理 |
| 消息队列 | 削峰填谷 | 增加系统复杂度,实时性下降 |
| 人工限流 | 灵活性高 | 响应慢,无法精确控制,容易误操作 |
这些方案要么成本过高,要么效果有限,要么需要大量人力投入。我们需要一个更加智能化、自动化的流量控制解决方案。
二、Sentinel简介
2.1 Sentinel是什么?
Sentinel是阿里巴巴开源的一款面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助您保障微服务的稳定性。
Sentinel系统架构
2.2 核心特性
① 丰富的应用场景
- 秒杀系统:瞬间大流量限流
- 消息削峰:平滑处理突发流量
- 熔断降级:保护核心服务不被拖垮
- 实时监控:全方位流量监控大盘
② 完备的实时监控Sentinel提供实时的监控功能,可以监控:
- QPS(每秒查询数)
- RT(响应时间)
- 成功率
- 拒绝数
③ 广泛的开源生态Sentinel提供与主流框架的整合:
- Spring Cloud / Spring Boot
- Dubbo
- gRPC
- RocketMQ
④ 完善的SPI扩展点Sentinel提供简单易用、完善的SPI扩展接口,可以通过实现扩展接口来快速定制逻辑。
三、Sentinel核心原理
3.1 责任链模式设计
Sentinel的核心工作原理基于责任链模式,通过一系列的Slot(槽位)串联成一个处理链。
Sentinel核心原理
图3:Sentinel核心工作原理
当请求进入时,会依次经过以下Slot:
① NodeSelectorSlot
- 负责收集资源的调用路径
- 构建树状结构的调用链路
- 为每个资源创建DefaultNode
② ClusterBuilderSlot
- 构建ClusterNode
- 统计集群维度某个资源的调用情况
- 用于存储聚合后的统计信息
③ LogSlot
- 记录异常日志
- 便于问题排查和定位
④ StatisticSlot
- 实时统计指标的Slot
- 记录秒级、分钟级的指标数据
- 为后续的规则判断提供数据支撑
⑤ AuthoritySlot
- 黑白名单控制
- 基于来源的流量控制
⑥ FlowSlot
- 流量控制Slot
- 根据配置的限流规则进行判断
- 超出阈值则抛出FlowException
⑦ DegradeSlot
- 熔断降级Slot
- 根据熔断规则判断是否需要熔断
- 触发熔断则抛出DegradeException
3.2 核心概念
① 资源(Resource)资源是Sentinel的核心概念,可以是:
- Java代码中的一段代码
- 一个接口
- 一个方法
// 定义资源方式一:使用@SentinelResource注解 @SentinelResource(value = "getUserInfo", blockHandler = "handleBlock") public User getUserInfo(Long id) { return userService.getUser(id); } // 定义资源方式二:使用try-catch try (Entry entry = SphU.entry("getUserInfo")) { return userService.getUser(id); } catch (BlockException e) { return handleBlock(e); }② 规则(Rule)Sentinel支持多种规则类型:
| 规则类型 | 说明 | 配置参数 |
|---|---|---|
| FlowRule | 流量控制规则 | resource, limitApp, grade, count, strategy, controlBehavior |
| DegradeRule | 熔断降级规则 | resource, grade, count, timeWindow, minRequestAmount |
| AuthorityRule | 访问控制规则 | resource, limitApp, strategy |
| ParamFlowRule | 热点参数规则 | resource, paramIdx, grade, count, durationInSec |
③ 上下文(Context)Context保存了调用链路的元数据,包括:
- 入口节点(EntranceNode)
- 当前节点(CurrentNode)
- 调用来源(Origin)
四、流量控制详解
4.1 限流流程
Sentinel的限流处理流程如下图所示:
限流流程
图4:Sentinel限流处理流程
4.2 限流维度
① QPS限流每秒查询数限流,适用于:
- API接口限流
- 防止接口被刷
- 保护下游服务
// QPS限流配置 List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(); rule.setResource("getUserInfo"); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS维度 rule.setCount(100); // 每秒最多100个请求 rule.setStrategy(RuleConstant.STRATEGY_DIRECT); // 直接拒绝 rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 默认行为 rules.add(rule); FlowRuleManager.loadRules(rules);② 线程数限流并发线程数限流,适用于:
- 业务处理时间长
- 需要限制并发量的场景
// 线程数限流配置 FlowRule rule = new FlowRule(); rule.setResource("processOrder"); rule.setGrade(RuleConstant.FLOW_GRADE_THREAD); // 线程数维度 rule.setCount(10); // 最多10个线程并发处理4.3 限流策略
① 直接拒绝(Default)默认策略,超出阈值直接拒绝请求:
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 抛出FlowException: Blocked by Sentinel (flow limiting)② Warm Up(预热)从初始阈值缓慢上升到最大阈值:
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP); rule.setCount(100); // 最大阈值 rule.setWarmUpPeriodSec(10); // 预热时长10秒 // 实际效果:前10秒从 100/3 ≈ 33 逐渐增加到100适用于:
- 秒杀系统预热
- 缓存预热
- 系统启动阶段流量控制
③ 排队等待(Throttling)请求在队列中排队,超时则拒绝:
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER); rule.setCount(100); // 每秒100个请求 rule.setMaxQueueingTimeMs(500); // 最大排队等待时间500ms适用于:
- 消息削峰填谷
- 请求可以适当延迟处理的场景
4.4 关联限流
当关联的资源达到阈值时,对当前资源限流:
// 当userLogin资源QPS超过50时,限制getUserInfo rule.setStrategy(RuleConstant.STRATEGY_RELATE); rule.setRefResource("userLogin"); rule.setCount(50);适用场景:
- 登录接口压力大时,限制其他非核心接口
- 支付接口压力大时,限制下单接口
五、熔断降级详解
5.1 熔断机制
熔断器模式(Circuit Breaker Pattern)是一种保护性设计模式,Sentinel实现了完整的熔断降级机制。
熔断机制降级机制
图5:Sentinel熔断降级机制
熔断器有三种状态:
① Closed(关闭状态)
- 正常状态,请求正常通过
- 监控失败率和响应时间
- 异常达到阈值时,转换为Open状态
② Open(开启状态)
- 熔断状态,直接拒绝所有请求
- 持续熔断时长(timeWindow)结束后进入Half-Open状态
③ Half-Open(半开状态)
- 探测状态,允许部分请求通过
- 如果请求成功,说明服务已恢复,转为Closed状态
- 如果请求失败,说明服务仍未恢复,转回Open状态
5.2 熔断策略
① 慢调用比例(SLOW_REQUEST_RATIO)
当资源的响应时间超过最大RT时,被标记为慢调用。慢调用比例超过阈值时触发熔断:
List<DegradeRule> rules = new ArrayList<>(); DegradeRule rule = new DegradeRule(); rule.setResource("orderService"); rule.setGrade(RuleConstant.DEGRADE_GRADE_SLOW_REQUEST_RATIO); rule.setCount(500); // 慢调用阈值:RT > 500ms rule.setSlowRatioThreshold(0.5); // 慢调用比例阈值:50% rule.setTimeWindow(10); // 熔断时长:10秒 rule.setMinRequestAmount(5); // 最小请求数:5 rule.setStatIntervalMs(1000); // 统计时长:1秒 rules.add(rule); DegradeRuleManager.loadRules(rules);② 异常比例(EXCEPTION_RATIO)
当资源的异常比例超过阈值时触发熔断:
DegradeRule rule = new DegradeRule(); rule.setResource("paymentService"); rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); rule.setCount(0.5); // 异常比例阈值:50% rule.setTimeWindow(10); // 熔断时长:10秒 rule.setMinRequestAmount(5); // 最小请求数:5③ 异常数(EXCEPTION_COUNT)
当资源的异常数超过阈值时触发熔断:
DegradeRule rule = new DegradeRule(); rule.setResource("smsService"); rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT); rule.setCount(10); // 异常数阈值:10个 rule.setTimeWindow(10); // 熔断时长:10秒 rule.setMinRequestAmount(5); // 最小请求数:55.3 降级处理
当请求被限流或熔断时,需要进行降级处理:
@SentinelResource( value = "getUserInfo", blockHandler = "handleBlock", // 限流/熔断时的处理 fallback = "handleFallback" // 异常时的处理 ) public User getUserInfo(Long id) { return userService.getUser(id); } // 限流/熔断处理 public User handleBlock(Long id, BlockException e) { // 返回默认值或缓存数据 return User.getDefaultUser(); } // 异常处理 public User handleFallback(Long id, Throwable e) { log.error("获取用户信息异常", e); return User.getDefaultUser(); }六、生产实战案例
6.1 电商秒杀系统
以下是一个电商秒杀系统使用Sentinel的完整案例:
生产实战案例
图6:生产实战:电商秒杀系统Sentinel应用架构
场景描述:
- 正常流量:约2000 QPS
- 秒杀流量:峰值可达50000+ QPS
- 核心需求:保护库存服务不被击垮
配置方案:
@Configuration public class SentinelConfig { @PostConstruct public void initRules() { initSeckillFlowRules(); initOrderDegradeRules(); initStockFlowRules(); } /** * 秒杀接口限流规则 */ private void initSeckillFlowRules() { List<FlowRule> rules = new ArrayList<>(); // 用户维度限流 FlowRule userRule = new FlowRule(); userRule.setResource("seckill:userId"); userRule.setGrade(RuleConstant.FLOW_GRADE_QPS); userRule.setCount(5); // 单用户每秒最多5次请求 userRule.setParamIdx(0); // 第一个参数作为userId rules.add(userRule); // 接口维度限流 FlowRule apiRule = new FlowRule(); apiRule.setResource("/api/seckill/doSeckill"); apiRule.setGrade(RuleConstant.FLOW_GRADE_QPS); apiRule.setCount(10000); // 接口整体限制10000 QPS apiRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP); apiRule.setWarmUpPeriodSec(10); // 10秒预热 rules.add(apiRule); FlowRuleManager.loadRules(rules); } /** * 订单服务熔断规则 */ private void initOrderDegradeRules() { List<DegradeRule> rules = new ArrayList<>(); DegradeRule rule = new DegradeRule(); rule.setResource("orderService:createOrder"); rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); rule.setCount(0.3); // 异常比例30% rule.setTimeWindow(10); // 熔断10秒 rule.setMinRequestAmount(10); rules.add(rule); DegradeRuleManager.loadRules(rules); } /** * 库存服务限流规则 */ private void initStockFlowRules() { List<FlowRule> rules = new ArrayList<>(); // 线程数限流,保护数据库 FlowRule rule = new FlowRule(); rule.setResource("stockService:decreaseStock"); rule.setGrade(RuleConstant.FLOW_GRADE_THREAD); rule.setCount(100); // 最多100个线程同时操作 rules.add(rule); FlowRuleManager.loadRules(rules); } }核心接口实现:
@RestController @RequestMapping("/api/seckill") public class SeckillController { @Autowired private SeckillService seckillService; /** * 秒杀接口 */ @PostMapping("/doSeckill") @SentinelResource( value = "seckill:doSeckill", blockHandler = "handleBlock", fallback = "handleFallback" ) public Result doSeckill(@RequestParam Long userId, @RequestParam Long goodsId) { try { boolean success = seckillService.doSeckill(userId, goodsId); return success ? Result.success("秒杀成功") : Result.error("秒杀失败"); } catch (Exception e) { log.error("秒杀异常", e); return Result.error("系统繁忙,请稍后重试"); } } /** * 限流处理 */ public Result handleBlock(Long userId, Long goodsId, BlockException e) { if (e instanceof FlowException) { return Result.error("当前请求过多,请稍后再试"); } else if (e instanceof DegradeException) { return Result.error("服务暂时不可用,请稍后再试"); } return Result.error("系统繁忙"); } /** * 异常处理 */ public Result handleFallback(Long userId, Long goodsId, Throwable e) { log.error("秒杀异常: userId={}, goodsId={}", userId, goodsId, e); return Result.error("系统异常,请稍后重试"); } } @Service public class SeckillServiceImpl implements SeckillService { @Autowired private RedisTemplate redisTemplate; @Autowired private StockService stockService; @Autowired private OrderService orderService; @Override @SentinelResource( value = "seckill:doSeckill:inner", blockHandler = "handleBlock" ) public boolean doSeckill(Long userId, Long goodsId) { // 1. 校验用户是否重复购买 String key = "seckill:user:" + userId + ":goods:" + goodsId; Boolean isBought = redisTemplate.hasKey(key); if (Boolean.TRUE.equals(isBought)) { throw new BusinessException("您已经参与过此秒杀活动"); } // 2. 预扣减库存 Long stock = redisTemplate.opsForValue().decrement("seckill:stock:" + goodsId); if (stock == null || stock < 0) { redisTemplate.opsForValue().increment("seckill:stock:" + goodsId); throw new BusinessException("库存不足"); } // 3. 创建订单(可能触发熔断) try { Order order = orderService.createOrder(userId, goodsId); // 标记用户已购买 redisTemplate.opsForValue().set(key, "1", 24, TimeUnit.HOURS); return true; } catch (DegradeException e) { // 订单服务熔断,回滚库存 redisTemplate.opsForValue().increment("seckill:stock:" + goodsId); return false; } } public boolean handleBlock(Long userId, Long goodsId, BlockException e) { log.warn("秒杀请求被限流: userId={}, goodsId={}", userId, goodsId); return false; } }监控效果:
- 接口QPS被控制在10000左右
- 库存服务线程数不超过100
- 订单服务异常时自动熔断,不影响其他服务
- 系统整体可用性达到99.95%
6.2 第三方API调用保护
调用外部接口时,使用Sentinel进行保护:
@Service public class ThirdPartyServiceImpl { /** * 调用第三方支付接口 */ @SentinelResource( value = "thirdParty:payment", blockHandler = "handleBlock", fallback = "handleFallback", fallbackClass = ThirdPartyFallback.class ) public PaymentResult payment(PaymentRequest request) { try { // 调用第三方支付接口 return thirdPartyClient.payment(request); } catch (Exception e) { throw new ThirdPartyException("支付接口调用失败", e); } } public PaymentResult handleBlock(PaymentRequest request, BlockException e) { // 返回默认结果,后续异步重试 return PaymentResult.pending(); } } /** * 降级处理类 */ public class ThirdPartyFallback { public static PaymentResult handleFallback(PaymentRequest request, Throwable e) { log.error("支付接口异常,使用降级逻辑", e); // 返回降级结果,走人工处理流程 return PaymentResult.manual(); } } @Configuration public class ThirdPartySentinelConfig { @PostConstruct public void initRules() { // 慢调用熔断 DegradeRule slowRule = new DegradeRule(); slowRule.setResource("thirdParty:payment"); slowRule.setGrade(RuleConstant.DEGRADE_GRADE_SLOW_REQUEST_RATIO); slowRule.setCount(1000); // RT > 1秒 slowRule.setSlowRatioThreshold(0.5); // 50%慢调用 slowRule.setTimeWindow(30); // 熔断30秒 slowRule.setMinRequestAmount(5); // 异常比例熔断 DegradeRule exceptionRule = new DegradeRule(); exceptionRule.setResource("thirdParty:payment"); exceptionRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); exceptionRule.setCount(0.3); // 30%异常 exceptionRule.setTimeWindow(30); exceptionRule.setMinRequestAmount(5); DegradeRuleManager.loadRules(Arrays.asList(slowRule, exceptionRule)); } }6.3 系统自适应保护
Sentinel提供了系统自适应保护规则,根据系统的负载情况自动调整:
@Configuration public class SystemProtectConfig { @PostConstruct public void initSystemRules() { List<SystemRule> rules = new ArrayList<>(); // CPU使用率保护 SystemRule cpuRule = new SystemRule(); cpuRule.setHighestSystemLoad(0.8); // CPU使用率超过80%时触发 rules.add(cpuRule); // 平均RT保护 SystemRule rtRule = new SystemRule(); rtRule.setAvgRt(1000); // 平均RT超过1000ms时触发 rules.add(rtRule); // 并发线程数保护 SystemRule threadRule = new SystemRule(); threadRule.setMaxThread(500); // 并发线程超过500时触发 rules.add(threadRule); // 入口QPS保护 SystemRule qpsRule = new SystemRule(); qpsRule.setQps(10000); // QPS超过10000时触发 rules.add(qpsRule); SystemRuleManager.loadRules(rules); } }七、Sentinel Dashboard使用
7.1 Dashboard部署
# 下载Dashboard wget https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar # 启动Dashboard java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 \ -Dproject.name=sentinel-dashboard \ -jar sentinel-dashboard-1.8.6.jar7.2 客户端配置
# application.yml spring: application: name: sentinel-demo cloud: sentinel: transport: dashboard: localhost:8080 port: 8719 eager: true datasource: flow: type: file file: classpath:sentinel-flow.json degrade: type: file file: classpath:sentinel-degrade.json7.3 Dashboard功能
Dashboard提供了以下功能:
- 实时监控:查看QPS、RT、成功率等指标
- 规则配置:动态配置流控规则、熔断规则等
- 集群流控:配置集群限流
- 机器列表:查看连接到Dashboard的所有机器
八、总结
Sentinel作为一款成熟的流量控制组件,在微服务架构中发挥着重要作用:
- 核心价值
- 流量整形:平滑处理突发流量
- 服务保障:保护核心服务稳定
- 实时监控:全方位流量监控
- 快速失败:避免资源耗尽
- 适用场景
- 秒杀/抢购场景
- 第三方API调用
- 微服务链路保护
- 系统自适应保护
通过合理使用Sentinel,可以有效提升系统的稳定性和可用性,让微服务架构更加健壮。