跳到主要内容

最佳实践

本章总结了 Sentinel 在生产环境中的最佳实践,帮助你更好地使用 Sentinel 保障服务的稳定性。

整体规划

1. 分层保护策略

在生产环境中,建议采用多层保护策略:

                    ┌─────────────────────┐
│ 系统保护规则 │ ← 最后一道防线
└──────────┬──────────┘

┌──────────▼──────────┐
│ 熔断降级规则 │ ← 处理不稳定依赖
└──────────┬──────────┘

┌──────────▼──────────┐
│ 流量控制规则 │ ← 控制入口流量
└──────────┬──────────┘

┌──────────▼──────────┐
│ 业务逻辑 │
└─────────────────────┘

每一层保护都有其职责:

  • 流量控制规则:保护系统不被超出处理能力的流量冲垮
  • 熔断降级规则:处理依赖服务不稳定的情况
  • 系统保护规则:兜底保护,防止系统整体过载

2. 资源命名规范

良好的资源命名可以提高可维护性和可读性:

// 推荐:使用有业务含义的名称
@SentinelResource(value = "order:service:createOrder")
public Order createOrder(OrderRequest request) { ... }

@SentinelResource(value = "user:service:getUser")
public User getUser(String userId) { ... }

// 不推荐:使用无意义的名称
@SentinelResource(value = "method1")
public void process() { ... }

命名规范建议:

  • 使用模块前缀:module:service:method
  • 使用动词:creategetupdatedelete
  • 区分读写操作:read:write:

3. 合理划分资源粒度

资源粒度的划分需要在保护效果和管理复杂度之间取得平衡:

// 粒度太粗:无法精细化控制
@SentinelResource(value = "orderService")
public class OrderService { ... }

// 粒度太细:管理复杂
@SentinelResource(value = "orderService.createOrder.step1")
public void step1() { ... }
@SentinelResource(value = "orderService.createOrder.step2")
public void step2() { ... }

// 推荐:按接口级别划分
@SentinelResource(value = "order:create")
public Order createOrder() { ... }
@SentinelResource(value = "order:query")
public Order queryOrder() { ... }

流量控制最佳实践

1. 阈值设置

阈值的设置应该基于压测数据和实际业务情况:

QPS 阈值

// 推荐:设置为压测最大 QPS 的 70%-80%
// 假设压测最大 QPS 为 1000,设置 700-800
FlowRule rule = new FlowRule();
rule.setResource("api:order:create");
rule.setCount(800);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);

线程数阈值

// 推荐:设置为线程池大小的 70%-80%
// 或者根据依赖服务的处理能力设置
FlowRule rule = new FlowRule();
rule.setResource("external:payment");
rule.setCount(50); // 限制并发调用数
rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);

2. 流控效果选择

根据业务场景选择合适的流控效果:

场景推荐效果说明
API 网关直接拒绝快速失败,让客户端重试或降级
秒杀系统Warm Up预热系统,避免冷启动问题
消息处理匀速排队削峰填谷,平滑处理
内部服务直接拒绝快速响应,避免资源占用

Warm Up 配置示例

FlowRule rule = new FlowRule();
rule.setResource("seckill:api");
rule.setCount(1000);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
rule.setWarmUpPeriodSec(30); // 30秒预热时间

匀速排队配置示例

FlowRule rule = new FlowRule();
rule.setResource("message:process");
rule.setCount(100);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
rule.setMaxQueueingTimeMs(500); // 最大排队 500ms

3. 关联限流使用场景

关联限流适用于资源争抢场景:

// 场景:数据库读写争抢,写操作优先
// 当写操作 QPS 过高时,限制读操作

FlowRule writeRule = new FlowRule();
writeRule.setResource("db:write");
writeRule.setCount(100);
writeRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

FlowRule readRule = new FlowRule();
readRule.setResource("db:read");
readRule.setCount(200);
readRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
readRule.setStrategy(RuleConstant.STRATEGY_RELATE);
readRule.setRefResource("db:write"); // 关联写操作
// 当写操作 QPS 接近 100 时,开始限制读操作

熔断降级最佳实践

1. 阈值设置原则

慢调用阈值

// 设置为 P99 响应时间的 2-3 倍
// 假设 P99 响应时间为 200ms,设置 400-600ms
DegradeRule rule = new DegradeRule("external:service");
rule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
rule.setCount(500); // 500ms
rule.setSlowRatioThreshold(0.5); // 50% 慢调用比例

异常比例阈值

