Sentinel与Redis限流方案对比
Sentinel与Redis限流方案对比
架构对比
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25Sentinel单机限流:
┌──────────────┐
│ 请求 │
└──────┬───────┘
│
▼
┌──────────────┐
│ 应用服务器 │ ◄── Sentinel限流
└──────────────┘
Redis分布式限流:
┌──────────────┐
│ 请求 │
└──────┬───────┘
│
▼
┌──────────────┐ ┌──────────────┐
│ 应用服务器1 │ │ 应用服务器2 │
└──────┬───────┘ └──────┬───────┘
│ │
└─────────┬────────┘
▼
┌──────────────┐
│ Redis │ ◄── 限流统计
└──────────────┘特性对比
1
2
3
4
5
6
7
8
9
10
11┌────────────┬───────────────────┬───────────────────┐
│ 特性 │ Sentinel │ Redis限流 │
├────────────┼───────────────────┼───────────────────┤
│部署方式 │应用内限流 │中心化限流 │
│实现复杂度 │简单 │相对复杂 │
│限流精度 │较高 │受网络延迟影响 │
│扩展性 │单机 │分布式 │
│限流规则 │丰富 │需自行实现 │
│实时性 │很高 │有少量延迟 │
│资源占用 │内存 │网络IO │
└────────────┴───────────────────┴───────────────────┘应用场景
1
2
3
4
5
6
7
8
9
10
11Sentinel适用场景:
1. 单机应用的限流保护
2. 微服务内部限流
3. 需要精确控制的场景
4. 对实时性要求高的场景
Redis限流适用场景:
1. 分布式系统的全局限流
2. 跨服务的限流需求
3. 需要共享限流数据的场景
4. 动态调整限流规则组合使用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class OrderService {
private final RedisLimiter redisLimiter;
public Order createOrder(OrderRequest request) {
// 1. 分布式限流 - 全局QPS控制
if (!redisLimiter.isAllowed("order:global", 1000)) {
throw new LimitException("全局限流");
}
// 2. Sentinel限流 - 本地线程数控制
return processOrder(request);
}
// Sentinel限流配置
private void initSentinelRules() {
FlowRule rule = new FlowRule();
rule.setResource("createOrder");
rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
rule.setCount(10);
FlowRuleManager.loadRules(Arrays.asList(rule));
}
}为什么需要组合使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21技术原因:
1. 分层防护
- Redis限流:全局流量控制
- Sentinel:应用级保护
2. 不同维度
- Redis限流:QPS维度
- Sentinel:线程数维度
3. 补充优势
- Redis:分布式一致性
- Sentinel:实时精确控制
业务原因:
1. 多级限流需求
- 用户级别限流(Redis)
- 接口级别限流(Sentinel)
2. 差异化限流
- 全局业务限流(Redis)
- 资源保护限流(Sentinel)最佳实践
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public class RateLimiterConfig {
public GlobalFilter globalRateLimiter(RedisLimiter redisLimiter) {
return (exchange, chain) -> {
String path = exchange.getRequest().getPath().value();
// 1. 全局限流 - Redis
if (!redisLimiter.isAllowed("global:" + path)) {
return ResponseEntity.status(429).build();
}
// 2. 本地限流 - Sentinel
Entry entry = null;
try {
entry = SphU.entry(path);
return chain.filter(exchange);
} catch (BlockException e) {
return ResponseEntity.status(429).build();
} finally {
if (entry != null) {
entry.exit();
}
}
};
}
}