引言:当整个系统都在危险边缘
在前面的文章中,我们学习了限流和熔断,它们都是针对单个资源的保护:
- 限流:保护单个接口不被流量压垮
- 熔断:保护自己不被依赖服务拖垮
但在实际生产中,还有一种更危险的场景:
某天晚上8点,你的电商系统突然收到一波超大流量(可能是爬虫、攻击或者真实用户)。
虽然你对每个接口都做了限流,但这波流量分散在各个接口上:
- 首页接口:QPS 500(限流阈值600)✅
- 搜索接口:QPS 300(限流阈值400)✅
- 商品详情:QPS 400(限流阈值500)✅
- 下单接口:QPS 200(限流阈值300)✅
每个接口都没有超过限流阈值,但整个系统的负载已经爆炸了:
- CPU使用率:95%
- 系统Load:8.0(4核机器)
- 平均响应时间:5秒
- 内存使用率:90%
系统已经濒临崩溃边缘!
这就是单个资源限流的盲区:无法感知系统整体的健康状况。
Sentinel的系统自适应保护(System Adaptive Protection)就是为了解决这个问题。
系统保护的必要性
为什么需要系统级别的保护?
问题1:单个资源限流无法保护整体
┌─────────────────────────────────────┐
│ 服务器(4核8G) │
├─────────────────────────────────────┤
│ 接口A:QPS 500/600 ✅ (83%) │
│ 接口B:QPS 300/400 ✅ (75%) │
│ 接口C:QPS 400/500 ✅ (80%) │
│ 接口D:QPS 200/300 ✅ (67%) │
├─────────────────────────────────────┤
│ 但是... │
│ CPU使用率:95% ❌ │
│ Load:8.0 ❌ (4核机器) │
│ 平均RT:5秒 ❌ │
└─────────────────────────────────────┘
问题2:流量来源不均匀
- 不同接口的计算复杂度不同
- 不同接口的数据库查询次数不同
- 突发流量可能来自多个接口
问题3:无法应对突发故障
- 数据库突然变慢
- 缓存突然失效
- GC突然频繁
系统保护的目标
在系统整体负载过高时,从入口处开始限流,保证系统不被压垮。
核心思想:
- 监控系统指标:Load、CPU、RT、线程数等
- 智能判断:系统是否处于危险状态
- 全局限流:从入口处限流,保护整个系统
五大系统保护指标
Sentinel提供了五个维度的系统保护指标:
1. Load(系统负载)
定义:Linux的系统平均负载(Load Average)。
含义:
- Load = 1.0:1核CPU满载
- Load = 4.0:4核CPU满载
- Load = 8.0:4核CPU严重过载(2倍负载)
触发条件:
当前Load >= 阈值 && 当前并发线程数 >= 系统容量(BBR算法计算)
适用场景:
- Linux系统(Windows不支持Load指标)
- 希望根据整体负载保护系统
配置示例:
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(4.0); // Load阈值:4.0
解读:当系统Load >= 4.0,且系统容量已满,触发限流。
2. CPU使用率
定义:当前系统的CPU使用率(0.0 ~ 1.0)。
触发条件:
当前CPU使用率 >= 阈值
适用场景:
- 跨平台(Linux、Windows都支持)
- CPU密集型应用
配置示例:
SystemRule rule = new SystemRule();
rule.setHighestCpuUsage(0.8); // CPU使用率阈值:80%
解读:当CPU使用率 >= 80%,触发限流。
3. 平均响应时间(RT)
定义:所有入口流量的平均响应时间。
触发条件:
当前平均RT >= 阈值
适用场景:
- 关注响应时间的系统
- 防止雪崩效应
配置示例:
SystemRule rule = new SystemRule();
rule.setAvgRt(1000); // 平均RT阈值:1000ms
解读:当平均响应时间 >= 1秒,触发限流。
4. 并发线程数
定义:系统当前正在处理的并发线程数。
触发条件:
当前并发线程数 >= 阈值
适用场景:
- 防止线程池耗尽
- 保护下游依赖
配置示例:
SystemRule rule = new SystemRule();
rule.setMaxThread(100); // 并发线程数阈值:100
解读:当并发线程数 >= 100,触发限流。
5. 入口QPS
定义:系统所有入口流量的总QPS。
触发条件:
当前入口QPS >= 阈值
适用场景:
- 已知系统整体吞吐能力
- 简单粗暴的全局限流
配置示例:
SystemRule rule = new SystemRule();
rule.setQps(10000); // 入口QPS阈值:10000
解读:当入口QPS >= 10000,触发限流。
自适应算法:BBR
什么是BBR?
BBR(Bottleneck Bandwidth and Round-trip propagation time)是Google提出的拥塞控制算法,Sentinel借鉴了这个思想用于系统保护。
核心思想:
根据系统的处理能力(Capacity)动态调整限流阈值,让系统始终运行在最佳状态。
BBR算法原理
关键指标:
- maxQps:系统处理的最大QPS(通过滑动窗口统计)
- minRt:系统处理的最小响应时间(通过滑动窗口统计)
- 系统容量(Capacity):
maxQps * minRt / 1000
触发条件(以Load为例):
if (currentLoad >= threshold) {
// 计算系统容量
capacity = maxQps * minRt / 1000;
// 如果当前并发线程数 >= 容量,触发限流
if (currentThread >= capacity) {
return BLOCK;
}
}
举例:
- maxQps = 1000(系统在最佳状态下能处理1000 QPS)
- minRt = 10ms(系统在最佳状态下的响应时间)
- capacity = 1000 * 10 / 1000 = 10(系统容量:10个并发线程)
当Load >= 阈值时:
- 如果当前并发线程数 < 10,放行
- 如果当前并发线程数 >= 10,限流
为什么需要BBR?
问题:如果只看Load,可能会误判。
场景1:Load高但系统正常
- Load = 5.0(高)
- 但是系统只有2个并发请求(低)
- 不应该限流(可能是其他进程导致的Load高)
场景2:Load高且系统过载
- Load = 5.0(高)
- 系统有50个并发请求(高)
- 系统容量只有10
- 应该限流
BBR算法通过结合Load和并发线程数,避免了误判。
配置系统保护规则
基本配置
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import java.util.ArrayList;
import java.util.List;
public class SystemRuleConfig {
public static void initSystemRule() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
// 方式1:Load保护(Linux)
rule.setHighestSystemLoad(4.0);
// 方式2:CPU使用率保护(跨平台)
// rule.setHighestCpuUsage(0.8);
// 方式3:平均RT保护
// rule.setAvgRt(1000);
// 方式4:并发线程数保护
// rule.setMaxThread(100);
// 方式5:入口QPS保护
// rule.setQps(10000);
rules.add(rule);
SystemRuleManager.loadRules(rules);
System.out.println("✅ 系统保护规则已加载");
}
}
注意:
- 系统保护规则是全局的,只需配置一条
- 五个指标可以同时配置,任意一个触发都会限流
- 但通常只配置1-2个最关键的指标
Dashboard配置
在Sentinel Dashboard中:
- 选择应用
- 点击"系统规则"
- 点击"新增系统规则"
- 配置阈值
实战案例:保护电商系统
场景描述
电商系统部署在4核8G的服务器上,正常情况下:
- CPU使用率:50%
- Load:2.0
- 平均RT:100ms
- 并发线程数:20
某天晚上遭遇流量攻击,QPS从1000飙升到5000,系统濒临崩溃。
配置策略
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import java.util.ArrayList;
import java.util.List;
public class EcommerceSystemProtection {
public static void main(String[] args) throws InterruptedException {
// 1. 配置系统保护规则
initSystemRule();
// 2. 模拟正常流量
System.out.println("=== 正常流量 ===");
for (int i = 0; i < 10; i++) {
simulateRequest();
Thread.sleep(100);
}
// 3. 模拟系统过载
System.out.println("\n=== 系统过载(模拟CPU 90%)===");
SystemRuleManager.loadRules(createHighLoadRules());
for (int i = 0; i < 10; i++) {
simulateRequest();
Thread.sleep(100);
}
}
/**
* 配置系统保护规则
*/
private static void initSystemRule() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
// CPU使用率保护:80%
rule.setHighestCpuUsage(0.8);
// 平均RT保护:500ms
rule.setAvgRt(500);
// 并发线程数保护:50
rule.setMaxThread(50);
rules.add(rule);
SystemRuleManager.loadRules(rules);
System.out.println("✅ 系统保护规则已加载:CPU < 80%, RT < 500ms, 线程数 < 50\n");
}
/**
* 创建高负载规则(用于模拟)
*/
private static List<SystemRule> createHighLoadRules() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
rule.setHighestCpuUsage(0.5); // 降低阈值,模拟触发
rules.add(rule);
return rules;
}
/**
* 模拟请求
*/
private static void simulateRequest() {
try {
// 注意:系统保护不需要定义资源,它会自动保护所有入口流量
// 这里只是模拟业务逻辑
System.out.println("✅ 请求处理成功");
} catch (Exception e) {
System.out.println("🔴 请求被系统保护拒绝");
}
}
}
效果分析
正常情况(CPU 50%,RT 100ms):
✅ 请求处理成功
✅ 请求处理成功
✅ 请求处理成功
系统过载(CPU 90%,RT 500ms):
🔴 请求被系统保护拒绝
🔴 请求被系统保护拒绝
✅ 请求处理成功(少量放行)
🔴 请求被系统保护拒绝
收益:
- 系统不会崩溃
- CPU使用率被控制在安全范围
- 少量请求仍然能够成功(保证基本可用)
系统保护 vs 限流 vs 熔断
三者对比
| 维度 | 系统保护 | 限流 | 熔断 |
|---|---|---|---|
| 保护对象 | 整个系统 | 单个资源 | 调用依赖 |
| 触发条件 | Load、CPU、RT等 | QPS、线程数 | 慢调用、异常 |
| 保护范围 | 全局入口 | 指定资源 | 指定依赖 |
| 粒度 | 粗(系统级) | 中(资源级) | 细(调用级) |
| 适用场景 | 整体过载 | 接口热点 | 依赖故障 |
三层防护体系
用户请求
↓
┌──────────────────┐
│ 系统保护 │ ← 第一层:整体负载保护
│ (Load/CPU/RT) │
└──────────────────┘
↓
┌──────────────────┐
│ 接口限流 │ ← 第二层:接口级保护
│ (QPS/线程数) │
└──────────────────┘
↓
┌──────────────────┐
│ 依赖熔断 │ ← 第三层:依赖保护
│ (慢调用/异常) │
└──────────────────┘
↓
业务处理
实战组合使用
public class ComprehensiveProtection {
public static void init() {
// 第一层:系统保护
List<SystemRule> systemRules = new ArrayList<>();
SystemRule systemRule = new SystemRule();
systemRule.setHighestCpuUsage(0.8); // CPU 80%
systemRule.setAvgRt(500); // RT 500ms
systemRules.add(systemRule);
SystemRuleManager.loadRules(systemRules);
// 第二层:接口限流
List<FlowRule> flowRules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
flowRule.setResource("orderCreate");
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setCount(100); // QPS 100
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
// 第三层:依赖熔断
List<DegradeRule> degradeRules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource("callInventoryService");
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule.setCount(1000); // RT 1秒
degradeRule.setSlowRatioThreshold(0.5);
degradeRules.add(degradeRule);
DegradeRuleManager.loadRules(degradeRules);
System.out.println("✅ 三层防护体系已建立");
}
}
最佳实践
1. 选择合适的指标
| 场景 | 推荐指标 |
|---|---|
| Linux服务器 | Load + CPU |
| Windows服务器 | CPU + RT |
| 计算密集型 | CPU |
| IO密集型 | Load + RT |
| 响应时间敏感 | RT |
| 已知吞吐能力 | 入口QPS |
2. 阈值设置建议
CPU使用率:
- 推荐:0.8(80%)
- 激进:0.7(70%)
- 保守:0.9(90%)
Load(以4核服务器为例):
- 推荐:3.0(75%负载)
- 激进:2.5(62.5%)
- 保守:4.0(100%)
平均RT:
- 推荐:500ms
- 激进:300ms
- 保守:1000ms
并发线程数:
- 推荐:Tomcat最大线程数的70%
- 示例:最大200线程,设置140
3. 监控告警
关键指标:
# Prometheus告警规则
- alert: HighSystemLoad
expr: system_load > 4.0
for: 1m
annotations:
summary: "系统负载过高"
- alert: SystemProtectionTriggered
expr: rate(sentinel_system_block_total[1m]) > 10
for: 2m
annotations:
summary: "系统保护频繁触发"
4. 避免过度保护
问题:阈值设置过低,导致误判。
案例:
- 设置CPU阈值50%
- 正常流量CPU就达到50%
- 系统频繁触发保护
- 大量正常请求被拒绝
解决:
- 通过压测确定合理阈值
- 观察系统在正常和峰值流量下的指标
- 阈值要留有余量(如峰值60%,设置80%)
5. 测试验证
@Test
public void testSystemProtection() {
// 1. 配置系统保护规则
SystemRule rule = new SystemRule();
rule.setHighestCpuUsage(0.8);
SystemRuleManager.loadRules(Collections.singletonList(rule));
// 2. 模拟高负载
// (需要真实的负载生成工具,如JMeter)
// 3. 验证系统保护是否生效
// 检查监控指标:CPU、限流次数等
}
注意事项
1. 系统保护是全局的
特点:
- 一旦触发,所有入口流量都会被限流
- 不区分接口的重要性
影响:
- 可能导致核心接口也被限流
- 需要配合接口级限流使用
2. Load指标的局限性
问题:
- 只支持Linux
- Load受其他进程影响(如同机部署的其他服务)
- Load的更新有延迟
建议:
- 配合CPU使用率使用
- 或者只使用CPU使用率(跨平台)
3. BBR算法的冷启动
问题:
- 系统刚启动时,maxQps和minRt还没统计到
- 可能导致误判
解决:
- 系统启动后先预热(发送少量请求)
- 或者不使用Load保护,改用CPU/RT
4. 不要过度依赖系统保护
原则:
系统保护是最后一道防线,不应该成为主要的保护手段。
正确的做法:
- 首先做好接口级限流
- 其次做好依赖熔断
- 最后配置系统保护兜底
总结
本文我们学习了Sentinel的系统自适应保护机制:
- 五大保护指标:Load、CPU、RT、并发线程数、入口QPS
- BBR算法:根据系统容量动态限流,避免误判
- 配置方法:SystemRule配置,Dashboard可视化配置
- 实战案例:保护电商系统免于过载崩溃
- 三层防护:系统保护 + 接口限流 + 依赖熔断
- 最佳实践:选择指标、设置阈值、监控告警、避免过度保护
核心要点:
系统保护是Sentinel的"核武器",它从整体角度保护系统不被压垮。但要谨慎使用,阈值设置要合理,避免误伤正常流量。
下一篇预告:
我们将学习热点参数限流:
- 什么是热点数据?
- 为什么普通限流无法保护热点?
- 如何配置热点参数限流规则?
- 秒杀商品、热门主播的保护方案
让我们一起探索更精细化的限流策略!