// 根据业务容错能力设置
// 一般设置为 30%-50%
DegradeRule rule = new DegradeRule("external:service");
rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
rule.setCount(0.3); // 30% 异常比例

2. 熔断时长设置

熔断时长的设置需要考虑下游服务的恢复时间:

// 推荐:30-60 秒
// 太短:下游可能还没恢复
// 太长:影响服务可用性
rule.setTimeWindow(30);

对于不同类型的服务,可以调整:

  • 数据库服务:10-30 秒(可能快速恢复)
  • 外部 API:30-60 秒(恢复时间不确定)
  • 下游微服务:20-40 秒

3. 降级处理策略

提供有意义的降级响应:

@Service
public class ProductService {

@SentinelResource(value = "getProductDetail",
fallback = "getProductDetailFallback")
public ProductDetail getProductDetail(String productId) {
return remoteProductService.getDetail(productId);
}

// 降级策略:返回缓存的精简数据
public ProductDetail getProductDetailFallback(String productId, Throwable t) {
// 记录日志
log.warn("获取商品详情降级, productId={}, error={}", productId, t.getMessage());

// 尝试从缓存获取
ProductDetail cached = cacheService.getProductDetailCache(productId);
if (cached != null) {
return cached;
}

// 返回精简数据
return ProductDetail.builder()
.id(productId)
.name("商品信息暂时不可用")
.available(false)
.build();
}
}

4. 区分 blockHandler 和 fallback

@SentinelResource(value = "processOrder",
blockHandler = "handleBlock", // 限流/熔断时调用
fallback = "handleFallback") // 业务异常时调用
public Order processOrder(OrderRequest request) {
// 业务逻辑
}

// 限流或熔断时的处理
public Order handleBlock(OrderRequest request, BlockException e) {
return Order.blocked("系统繁忙,请稍后重试");
}

// 业务异常时的处理
public Order handleFallback(OrderRequest request, Throwable t) {
log.error("订单处理异常", t);
return Order.failed("服务暂时不可用");
}

系统保护最佳实践

1. 组合使用多种规则

private void initSystemRules() {
List<SystemRule> rules = new ArrayList<>();

// CPU 保护(最灵敏)
SystemRule cpuRule = new SystemRule();
cpuRule.setHighestCpuUsage(0.8); // CPU 80%

// 平均 RT 保护
SystemRule rtRule = new SystemRule();
rtRule.setAvgRt(1000); // 平均响应时间 1 秒

// 并发线程保护
SystemRule threadRule = new SystemRule();
threadRule.setMaxThread(200); // 最大并发 200

// 入口 QPS 保护
SystemRule qpsRule = new SystemRule();
qpsRule.setQps(5000); // 总入口 QPS 5000

rules.add(cpuRule);
rules.add(rtRule);
rules.add(threadRule);
rules.add(qpsRule);

SystemRuleManager.loadRules(rules);
}

2. 入口流量标记

系统保护规则只对入口流量生效,需要正确标记:

// 入口流量(Web 请求)
@GetMapping("/api/users/{id}")
public User getUser(@PathVariable String id) {
// Web 适配器会自动标记为入口流量
return userService.getUser(id);
}

// 内部调用
public void internalCall() {
// 手动定义资源时,默认为出口流量,不受系统保护
Entry entry = SphU.entry("internalResource");
// ...
}

// 如果需要系统保护,需要显式指定
public void protectedInternalCall() {
Entry entry = SphU.entry("internalResource", EntryType.IN); // 标记为入口
// ...
}

规则管理最佳实践

1. 使用动态规则源

生产环境必须使用动态规则源,支持规则的动态更新:

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: degrade
system:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-system-rules
groupId: SENTINEL_GROUP
rule-type: system

2. 规则版本管理

在 Nacos 等配置中心中,可以利用版本管理功能:

  • 保留历史规则配置
  • 支持规则回滚
  • 记录规则变更历史

3. 规则审计

建立规则变更审批流程:

  1. 在测试环境验证规则
  2. 通过代码评审
  3. 分批次灰度发布
  4. 监控生效情况

监控告警最佳实践

1. 监控关键指标

// 注册状态变化监听器
EventObserverRegistry.getInstance().addStateChangeObserver("alert",
(prevState, newState, rule, snapshotValue) -> {
if (newState == CircuitBreaker.State.OPEN) {
// 发送告警
alertService.sendAlert(
"熔断器打开: " + rule.getResource(),
"触发值: " + snapshotValue
);
}
});

