一、前言
在微服务架构中,流量突增、下游服务超时、报错雪崩是线上最常见的稳定性问题。Sentinel作为阿里开源、经过双11大促打磨的流量防护组件,相比 Hystrix 更轻量、功能更强、配置更灵活,是目前国内微服务限流、熔断、降级的主流方案。
本文带来零残缺、可直接运行、可上线的 Sentinel 完整实战案例,包含:
- blockHandler / fallback 精准区分(面试高频)
二、核心核心概念
1. 兜底方法区别
- blockHandler:Sentinel 框架拦截异常,只处理限流、熔断、系统保护、黑白名单拦截触发的BlockException。
- fallback:捕获业务代码所有异常,包含空指针、自定义异常、接口报错等业务异常。
2. 核心能力
- 限流:QPS 限流、并发线程限流、链路限流、热点参数限流
三、环境与依赖
适配版本:SpringBoot 2.7.x + SpringCloud Alibaba 2021.0.1.0(稳定生产版本)
完整 pom.xml 依赖
xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.15</version> <relativePath/> </parent>
<dependencies> <!-- Spring Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<!-- Sentinel 流量防护核心依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2021.0.1.0</version> </dependency>
<!-- Nacos 配置中心(用于规则持久化,生产必备) --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2021.0.1.0</version> </dependency>
<!-- OpenFeign 远程调用 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> |
四、项目配置文件 application.yml
配置控制台地址、开启服务预热初始化,适配开发、生产环境
yaml server: port: 8080
spring: application: name: sentinel-demo-service cloud: sentinel: # Sentinel 控制台地址 transport: dashboard: 127.0.0.1:8085 port: 8719 # 关闭懒加载,项目启动直接初始化Sentinel eager: true nacos: config: server-addr: 127.0.0.1:8848
# 开启feign对sentinel的支持 feign: sentinel: enabled: true |
五、启动类
java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication @EnableFeignClients public class SentinelDemoApplication { public static void main(String[] args) { SpringApplication.run(SentinelDemoApplication.class, args); } } |
六、核心业务代码(限流+熔断+双兜底完整实现)
统一资源名,区分限流熔断兜底、业务异常兜底,代码完全解耦,符合生产规范。
java import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController;
@RestController public class OrderController {
/** * Sentinel 资源名:createOrder * blockHandler:限流、熔断、系统保护、授权拦截兜底(Sentinel 框架异常) * fallback:业务代码异常兜底(代码报错、自定义异常等) */ @GetMapping("/order/create/{goodsId}") @SentinelResource( value = "createOrder", blockHandler = "blockHandlerCreateOrder", fallback = "fallbackCreateOrder" ) public String createOrder(@PathVariable Long goodsId) { // 模拟业务异常场景:商品999无库存 if (goodsId == 999) { throw new RuntimeException("商品库存不足,下单失败"); }
// 模拟慢接口(用于测试慢调用比例熔断) try { Thread.sleep(300); } catch (InterruptedException e) { throw new RuntimeException(e); }
return "下单成功,商品ID:" + goodsId; }
/** * 限流、熔断兜底方法 * 规则:参数与原方法一致,最后追加 BlockException */ public String blockHandlerCreateOrder(Long goodsId, BlockException ex) { // 区分限流、熔断异常,返回精准提示 if (ex instanceof com.alibaba.csp.sentinel.slots.block.flow.FlowException) { return "【限流兜底】当前下单人数过多,请稍后重试"; } else if (ex instanceof com.alibaba.csp.sentinel.slots.block.degrade.DegradeException) { return "【熔断兜底】服务暂时繁忙,已开启熔断保护,请稍后重试"; } else { return "【服务防护拦截】请求被限制:" + ex.getClass().getSimpleName(); } }
/** * 业务异常兜底方法 * 捕获所有业务代码异常 */ public String fallbackCreateOrder(Long goodsId, Throwable throwable) { return "【业务异常兜底】商品" + goodsId + "下单失败:" + throwable.getMessage(); } } |
七、全局异常处理器(生产核心:返回429/503标准状态码)
这是跨服务调用能识别限流/熔断的关键:
1. 限流异常FlowException→ 返回 HTTP 429
2. 熔断异常DegradeException→ 返回 HTTP 503
上游 A 服务可通过状态码精准区分「下游限流」还是「下游熔断」
java import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice public class SentinelGlobalExceptionHandler {
/** * 下游触发限流:429 Too Many Requests */ @ExceptionHandler(FlowException.class) @ResponseStatus(HttpStatus.TOO_MANY_REQUESTS) public String handleFlowException(FlowException e) { return "下游服务触发限流:请求过于频繁,请稍后重试"; }
/** * 下游触发熔断:503 Service Unavailable */ @ExceptionHandler(DegradeException.class) @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE) public String handleDegradeException(DegradeException e) { return "下游服务触发熔断:服务暂时不可用,已开启故障隔离"; }
/** * 通用Sentinel拦截异常 */ @ExceptionHandler(BlockException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleBlockException(BlockException e) { return "服务流量拦截:" + e.getMessage(); } } |
八、OpenFeign 跨服务调用(A服务调用B服务,精准识别限流/熔断)
场景说明
微服务最经典场景:A服务 OpenFeign 调用 B服务
B服务接口被 Sentinel 限流/熔断后,抛出对应异常,经过全局异常处理器返回标准 HTTP 状态码,A服务可精准捕获、区分限流/熔断/普通报错,做差异化降级策略。
1. Feign客户端定义(A服务)
java import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "sentinel-demo-service") public interface BOrderFeignClient {
@GetMapping("/order/create/{goodsId}") String createOrder(@PathVariable("goodsId") Long goodsId); } |
2. A服务调用代码(核心:区分429限流 / 503熔断)
java import feign.FeignException; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource;
@Slf4j @RestController public class AInvokeBController {
@Resource private BOrderFeignClient bOrderFeignClient;
@GetMapping("/a/call/b/{goodsId}") public String aCallB(@PathVariable Long goodsId) { try { // A服务远程调用B服务带Sentinel防护的接口 return bOrderFeignClient.createOrder(goodsId); } catch (FeignException e) { // 通过HTTP状态码精准区分下游异常类型 int status = e.status(); if (status == 429) { // 下游B服务触发限流 log.warn("【跨服务降级】B服务接口限流,goodsId:{}", goodsId); return "系统繁忙,当前访问人数过多,请稍后重试(限流降级)"; } else if (status == 503) { // 下游B服务触发熔断 log.error("【跨服务熔断】B服务接口熔断,服务暂时不可用,goodsId:{}", goodsId); return "服务暂时异常,已开启熔断保护,请稍后重试(熔断降级)"; } else { // 其他业务异常 log.error("【远程调用异常】未知错误:{}", e.getMessage()); return "服务调用异常,请稍后重试"; } } } } |
九、规则配置方式一:代码硬编码(快速测试)
无需控制台,项目启动自动加载限流、熔断规则,适合单元测试、快速验证场景。
java import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List;
@Configuration public class SentinelRuleConfig {
// 与接口资源名保持一致 private static final String RESOURCE = "createOrder";
@PostConstruct public void initSentinelRule() { // 1. 限流规则:QPS单机阈值2,每秒最多2次请求 List<FlowRule> flowRuleList = new ArrayList<>(); FlowRule flowRule = new FlowRule(); flowRule.setResource(RESOURCE); // 限流维度:QPS flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 阈值 flowRule.setCount(2); // 流控效果:快速失败 flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); flowRuleList.add(flowRule); FlowRuleManager.loadRules(flowRuleList);
// 2. 熔断规则:慢调用比例熔断 List<DegradeRule> degradeRuleList = new ArrayList<>(); DegradeRule degradeRule = new DegradeRule(); degradeRule.setResource(RESOURCE); // 熔断策略:慢调用RT degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT); // 超过250ms判定为慢调用 degradeRule.setCount(250); // 慢调用比例超过50%触发熔断 degradeRule.setSlowRatioThreshold(0.5); // 最小统计请求数 degradeRule.setMinRequestAmount(5); // 熔断窗口期5秒,期间直接降级 degradeRule.setTimeWindow(5); degradeRuleList.add(degradeRule); DegradeRuleManager.loadRules(degradeRuleList); } } |
十、规则配置方式二:Sentinel 控制台动态配置(生产推荐)
1. 启动控制台
下载 sentinel-dashboard-1.8.8.jar,执行启动命令:
shell java -jar sentinel-dashboard-1.8.8.jar --server.port=8085 |
访问地址:http://127.0.0.1:8085,默认账号密码:sentinel / sentinel
2. 配置流控规则
3. 配置熔断降级规则
十一、完整测试场景(含跨服务调用)
1. 本地接口限流测试
快速高频访问:http://localhost:8080/order/create/1
每秒请求超过2次,触发限流,返回429提示信息。
2. 业务异常 fallback 测试
访问:http://localhost:8080/order/create/999
代码主动抛出业务异常,触发 fallback 兜底。
3. 跨服务限流识别测试(A调B)
高频访问:http://localhost:8080/a/call/b/1
B服务触发限流后返回429,A服务捕获状态码,执行限流专属降级逻辑。
4. 跨服务熔断识别测试(A调B)
批量并发请求接口,触发B服务慢调用熔断,B返回503,A服务捕获后执行熔断专属降级逻辑,不再重试。
十二、生产核心规范与避坑总结
1. 方法签名硬性规则
- blockHandler 方法:参数必须和原方法一致,末尾必须追加BlockException
- fallback 方法:参数同原方法,可追加Throwable捕获所有异常
2. 跨服务调用核心规范(重点)
- 限流=429:服务正常、流量打满,可短时重试、排队、友好提示
- 熔断=503:服务异常隔离,禁止重试,直接走本地兜底/缓存
- 禁止统一返回200状态码+业务码,会导致上游无法精准区分故障类型,丢失降级策略
Feign 底层逻辑:
只要 HTTP 状态码 不是 200~299,不会把 body 正常返回,直接抛出 FeignException;
FeignException 内部会保存原始 HTTP 状态码,通过 e.status() 获取。
3. 生产建议
- 禁止使用代码硬编码规则,务必使用Nacos 持久化规则,支持动态修改、集群统一生效
- 核心接口配置限流+熔断双重防护,非核心接口可只配置限流
- 统一 429/503 状态码规范,统一上下游降级逻辑
- 开启 Sentinel 监控日志,线上快速定位流量、熔断异常
十三、总结
本文实现了零缺失、可直接投产的 Sentinel 限流熔断完整案例,覆盖本地接口防护 + OpenFeign跨服务调用、上下游异常识别、差异化降级全场景,厘清了blockHandler、fallback、限流熔断跨服务传递的核心原理。
Sentinel 凭借轻量、高可用、功能丰富的特性,完全可以替代 Hystrix,作为微服务稳定性防护的核心组件,是中高级开发必备的技术栈。