前言
在微服务架构中,服务之间的调用链路错综复杂。一旦某个下游服务出现响应变慢或不可用,极容易引发雪崩效应——上游服务因等待响应而线程耗尽,最终导致整个系统崩溃。
Sentinel 是阿里巴巴开源的微服务流量治理框架,提供了流量控制、熔断降级、系统自适应保护等能力,是 Spring Cloud Alibaba 体系中的核心组件。
本文将手把手带你在 Spring Boot 3.x 项目中集成 Sentinel,实现:
- ✅ 接口级别的 QPS 限流
- ✅ 基于慢调用比例的熔断降级
- ✅ 自定义 BlockException 返回结构
- ✅ Sentinel Dashboard 可视化监控
踩坑提示:Spring Boot 3.x 对应 Spring Cloud 2023.x,与 2.x 时代的配置方式有若干差异,本文会重点标注。
一、核心概念速览
在动手之前,先理清几个核心概念:
| 概念 | 说明 |
|---|---|
| 资源(Resource) | 需要保护的对象,可以是接口、方法、代码块 |
| 规则(Rule) | 针对资源的限流/熔断策略 |
| BlockException | 触发规则后抛出的异常基类 |
| Slot Chain | Sentinel 的处理链,依次经过统计、限流、熔断等 Slot |
限流(Flow Control):控制单位时间内的请求数(QPS)或并发线程数。
熔断降级(Circuit Breaker):当资源异常率或响应时间超过阈值时,自动断开调用链,返回兜底结果,防止级联故障。
二、环境准备
2.1 版本说明
JDK 21
Spring Boot 3.2.x
Spring Cloud Alibaba 2023.0.1
Sentinel 1.8.8
2.2 Maven 依赖
<!-- Spring Cloud Alibaba BOM,统一版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2023.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Sentinel Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel 对 OpenFeign 的支持(如有 Feign 调用) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
⚠️ 踩坑:Spring Boot 3.x 不再兼容
spring-cloud-starter-alibaba-sentinel2.x 版本,务必使用2023.0.x系列。
三、application.yml 配置
spring:
application:
name: sentinel-demo
cloud:
sentinel:
transport:
# Sentinel Dashboard 地址
dashboard: localhost:8080
# 本服务向 Dashboard 汇报的端口(默认 8719,多服务部署时注意区分)
port: 8719
# 饥饿加载:启动时就初始化 Sentinel,不等第一次请求
eager: true
# 开启对 Web 请求的自动拦截(默认 true)
web-context-unify: false
💡
web-context-unify: false很关键:设为false后,每个接口路径会作为独立资源统计,否则所有 web 请求会被归并到同一上下文,导致链路规则失效。
四、下载并启动 Sentinel Dashboard
Sentinel Dashboard 是一个独立的 Spring Boot 应用,用于可视化配置规则和查看实时流量。
# 下载 jar(1.8.8 版本)
wget https://github.com/alibaba/Sentinel/releases/download/1.8.8/sentinel-dashboard-1.8.8.jar
# 启动(默认端口 8080)
java -Dserver.port=8080 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard \
-jar sentinel-dashboard-1.8.8.jar
访问 http://localhost:8080,默认账号密码均为 sentinel。
五、注解方式声明资源
Sentinel 提供了 @SentinelResource 注解,非常简洁地声明受保护的资源。
5.1 基础示例
@RestController
@RequestMapping("/api/order")
public class OrderController {
@GetMapping("/{id}")
@SentinelResource(
value = "getOrderById", // 资源名称
blockHandler = "handleBlock", // 限流/熔断时的处理方法
fallback = "handleFallback" // 业务异常时的兜底方法
)
public Result<Order> getOrderById(@PathVariable Long id) {
// 模拟业务逻辑
return orderService.findById(id);
}
// blockHandler:专门处理 BlockException(限流、熔断触发时调用)
// 方法签名必须与原方法一致,末尾加 BlockException 参数
public Result<Order> handleBlock(Long id, BlockException ex) {
log.warn("资源 [getOrderById] 被限流/熔断,id={}, rule={}", id, ex.getRule());
return Result.fail(429, "服务繁忙,请稍后重试");
}
// fallback:处理业务异常(非 BlockException)
public Result<Order> handleFallback(Long id, Throwable t) {
log.error("资源 [getOrderById] 业务异常,id={}", id, t);
return Result.fail(500, "服务暂时不可用");
}
}
5.2 blockHandler 与 fallback 的区别
| 属性 | 触发场景 | 典型用途 |
|---|---|---|
blockHandler | BlockException(限流、熔断、系统保护触发) | 返回友好的限流提示 |
fallback | 任何 Throwable(业务异常、超时、NPE 等) | 通用兜底/降级 |
若同时配置,
BlockException会优先走blockHandler,业务异常走fallback。
六、流量控制规则配置
6.1 Dashboard 配置(推荐)
在 Sentinel Dashboard 中:
- 左侧导航选择你的服务
- 找到「流控规则」→「新增流控规则」
- 配置如下:
| 字段 | 示例值 | 说明 |
|---|---|---|
| 资源名 | getOrderById | 与 @SentinelResource 的 value 对应 |
| 阈值类型 | QPS | 也可选「并发线程数」 |
| 单机阈值 | 10 | 每秒最多 10 次请求 |
| 流控模式 | 直接 | 也可选「关联」或「链路」 |
| 流控效果 | 快速失败 | 也可选「Warm Up」或「排队等待」 |
6.2 代码方式配置(适合测试)
@Configuration
public class SentinelRuleConfig {
@PostConstruct
public void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("getOrderById");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 按 QPS 限流
rule.setCount(10); // QPS 阈值 10
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 快速失败
rules.add(rule);
FlowRuleManager.loadRules(rules);
log.info("Sentinel 流控规则初始化完成");
}
}
6.3 Warm Up 预热模式
对于刚启动的服务,冷启动阶段缓存未预热,突然大流量会压垮服务。Warm Up 模式可以让阈值从低到高逐渐增长:
FlowRule warmUpRule = new FlowRule();
warmUpRule.setResource("getOrderById");
warmUpRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
warmUpRule.setCount(100); // 最终目标 QPS
warmUpRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
warmUpRule.setWarmUpPeriodSec(10); // 10秒内从 33 QPS 爬升到 100
💡 Warm Up 的起始阈值为
count / coldFactor,coldFactor 默认为 3,即从100/3 ≈ 33QPS 开始预热。
七、熔断降级规则配置
Sentinel 1.8.x 支持三种熔断策略:
| 策略 | 枚举值 | 说明 |
|---|---|---|
| 慢调用比例 | SLOW_REQUEST_RATIO | 响应时间超过阈值的请求比例超标时熔断 |
| 异常比例 | EXCEPTION_RATIO | 异常请求比例超标时熔断 |
| 异常数 | EXCEPTION_COUNT | 统计周期内异常数超标时熔断 |
7.1 慢调用比例熔断(最常用)
@PostConstruct
public void initDegradeRules() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule();
rule.setResource("getOrderById");
rule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
rule.setCount(500); // 慢调用 RT 阈值:响应时间 > 500ms 视为慢调用
rule.setSlowRatioThreshold(0.5); // 慢调用比例 > 50% 时触发熔断
rule.setMinRequestAmount(5); // 最小请求数:统计窗口内至少 5 次请求才触发判断
rule.setStatIntervalMs(1000);// 统计时间窗口:1秒
rule.setTimeWindow(10); // 熔断持续时间:10秒后进入半开状态
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
7.2 熔断状态机
Sentinel 的熔断器遵循标准的三态模型:
CLOSED(关闭)
│ 异常/慢调用比例超阈值
▼
OPEN(打开)← 所有请求直接走 blockHandler
│ timeWindow 时间后
▼
HALF_OPEN(半开)← 放行一个探测请求
│ 成功 → CLOSED
│ 失败 → OPEN(重置计时)
八、全局异常处理
每个接口都写 blockHandler 太繁琐,推荐用全局处理器统一拦截 Web 层的 BlockException:
/**
* Sentinel 全局 Block 异常处理器
* 适用于 Spring MVC / Spring Boot Web 项目
*/
@Component
public class SentinelBlockExceptionHandler implements BlockExceptionHandler {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
String resourceName, BlockException ex) throws Exception {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
String message;
if (ex instanceof FlowException) {
message = "请求过于频繁,请稍后重试";
} else if (ex instanceof DegradeException) {
message = "服务降级中,请稍后再试";
} else if (ex instanceof SystemBlockException) {
message = "系统负载过高,请稍后重试";
} else {
message = "服务暂时不可用";
}
Map<String, Object> body = new LinkedHashMap<>();
body.put("code", 429);
body.put("message", message);
body.put("resource", resourceName);
body.put("timestamp", System.currentTimeMillis());
response.getWriter().write(MAPPER.writeValueAsString(body));
}
}
⚠️ Spring Boot 3.x 踩坑:
WebCallbackManager.setBlockHandler()在 3.x 中已废弃,请使用实现BlockExceptionHandler接口并注册为 Bean 的方式。
九、与 OpenFeign 集成(熔断远程调用)
当服务 A 通过 Feign 调用服务 B 时,同样需要熔断保护。
9.1 开启 Feign + Sentinel
feign:
sentinel:
enabled: true
9.2 定义 Feign 客户端与 Fallback
@FeignClient(
name = "inventory-service",
fallbackFactory = InventoryClientFallbackFactory.class
)
public interface InventoryClient {
@GetMapping("/api/inventory/{productId}")
Result<Integer> getStock(@PathVariable Long productId);
}
@Component
public class InventoryClientFallbackFactory
implements FallbackFactory<InventoryClient> {
@Override
public InventoryClient create(Throwable cause) {
return productId -> {
log.warn("库存服务调用失败,productId={},原因:{}", productId, cause.getMessage());
// 返回兜底库存数量(如 0 表示暂时无法查询)
return Result.fail(503, "库存服务暂时不可用");
};
}
}
💡 使用
FallbackFactory而非直接fallback,好处是可以拿到原始异常cause,便于日志追踪。
十、规则持久化到 Nacos
默认情况下,Sentinel 规则存储在内存中,服务重启后规则丢失。生产环境必须做规则持久化。
10.1 添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
10.2 配置 Nacos 数据源
spring:
cloud:
sentinel:
datasource:
# flow-rules 是数据源名称,可自定义
flow-rules:
nacos:
server-addr: localhost:8848
namespace: dev
group-id: SENTINEL_GROUP
data-id: ${spring.application.name}-flow-rules
rule-type: flow # 规则类型:flow / degrade / system / authority / param-flow
degrade-rules:
nacos:
server-addr: localhost:8848
namespace: dev
group-id: SENTINEL_GROUP
data-id: ${spring.application.name}-degrade-rules
rule-type: degrade
10.3 Nacos 中的规则格式(JSON)
在 Nacos 控制台创建配置,Data ID 为 sentinel-demo-flow-rules,内容:
[
{
"resource": "getOrderById",
"grade": 1,
"count": 10,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
✅ 规则持久化后,即使服务重启,从 Nacos 拉取规则后立即生效,无需重新在 Dashboard 配置。
十一、常见踩坑汇总
坑 1:@SentinelResource 不生效
原因:Sentinel 基于 AOP 实现,如果 blockHandler/fallback 方法在同一个 Bean 内通过 this.method() 调用,AOP 代理不会生效。
解决:将 blockHandler 提取到独立的类,通过 blockHandlerClass 指定:
@SentinelResource(
value = "getOrderById",
blockHandlerClass = OrderBlockHandler.class,
blockHandler = "handleBlock"
)
坑 2:流控规则对 Feign 调用不生效
原因:web-context-unify 默认为 true,所有调用归并到同一上下文。
解决:设置 spring.cloud.sentinel.web-context-unify: false。
坑 3:Dashboard 看不到服务
原因:Sentinel 客户端需要接受至少一次请求后才会向 Dashboard 注册。
解决:配置 spring.cloud.sentinel.eager: true,服务启动时主动注册。
坑 4:熔断后一直不恢复
原因:timeWindow 配置的是秒数,容易填错为毫秒。
解决:确认 timeWindow 单位是秒(如 10 表示 10 秒后尝试恢复)。
十二、完整演示效果
启动服务后,使用压测工具(如 wrk 或 Apache Bench)模拟超阈值请求:
# 使用 ab 工具,发送 100 个并发请求
ab -n 1000 -c 100 http://localhost:8080/api/order/1
当 QPS 超过 10 时,多余的请求会立即收到:
{
"code": 429,
"message": "请求过于频繁,请稍后重试",
"resource": "getOrderById",
"timestamp": 1742695200000
}
在 Sentinel Dashboard 的「实时监控」页面,可以看到通过数和拒绝数的实时曲线图。
总结
本文从零开始,完整演示了 Spring Boot 3.x 集成 Sentinel 的全过程:
| 功能 | 实现方式 |
|---|---|
| 声明受保护资源 | @SentinelResource 注解 |
| 流量控制 | FlowRule(QPS/线程数,支持 Warm Up、排队等待) |
| 熔断降级 | DegradeRule(慢调用比例、异常比例、异常数) |
| 全局异常处理 | 实现 BlockExceptionHandler 接口 |
| Feign 熔断 | FallbackFactory + feign.sentinel.enabled: true |
| 规则持久化 | Nacos 数据源,规则零丢失 |
Sentinel 是微服务稳定性治理的利器,与 Spring Boot 3.x + Spring Cloud Alibaba 的组合已经非常成熟。如果你的项目还没有引入流量治理,现在是最好的时机。
下一篇文章,我们将继续探讨 Sentinel + Gateway 网关层限流,实现统一入口的流量管控,敬请期待!
💬 如有疑问或踩到新的坑,欢迎在评论区留言交流!
⭐ 觉得有用的话,点个赞支持一下~
评论区