Sentinel 流量控制
流量控制原理
滑动窗口算法
Sentinel 基于滑动窗口算法实现流量统计:
时间轴:
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
↑ ↑
窗口开始 窗口结束
当前窗口统计:slot 5-10 的请求总数
令牌桶算法
用于实现匀速排队和预热:
令牌桶:
┌─────┬─────┬─────┬─────┬─────┐
│ 🪙 │ 🪙 │ 🪙 │ 🪙 │ 🪙 │ ← 固定容量
└─────┴─────┴─────┴─────┴─────┘
↑
添加令牌(固定速率)
↓
请求获取令牌
↓
有令牌:通过
无令牌:拒绝/等待
QPS 限流
基础配置
@Configuration
public class QpsFlowRuleConfig {
@PostConstruct
public void initRules() {
List<FlowRule> rules = new ArrayList<>();
// 基础 QPS 限流
FlowRule rule = new FlowRule();
rule.setResource("getUserById");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100); // 每秒最多 100 次请求
rule.setLimitApp("default"); // 针对所有调用来源
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
限流模式
1. 直接拒绝(默认)
FlowRule rule = new FlowRule();
rule.setResource("getUserById");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
2. 冷启动(预热)
FlowRule rule = new FlowRule();
rule.setResource("getUserById");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
rule.setWarmUpPeriodSec(10); // 预热 10 秒
预热过程:
- 第 0 秒:QPS = 10
- 第 5 秒:QPS = 50
- 第 10 秒:QPS = 100(达到阈值)
3. 排队等待(匀速排队)
FlowRule rule = new FlowRule();
rule.setResource("createOrder");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
rule.setMaxQueueingTimeMs(500); // 最大排队 500ms
适用场景:
- 秒杀活动
- 定时任务
- 消息推送
4. 预热 + 排队
FlowRule rule = new FlowRule();
rule.setResource("createOrder");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER);
rule.setWarmUpPeriodSec(10);
rule.setMaxQueueingTimeMs(500);
线程数限流
基础配置
@Configuration
public class ThreadFlowRuleConfig {
@PostConstruct
public void initRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("processData");
rule.setGrade(RuleConstant.FLOW_GRADE_THREAD); // 线程数模式
rule.setCount(50); // 最多 50 个并发线程
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
适用场景:
- 耗时操作
- 数据库操作
- 外部 API 调用
与 QPS 限流对比
| 特性 | QPS 限流 | 线程数限流 |
|---|---|---|
| 统计维度 | 请求数 | 并发线程数 |
| 适用场景 | 快速响应接口 | 耗时操作 |
| 资源消耗 | 低 | 高 |
| 控制精度 | 高 | 中 |
热点参数限流
配置规则
@Configuration
public class ParamFlowRuleConfig {
@PostConstruct
public void initRules() {
List<ParamFlowRule> rules = new ArrayList<>();
ParamFlowRule rule = new ParamFlowRule();
rule.setResource("getUserById");
rule.setParamIdx(0); // 对第一个参数限流
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(10); // 每个参数值每秒最多 10 次
rule.setDurationInSec(1);
// 针对特定参数值设置不同限流
List<ParamFlowItem> items = new ArrayList<>();
// VIP 用户:每秒 100 次
ParamFlowItem vipItem = new ParamFlowItem();
vipItem.setObject(String.valueOf(1)); // 用户 ID=1
vipItem.setCount(100);
items.add(vipItem);
// 普通用户:每秒 10 次
ParamFlowItem normalItem = new ParamFlowItem();
normalItem.setObject(String.valueOf(2)); // 用户 ID=2
normalItem.setCount(10);
items.add(normalItem);
rule.setParamFlowItemList(items);
rules.add(rule);
ParamFlowRuleManager.loadRules(rules);
}
}
使用场景
1. 商品详情页限流
@GetMapping("/product/{id}")
@SentinelResource(
value = "productDetail",
blockHandler = "handleParamBlock"
)
public Result<Product> getProduct(@PathVariable Long id) {
return Result.success(productService.findById(id));
}
// 热点商品单独限流
@Configuration
public class ProductParamRuleConfig {
@PostConstruct
public void init() {
ParamFlowRule rule = new ParamFlowRule();
rule.setResource("productDetail");
rule.setParamIdx(0); // 商品 ID 参数
rule.setCount(100); // 默认每个商品每秒 100 次
// 热门商品限制更严格
List<ParamFlowItem> hotItems = Arrays.asList(
createItem(1001L, 50), // 商品 1001:50 QPS
createItem(1002L, 50), // 商品 1002:50 QPS
createItem(1003L, 50) // 商品 1003:50 QPS
);
rule.setParamFlowItemList(hotItems);
ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
}
private ParamFlowItem createItem(Long productId, int count) {
ParamFlowItem item = new ParamFlowItem();
item.setObject(productId);
item.setCount(count);
return item;
}
}
2. IP 限流
@GetMapping("/api/data")
@SentinelResource(
value = "getData",
blockHandler = "handleIpBlock"
)
public Result<Data> getData(HttpServletRequest request) {
String ip = request.getRemoteAddr();
return Result.success(dataService.getData(ip));
}
@Configuration
public class IpParamRuleConfig {
@PostConstruct
public void init() {
ParamFlowRule rule = new ParamFlowRule();
rule.setResource("getData");
rule.setParamIdx(0); // IP 参数
rule.setCount(10); // 每个 IP 每秒 10 次
ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
}
}
关联限流
配置关联规则
@Configuration
public class RelationFlowRuleConfig {
@PostConstruct
public void initRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("createOrder"); // 被限流资源
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100);
rule.setLimitApp("default");
rule.setStrategy(RuleConstant.STRATEGY_RELATE); // 关联策略
rule.setRefResource("payOrder"); // 关联资源
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
工作原理:
当 payOrder 的 QPS 超过阈值时,
限流 createOrder 资源
适用场景:
- 下单和支付关联
- 读操作和写操作关联
链路限流
配置链路规则
@Configuration
public class ChainFlowRuleConfig {
@PostConstruct
public void initRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("getUserById");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100);
rule.setLimitApp("default");
rule.setStrategy(RuleConstant.STRATEGY_CHAIN); // 链路策略
rule.setRefResource("com.example.controller.UserController"); // 入口资源
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
工作原理:
只统计从 UserController 调用 getUserById 的流量
其他链路调用不统计
集群限流
配置集群规则
@Configuration
public class ClusterFlowRuleConfig {
@PostConstruct
public void initRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("getUserById");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(1000); // 集群总 QPS
rule.setLimitApp("default");
rule.setClusterMode(true); // 启用集群模式
ClusterFlowConfig clusterConfig = new ClusterFlowConfig();
clusterConfig.setFlowId(1); // 流控 ID
clusterConfig.setThresholdType(0); // 0=QPS, 1=线程数
clusterConfig.setClientOfflineTime(2000); // 客户端离线时间
rule.setClusterConfig(clusterConfig);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
集群限流模式
1. 平均分配
cluster:
flow:
strategy: 0 # 平均分配
每个实例分配的 QPS = 总 QPS / 实例数
2. 单独分配
cluster:
flow:
strategy: 1 # 单独分配
每个实例独立统计,不共享配额
限流效果处理
1. 快速失败
public Result<User> handleBlock(Long id, BlockException ex) {
return Result.fail("访问过于频繁,请稍后再试");
}
2. 降级处理
@SentinelResource(
value = "getUserById",
fallback = "handleFallback"
)
public Result<User> getUser(Long id) {
return Result.success(userService.findById(id));
}
public Result<User> handleFallback(Long id, Throwable ex) {
// 可以记录日志
log.error("获取用户失败", ex);
return Result.fail("服务暂时不可用");
}
3. 排队等待
FlowRule rule = new FlowRule();
rule.setResource("createOrder");
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
rule.setMaxQueueingTimeMs(1000); // 最多等待 1 秒
实时监控
查看监控指标
# 查看资源 QPS
curl http://localhost:8080/actuator/sentinel/metrics?resource=getUserById
# 查看限流次数
curl http://localhost:8080/actuator/sentinel/metrics?resource=getUserById&metricType=blockQps
集成 Grafana
# Prometheus 配置
management:
metrics:
export:
prometheus:
enabled: true
# Sentinel 指标
spring:
cloud:
sentinel:
metric:
charset: UTF-8
interval: 1000 # 指标收集间隔
最佳实践
1. 限流阈值设置
- 根据压测结果:通过压测确定系统容量
- 预留缓冲:设置阈值为容量的 80%
- 动态调整:根据监控数据动态调整
2. 限流策略选择
- 普通接口:QPS 限流 + 快速失败
- 耗时接口:线程数限流
- 秒杀活动:QPS 限流 + 排队等待
- 热点数据:热点参数限流
3. 降级方案设计
- 返回默认值:提供兜底数据
- 缓存降级:返回缓存数据
- 服务降级:关闭非核心功能
4. 告警配置
@Component
public class FlowAlertListener {
@Autowired
private AlertService alertService;
@Scheduled(fixedRate = 60000) // 每分钟检查
public void checkFlowMetrics() {
Map<String, MetricVo> metrics = SentinelMetricService.getMetrics();
metrics.forEach((resource, metric) -> {
if (metric.getBlockQps() > 100) {
alertService.sendAlert(
String.format("资源 %s 限流严重,QPS=%d, BlockQPS=%d",
resource, metric.getQps(), metric.getBlockQps())
);
}
});
}
}
总结
Sentinel 提供了丰富的流量控制功能,包括 QPS 限流、线程数限流、热点参数限流等。
合理配置限流规则可以有效保护系统免受突发流量影响,提高系统的稳定性和可用性。
在生产环境中,建议根据压测结果设置合理的阈值,并建立完善的监控告警机制。