Appearance
Sentinel 极简教程
一、基础理论
1. 定位
- 流量控制:从 QPS / 并发线程数维度限制资源访问,防止服务被打垮。
- 熔断降级:依赖下游故障时快速失败,避免级联雪崩。
- 系统保护:根据 Load、CPU、RT 等系统指标进行自适应保护。
- 阿里开源,对标 Hystrix 且能力更强,Spring Cloud Alibaba 官方推荐。
2. 核心架构
- 核心库(Client):嵌入业务进程,通过 AOP / 拦截器统计资源指标,判断规则。
- Dashboard 控制台:可视化实时监控、动态配置规则、查看簇点链路。
- 通信机制:Client 通过 HTTP 向 Dashboard 暴露 hearts + metric 数据(端口默认
8719)。
3. 流量控制(Flow)
针对**资源(Resource)**设置限流规则,统计维度两种:
| Grade | 说明 |
|---|---|
| QPS(每秒请求数) | 最常见,超过阈值直接拦截或排队 |
| 并发线程数 | 信号量隔离,防止慢调用拖垮线程池 |
流控效果(Control Behavior):
- 快速失败:默认,直接抛
FlowException。 - Warm Up(预热):缓慢增加阈值,防止冷系统被突发流量击垮(如秒杀预热)。
- 匀速排队(Rate Limiter):严格控制请求通过的时间间隔,用于削峰填谷。
流控模式:
- 直接:当前资源达到阈值就限自己。
- 关联:当关联资源达到阈值,限流当前资源(如支付接口高并发时限制下单接口)。
- 链路:只针对从指定入口访问到本资源的流量进行限制(细粒度 API 级别)。
4. 熔断降级(Degrade)
当某个资源不稳定(慢调用或异常过多),自动熔断该资源调用。
| 统计策略 | 说明 |
|---|---|
| 慢调用比例 | 响应时间 > 慢调用 RT 阈值的请求占比超过比例,且请求数 ≥ 最小请求数 |
| 异常比例 | 异常请求占总请求的比例超过阈值,且请求数 ≥ 最小请求数 |
| 异常数 | 近 1 分钟异常数超过阈值 |
状态机:CLOSED(关闭) → OPEN(打开,熔断) → HALF_OPEN(半开,放行部分请求探测) → 恢复或重新熔断。
5. 热点参数限流(Param Flow)
针对频繁访问的热点参数值进行限流。
例如:对商品 ID 参数限流,普通商品 QPS 1000,但某个爆款商品 ID="10086" 限制 QPS 为 10。
6. 与 Hystrix 对比
| 维度 | Hystrix | Sentinel |
|---|---|---|
| 隔离策略 | 线程池隔离 | 信号量隔离(并发线程数) |
| 流控能力 | 仅熔断,无精细限流 | QPS / 并发 / 热点 / 系统级 多维限流 |
| 熔断策略 | 异常比例/数 | 慢调用比例、异常比例、异常数 |
| 动态规则 | 需依赖 Archaius | Dashboard 实时推送,天然支持动态数据源 |
| 实时监控 | Dashboard 搭建复杂 | 开箱即用,秒级监控 |
| 社区状态 | Netflix 已停更维护 | 阿里持续迭代,国内主流 |
二、工作实践(复制即用)
1. 基础依赖
xml
<!-- Sentinel + Spring Cloud -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>2. 接入 Dashboard
yaml
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8858 # 控制台地址
port: 8719 # 本地暴露给 Dashboard 通信的端口,默认8719
# 取消懒加载(可选):启动即注册,而非第一次访问才初始化
eager: true启动 Dashboard(Docker)
bash
docker run --name sentinel \
-p 8858:8858 \
-d bladex/sentinel-dashboard:1.8.6
# 账号/密码:sentinel / sentinel⚠️ 关键特性:Sentinel 属于懒加载,服务启动后必须先访问一次接口,Dashboard 才能看到该服务及规则。
3. 注解方式定义资源(最常用)
java
@RestController
public class OrderController {
/**
* value: 资源名(Dashboard 中看到的名字)
* blockHandler: 被 Sentinel 规则拦截时(限流/降级/热点)调用的方法
* fallback: 业务代码抛出异常时调用的方法
*/
@GetMapping("/order/{id}")
@SentinelResource(
value = "getOrderById",
blockHandler = "getOrderBlock",
fallback = "getOrderFallback"
)
public OrderDTO getOrder(@PathVariable Long id) {
// 模拟业务异常
if (id < 0) {
throw new IllegalArgumentException("无效订单号");
}
return new OrderDTO(id, "订单-" + id);
}
/**
* blockHandler 要求:
* 1. 返回类型与原方法一致
* 2. 参数列表在原方法基础上,最后加一个 BlockException(或其子类)
* 3. 必须与原方法在同一个类;如果在外部类,需用 blockHandlerClass 指定,且方法为 static
*/
public OrderDTO getOrderBlock(Long id, BlockException ex) {
return new OrderDTO(id, "系统繁忙,请稍后查询");
}
/**
* fallback 要求:
* 1. 返回类型与原方法一致
* 2. 参数列表在原方法基础上,最后加一个 Throwable
* 3. 负责捕获业务异常(不会捕获 BlockException)
*/
public OrderDTO getOrderFallback(Long id, Throwable ex) {
return new OrderDTO(id, "查询失败,请检查参数");
}
}4. 代码定义流控规则(单机版 / 测试用)
生产建议通过 Dashboard 或 Nacos 动态数据源 推送,避免重启丢失。
java
@Component
public class SentinelConfig {
@PostConstruct
public void initRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("getOrderById"); // 对应 @SentinelResource 的 value
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS 维度
rule.setCount(10); // 阈值:每秒 10 次
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 快速失败
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}5. 热点参数限流
java
@GetMapping("/hot")
@SentinelResource(value = "hotGood", blockHandler = "hotBlock")
public String hotGood(@RequestParam("goodId") Long goodId, @RequestParam("userId") Long userId) {
return "查询商品:" + goodId;
}
public String hotBlock(Long goodId, Long userId, BlockException ex) {
return "该商品太火爆了,请稍后再试";
}配置热点规则(代码或在 Dashboard 中配置)
java
@PostConstruct
public void initParamRule() {
ParamFlowRule rule = new ParamFlowRule("hotGood")
.setParamIdx(0) // 对第0个参数 goodId 限流
.setCount(10) // 普通阈值 QPS=10
.setDurationInSec(1);
// 针对具体参数值的特殊阈值:goodId=10086 时 QPS 限制为 1
ParamFlowItem item = new ParamFlowItem()
.setObject("10086") // 参数值(String)
.setCount(1);
rule.setParamFlowItemList(Collections.singletonList(item));
ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
}6. 熔断降级规则
java
@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(0.2); // 慢调用比例阈值 20%
rule.setSlowRatioThreshold(500); // 慢调用 RT:超过 500ms 视为慢调用
rule.setTimeWindow(10); // 熔断时长:10 秒
rule.setMinRequestAmount(5); // 熔断触发的最小请求数
rule.setStatIntervalMs(1000); // 统计时长:1 秒
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}7. 自定义统一异常返回(BlockExceptionHandler)
如果不配置,默认返回 Blocked by Sentinel (flow limiting) 页面。生产环境必须自定义 JSON:
java
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
response.setContentType("application/json;charset=utf-8");
response.setStatus(429);
String msg = "系统繁忙,请稍后再试";
if (e instanceof FlowException) {
msg = "访问过于频繁,已被限流";
} else if (e instanceof DegradeException) {
msg = "服务已熔断,请稍后再试";
} else if (e instanceof ParamFlowException) {
msg = "热点参数限流";
} else if (e instanceof SystemBlockException) {
msg = "系统保护触发";
} else if (e instanceof AuthorityException) {
msg = "没有权限访问";
response.setStatus(403);
}
response.getWriter().write("{\"code\":999,\"message\":\"" + msg + "\"}");
}
}8. Feign 整合 Sentinel(熔断降级)
开启支持
yaml
feign:
sentinel:
enabled: trueFallbackFactory(详见 OpenFeign 文档,Sentinel 触发时会走进 Fallback)
java
@FeignClient(
name = "order-service",
fallbackFactory = OrderClientFallbackFactory.class
)
public interface OrderClient { ... }9. 网关层限流(Spring Cloud Gateway)
如需网关层全局限流,需引入:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>并在 Sentinel Dashboard 的 网关流控菜单 中针对 Route ID 或 API 分组配置规则,此处不展开。
三、核心速查表
| 概念 | 说明 |
|---|---|
@SentinelResource | 定义资源名及异常回调方法 |
value | 资源唯一标识,Dashboard 中可见 |
blockHandler | 处理 BlockException(限流/降级/热点/系统保护) |
fallback | 处理业务异常(Throwable),不会处理 Sentinel 规则异常 |
blockHandlerClass | 指定外部类中的静态方法处理限流 |
FlowRule | 流控规则:QPS / 并发线程数 |
DegradeRule | 熔断规则:慢调用比例 / 异常比例 / 异常数 |
ParamFlowRule | 热点参数限流规则 |
BlockException | 所有 Sentinel 拦截异常的父类 |
SystemBlockException | 系统保护规则触发异常 |
AuthorityException | 黑白名单授权规则异常 |
| 懒加载 | Dashboard 默认需先访问资源接口,才显示监控与规则选项 |
四、排错速查
| 现象 | 解决 |
|---|---|
| Dashboard 看不到服务 | 1. 检查 spring.cloud.sentinel.transport.dashboard 配置2. 必须先访问一次接口,Sentinel 懒加载 3. 检查 8719 端口是否被占用或防火墙拦截 |
@SentinelResource 没生效 | 1. 确认引入了 spring-cloud-starter-alibaba-sentinel2. 确认类被 Spring 管理( @RestController / @Component) |
blockHandler 不触发 | 方法签名错误:必须与原方法同返回类型、同参数、末尾加 BlockException,且在同一类;若在外部类需 static + blockHandlerClass |
fallback 捕获不到限流异常 | 正确!fallback 只管业务异常,BlockException 必须由 blockHandler 处理,二者职责分离 |
| 规则重启后丢失 | 代码配置仅在内存生效;生产环境务必对接 Nacos / Apollo / ZooKeeper 等持久化数据源,或提交到 DB + ReadableDataSource |
| 规则配置未生效 | 1. 检查资源名是否完全匹配(区分大小写) 2. 检查是否被其他规则覆盖( FlowRuleManager.loadRules 是全量覆盖) |