2. 接入监控平台

将 Sentinel 监控数据接入 Prometheus、Grafana 等监控平台:

// 通过 HTTP API 获取监控数据
curl http://localhost:8719/metric?startTime=xxx&endTime=xxx

// 或自定义 MetricExporter
public class SentinelMetricExporter {

@Scheduled(fixedRate = 1000)
public void exportMetrics() {
for (ResourceWrapper resource : ResourceWrapperRegistry.getAll()) {
ClusterNode node = ClusterBuilderSlot.getClusterNode(resource.getName());
if (node != null) {
// 导出指标到监控系统
Metrics.export("sentinel_pass_qps", node.passQps());
Metrics.export("sentinel_block_qps", node.blockQps());
Metrics.export("sentinel_rt", node.avgRt());
}
}
}
}

3. 告警规则配置

建议配置的告警项:

告警项阈值建议说明
限流触发率> 10%大量请求被限流
熔断器打开任何打开依赖服务异常
CPU 使用率> 80%系统负载过高
平均 RT> P99 * 2响应变慢
异常比例> 10%错误率升高

性能优化最佳实践

1. 滑动窗口配置

// 增加滑动窗口精度(代价是更多内存)
SampleCountProperty.updateGlobalSampleCount(4); // 默认 2
IntervalProperty.updateGlobalInterval(1000); // 默认 1000ms

2. 避免过度埋点

// 不推荐:对每个小方法都埋点
@SentinelResource(value = "method1")
public void method1() { ... }

@SentinelResource(value = "method2")
public void method2() { ... }

// 推荐:对关键接口埋点
@SentinelResource(value = "api:order:create")
public Order createOrder() {
// 内部方法不需要单独埋点
validateOrder();
saveOrder();
notifyUser();
}

3. 规则数量控制

  • 单个资源的规则数量控制在 10 个以内
  • 总规则数量控制在合理范围(如 1000 个以内)
  • 定期清理不再使用的规则

部署架构最佳实践

1. 控制台高可用

         ┌─────────────┐
│ 负载均衡器 │
└──────┬──────┘

┌────────┴────────┐
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Dashboard │ │ Dashboard │
│ Instance 1 │ │ Instance 2 │
└──────┬──────┘ └──────┬──────┘
│ │
└────────┬────────┘

┌──────▼──────┐
│ Nacos │
│ (规则存储) │
└─────────────┘

2. 规则配置分离

不同环境使用不同的规则配置:

Nacos 配置:
├── dev
│ ├── order-service-flow-rules
│ └── order-service-degrade-rules
├── test
│ ├── order-service-flow-rules
│ └── order-service-degrade-rules
└── prod
├── order-service-flow-rules
└── order-service-degrade-rules

3. 灰度发布支持

通过规则配置支持灰度发布:

// 对灰度实例设置不同的限流阈值
FlowRule rule = new FlowRule();
rule.setResource("api:newFeature");
rule.setCount(10); // 灰度实例低阈值

常见问题规避

1. 避免规则配置错误

// 错误:阈值为 0
rule.setCount(0); // 所有请求都会被拒绝

// 错误:资源名不匹配
@SentinelResource(value = "getUser")
public User getUserInfo() { ... } // 规则配置的是 "getUserInfo"

// 正确:仔细核对配置
rule.setResource("getUser");
rule.setCount(100);

2. 避免死锁

// 错误:在 entry 之前获取锁
synchronized(lock) {
Entry entry = SphU.entry("resource"); // 如果被阻塞,锁不会释放
}

// 正确:先 entry 再获取锁
Entry entry = SphU.entry("resource");
try {
synchronized(lock) {
// 业务逻辑
}
} finally {
entry.exit();
}

3. 正确处理异常

// 错误:吞掉 BlockException
try {
Entry entry = SphU.entry("resource");
entry.exit();
} catch (Exception e) {
// BlockException 被吞掉,无法区分限流和业务异常
}

// 正确:单独处理 BlockException
try {
Entry entry = SphU.entry("resource");
try {
// 业务逻辑
} finally {
entry.exit();
}
} catch (BlockException e) {
// 限流处理
}

检查清单

生产环境上线前的检查清单:

  • 所有规则配置了动态数据源
  • 控制台鉴权配置正确
  • 降级逻辑已实现并测试
  • 关键资源添加了监控告警
  • 规则阈值经过压测验证
  • 日志配置正确
  • 异常处理完备
  • 文档已更新

下一步