Day 45 | Sentinel流量治理:从限流到熔断降级再到系统自适应保护

📅 2026/8/10 9:51:07
Day 45 | Sentinel流量治理:从限流到熔断降级再到系统自适应保护
专栏《Java高级进阶》90天进阶系列 版本环境Spring Boot 3.2.x Spring Cloud Alibaba 2023.0.1.0 Sentinel 1.8.6一、开篇大促那一夜限流救了我们有一年双 11公司搞了一场优惠券秒杀。接口上线前压测明明过了结果活动开始 3 分钟数据库连接池打满Redis 主节点被打到 CPU 飙到 95%整个下单链路全崩。事后看监控羊毛党的脚本和正常用户混在一起QPS 曲线像一把刀一样竖起来。我们说“下次一定要做限流。” 但限流怎么做才不算“一刀切”把所有请求都拒掉正常用户也一起骂娘。Sentinel 就是用来解决这个问题的。它不是简单的“超过阈值就 429”而是把流量当成一个立体系统来治理入口限流、链路隔离、熔断降级、热点防护、系统自适应保护一层一层把风险关在笼子里。今天这一篇把生产里用得最多的 4 个能力串起来给你一套能直接落地的代码。二、Sentinel 的设计精髓一条 Slot 责任链理解 Sentinel 最快的方式不是先背概念而是先看它的执行链。Sentinel 把每一次资源访问都抽象成一条调用链链上每个节点叫Slot槽各司其职NodeSelectorSlot按调用链路构建树方便你做链路限流。ClusterBuilderSlot统计集群维度的总流量。StatisticSlot滑动窗口计数所有限流/熔断的判断数据都来自这里。FlowSlot核心流控支持 QPS、线程数、关联、链路等多种策略。DegradeSlot熔断降级慢调用、异常比例、异常数三种触发条件。SystemSlot系统保护根据 Load、CPU、RT、线程数做入口总控。ParamFlowSlot热点参数限流针对某个参数值比如用户 ID、商品 ID做精细控制。这条链的最大好处是每一层只做一件事组合起来就是一套完整的防御体系。三、代码实战 1流量控制先学会“精准拒绝”流控是 Sentinel 最基础也最常用的能力。生产里不要一上来就全局 QPS 限流而是按资源粒度配规则。下面是一个 Spring Boot 3.2 项目的完整最小可用示例。3.1 Maven 依赖!-- Spring Boot 3.2.x 请使用 2023.0.1.0 版本 -- dependencyManagement dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version2023.0.1/version typepom/type scopeimport/scope /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version2023.0.1.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement ​ dependencies dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-sentinel/artifactId /dependency /dependencies3.2 启动时加载流控规则Configuration public class SentinelFlowConfig { ​ PostConstruct public void initRules() { ListFlowRule rules new ArrayList(); ​ // 资源名建议用 类名:方法名 或业务语义名和 SentinelResource 保持一致 FlowRule seckillRule new FlowRule(seckill:submit); seckillRule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 按 QPS 限流 seckillRule.setCount(1000); // 阈值 1000 QPS seckillRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP); seckillRule.setWarmUpPeriodSec(10); // 预热 10 秒防止冷启动瞬间打崩 seckillRule.setLimitApp(default); rules.add(seckillRule); ​ // 关联限流当查询接口流量过高时限制下单接口 FlowRule queryRelatedRule new FlowRule(order:create); queryRelatedRule.setGrade(RuleConstant.FLOW_GRADE_QPS); queryRelatedRule.setCount(500); queryRelatedRule.setStrategy(RuleConstant.STRATEGY_RELATE); queryRelatedRule.setRefResource(order:query); // 关联 order:query 资源 queryRelatedRule.setRefThreshold(2000); // order:query 超过 2000 时触发 rules.add(queryRelatedRule); ​ FlowRuleManager.loadRules(rules); } }3.3 Controller 与统一异常处理RestController RequestMapping(/seckill) public class SeckillController { ​ GetMapping(/submit) SentinelResource(value seckill:submit, blockHandler submitBlockHandler, fallback submitFallback) public String submit(RequestParam Long skuId, RequestParam Long userId) { // 真正的秒杀下单逻辑 return 下单成功sku skuId; } ​ // blockHandler仅处理 Sentinel 限流/降级抛出的 BlockException public String submitBlockHandler(Long skuId, Long userId, BlockException ex) { return 系统繁忙请稍后再试; } ​ // fallback处理业务异常如库存不足、RPC 超时 public String submitFallback(Long skuId, Long userId, Throwable ex) { return 下单失败 ex.getMessage(); } } RestControllerAdvice public class SentinelGlobalExceptionHandler { ​ ExceptionHandler(BlockException.class) public ResponseEntityString handleBlockException(BlockException e) { return ResponseEntity.status(429).body(请求过于频繁请稍后重试); } }老梁提醒blockHandler只处理 Sentinel 规则触发fallback处理业务异常。两者参数签名必须一致且最后一个是BlockException或Throwable。预热模式对秒杀场景非常有用避免流量瞬间打到最大值。四、代码实战 2熔断降级让故障“快速失败”限流是“防冲”熔断是“止损”。下游服务变慢或者疯狂报错时继续调用只会把故障放大。Sentinel 熔断有三种触发策略策略含义适用场景慢调用比例单位时间内慢调用占比超过阈值下游 RT 抖动、GC 频繁异常比例异常调用占比超过阈值下游偶发 500、网络抖动异常数异常调用次数超过阈值下游明确故障下面以保护 AI 模型调用接口为例演示慢调用比例熔断。Configuration public class SentinelDegradeConfig { ​ PostConstruct public void initDegradeRules() { ListDegradeRule rules new ArrayList(); ​ DegradeRule aiRule new DegradeRule(ai:chat); aiRule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()); // 慢调用比例 aiRule.setCount(0.5); // 慢调用比例阈值 50% aiRule.setSlowRatioThreshold(800); // 超过 800ms 算慢调用 aiRule.setTimeWindow(10); // 熔断后 10 秒内快速失败 aiRule.setMinRequestAmount(10); // 最小统计请求数避免刚启动就熔断 aiRule.setStatIntervalMs(1000); // 统计窗口 1 秒 rules.add(aiRule); ​ DegradeRuleManager.loadRules(rules); } } Service public class AiChatService { ​ private final ChatClient chatClient; ​ public AiChatService(ChatClient.Builder builder) { this.chatClient builder.build(); } ​ SentinelResource(value ai:chat, blockHandler chatBlock, fallback chatFallback) public String ask(String question) { return chatClient.prompt() .user(question) .call() .content(); } ​ public String chatBlock(String question, BlockException ex) { // 熔断或限流时直接返回本地兜底话术 return AI 服务繁忙已切换至离线模式。常见问题请查看帮助文档。; } ​ public String chatFallback(String question, Throwable ex) { // 大模型调用本身的异常 return AI 响应异常 ex.getMessage(); } }这里的关键是熔断时间窗口结束后Sentinel 会进入半开状态放少量请求试探成功后关闭熔断。不要自己写死“休眠 10 秒再恢复”那在波动环境里很容易误恢复。五、代码 3热点参数限流针对“某个用户/某个商品”精准打击全局 QPS 限流有一个问题羊毛党用 10 个账号并发每个账号请求量都不高但总量能压垮系统。热点参数限流就是来解决这种“局部热点”的。假设我们要保护一个 AI 文档摘要接口针对docId做限流同时给 VIP 用户单独配置阈值。Configuration public class SentinelParamFlowConfig { ​ PostConstruct public void initParamRules() { ListParamFlowRule rules new ArrayList(); ​ ParamFlowRule docRule new ParamFlowRule(ai:summary); docRule.setParamIdx(0); // 第 0 个参数是 docId docRule.setGrade(RuleConstant.FLOW_GRADE_QPS); docRule.setCount(10); // 默认每个 docId 10 QPS ​ // 对特定热点值单独限流docId10086 的文档被疯狂点击 ListParamFlowItem items new ArrayList(); items.add(new ParamFlowItem(10086, 2, String.class.getName())); docRule.setParamFlowItemList(items); ​ rules.add(docRule); ParamFlowRuleManager.loadRules(rules); } } RestController RequestMapping(/ai) public class AiSummaryController { GetMapping(/summary) SentinelResource(value ai:summary, blockHandler summaryBlock) public String summary(RequestParam String docId, RequestParam Long userId) { // 调用大模型生成摘要 return 这是文档 docId 的 AI 摘要……; } public String summaryBlock(String docId, Long userId, BlockException ex) { // 热点限流触发返回缓存摘要或友好提示 return 该文档当前访问火爆摘要生成排队中请 5 秒后重试; } }热点参数限流在 AI 场景特别好用同一个问题被反复问缓存没命中时可以限流保护 Token 费用。某个用户疯狂刷接口按userId限流不影响其他用户。六、系统自适应保护最后一道闸门前面都是针对单个资源做规则。但如果机器本身已经不行了——CPU 被打满、Load 飙高、线程数暴涨——再精细的规则也救不了。Sentinel 的 SystemSlot 提供了系统级保护根据当前系统负载动态控制入口总流量。 Configuration public class SentinelSystemConfig { PostConstruct public void initSystemRules() { ListSystemRule rules new ArrayList(); SystemRule rule new SystemRule(); rule.setHighestSystemLoad(8.0); // Linux Load1 超过 8 限流 rule.setHighestCpuUsage(0.8); // CPU 超过 80% 限流 rule.setMaxThread(500); // 入口线程数超过 500 限流 rule.setAvgRt(200); // 平均 RT 超过 200ms 限流 rule.setQps(5000); // 入口总 QPS 超过 5000 限流 rules.add(rule); SystemRuleManager.loadRules(rules); } }系统保护规则一般作为兜底不要和流控规则重复叠加太多否则容易出现“双重限流”导致正常流量被误杀。七、生产环境里的三条实战建议1. 规则必须持久化否则重启就丢Sentinel 默认规则放在内存里服务重启就没了。生产里一定要接 Nacos、Apollo 或者 Redis 数据源。spring: cloud: sentinel: datasource: flow: nacos: server-addr: localhost:8848 dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP rule-type: flow degrade: nacos: server-addr: localhost:8848 dataId: ${spring.application.name}-degrade-rules groupId: SENTINEL_GROUP rule-type: degrade2. 限流提示要做业务语义化不要直接抛429 Too Many Requests给前端。用户看不懂产品也骂你。统一封装成{ code: RATE_LIMITED, message: 当前排队人数较多预计等待 8 秒, retryAfter: 8 }3. 先埋点再配规则阈值是压测出来的很多团队一上来就凭感觉写count100。正确的做法是先用 Sentinel 控制台或者 Micrometer 暴露接口 QPS/RT 基线用 JMeter 压测找到拐点把阈值设在拐点 70%~80% 的位置留出缓冲。八、结尾把“防御”做成系统能力流量治理不是加几行代码的事而是一种系统能力。限流解决“谁该进”熔断解决“坏了怎么办”降级解决“还能给什么”系统保护解决“机器不行了怎么保命”。四层叠加才是真正能扛住生产风暴的架构。下一篇 Day 46我们聊一聊Spring Cloud Gateway 网关实战路由、过滤器、限流全攻略看看怎么在网关层就把坏人拦在外面。