一、Sentinel 的核心概念
Sentinel 的设计围绕“流量治理”展开,以下是其核心概念:
资源(Resource):
- 资源是 Sentinel 的核心概念,可以是代码中的任意一段逻辑(如方法调用、接口、SQL 查询等),也可以是服务或 URL。
- 每个资源都有唯一的名称(resourceName),Sentinel 通过资源名称对其进行监控和控制。
- 用户需要通过 Sentinel API(如
SphU.entry(resourceName)
)定义资源。
规则(Rule):
- 规则定义了对资源的流量控制、降级等策略。Sentinel 支持多种规则类型:
- 流量控制规则(FlowRule):控制资源的 QPS 或并发线程数。
- 熔断降级规则(DegradeRule):当资源达到某种异常比例或异常数时触发熔断。
- 热点参数规则(ParamFlowRule):针对热点参数(如请求中的某个 ID)进行限流。
- 系统保护规则(SystemRule):基于系统负载、CPU 使用率等指标进行动态限流。
- 规则可以动态配置,支持从内存、配置中心(如 Nacos、Zookeeper)加载。
- 规则定义了对资源的流量控制、降级等策略。Sentinel 支持多种规则类型:
Slot 链(Slot Chain):
- Sentinel 使用责任链模式(Chain of Responsibility)实现功能模块化。每个功能(如统计、限流、熔断)由一个 Slot 负责,Slot 按顺序处理请求。
- 默认的 Slot 包括:
- NodeSelectorSlot:选择或创建对应的资源节点。
- ClusterNodeBuilderSlot:构建集群节点。
- StatisticSlot:统计流量数据。
- FlowSlot:执行流量控制。
- DegradeSlot:执行熔断降级。
- SystemSlot:系统自适应限流。
- 用户可以自定义 Slot 扩展功能。
上下文(Context):
- 每次请求都会生成一个上下文(Context),包含当前的资源、调用链信息等。
- 上下文通过 ThreadLocal 机制管理,确保线程安全。
指标(Metric):
- Sentinel 实时收集了丰富的监控指标,如 QPS、RT(响应时间)、异常数、拒绝请求数等。
- 这些指标可以推送到外部监控系统(如 Prometheus)或通过 Dashboard 查看。
二、Sentinel 的主要功能
流量控制(Flow Control):
- 通过限制资源的访问频率(如 QPS 或线程数)来防止流量突增导致系统崩溃。
- 支持多种限流模式:
- 直接拒绝:超过阈值后直接拒绝请求。
- 匀速排队:请求按固定速率通过,超出的请求排队等待。
- 冷启动(Warm-up):系统启动时逐步增加流量,防止瞬时过载。
- 支持基于调用来源(Caller)的限流,适合多租户场景。
熔断降级(Circuit Breaking):
- 当资源出现异常(如高延迟、高错误率)时,触发熔断,暂时阻止对该资源的访问。
- 熔断后可以配置降级策略(如返回默认值或调用备用接口)。
- 支持半开状态,定期尝试恢复服务。
热点参数限流:
- 针对请求中的热点参数(如商品 ID、用户 ID)进行精细化限流。
- 常用于缓存穿透、热点数据访问等场景。
系统自适应保护:
- 根据系统指标(如 CPU 使用率、负载、RT)动态调整流量,防止系统过载。
- 这是 Sentinel 区别于其他限流工具的独特功能。
集群流量控制:
- 支持分布式环境下的集群限流,通过 Token Server 集中分配令牌。
- 适合大规模微服务架构。
动态规则配置:
- 支持通过控制台、配置中心动态修改规则,实时生效,无需重启服务。
三、Sentinel 的架构
Sentinel 的架构分为核心模块和扩展模块,以下是主要组成部分:
核心库(sentinel-core):
- 提供流量控制、熔断降级等核心功能。
- 轻量级,无外部依赖,适合嵌入到各种应用中。
适配模块:
- Sentinel 提供了与主流框架的适配,如:
- Spring Cloud、Spring Boot
- Dubbo、gRPC
- Servlet、RestTemplate、Feign
- 通过注解(如
@SentinelResource
)或拦截器简化集成。
- Sentinel 提供了与主流框架的适配,如:
Dashboard:
- 提供可视化控制台,用于监控流量、配置规则、查看实时指标。
- 支持集群流量监控。
数据源扩展:
- 支持从文件、Nacos、Zookeeper、Apollo 等加载规则。
- 规则变更可实时推送。
传输模块:
- 用于将监控数据推送至外部系统,如 Prometheus、InfluxDB。
集群流控模块:
- 提供 Token Server 和 Client,用于分布式限流。
四、Sentinel 的核心算法
Sentinel 的实现依赖多种算法,以下详细讲解其核心算法:
1. 滑动窗口算法(Sliding Window)
- 作用:用于统计实时的流量数据(如 QPS、RT、异常数)。
- 原理:
- Sentinel 使用滑动窗口来记录一段时间内的请求数据。
- 时间窗口被分为多个小时间片(如 1 秒分为 10 个 100ms 时间片)。
- 每个时间片记录请求数、成功数、异常数、RT 等指标。
- 当时间推进,旧的时间片被淘汰,新的时间片加入,保持窗口的滑动。
- 实现:
- Sentinel 使用
LeapArray
数据结构管理滑动窗口。 LeapArray
是一个循环数组,每个元素是一个时间片(WindowWrap
)。- 时间片的统计数据通过原子操作(如
AtomicLong
)更新,确保线程安全。
- Sentinel 使用
- 应用:
- 流量控制:计算当前窗口的 QPS,判断是否超过阈值。
- 熔断降级:统计异常比例或平均 RT,触发熔断。
代码示例(伪代码):
class LeapArray {
WindowWrap[] array; // 循环数组
int windowSize; // 时间片大小(如 100ms)
int interval; // 窗口总大小(如 1s)
// 获取当前时间片的统计数据
WindowWrap getCurrentWindow() {
long time = System.currentTimeMillis();
int idx = (int) ((time / windowSize) % array.length);
WindowWrap window = array[idx];
// 如果时间片过期,重置
if (window.time < time - interval) {
window.reset();
}
return window;
}
}
2. 令牌桶算法(Token Bucket)
- 作用:用于匀速排队模式的流量控制。
- 原理:
- 系统以固定速率向令牌桶添加令牌。
- 每个请求需要从桶中获取一个令牌才能通过。
- 如果令牌不足,请求排队等待或被拒绝。
- 实现:
- Sentinel 的匀速排队模式基于令牌桶算法。
- 配置 QPS 阈值后,系统按
1/QPS
的时间间隔生成令牌。 - 请求到达时,计算所需等待时间(基于当前令牌数和生成速率)。
- 优势:
- 平滑流量,避免突刺。
- 支持配置最大排队时间,防止请求无限等待。
- 应用:
- API 网关、消息队列等需要匀速处理的场景。
代码示例(伪代码):
class TokenBucket {
double rate; // 每秒令牌生成速率
double capacity; // 桶容量
double tokens; // 当前令牌数
long lastRefill; // 上次填充时间
boolean tryAcquire() {
refill(); // 填充令牌
if (tokens >= 1) {
tokens -= 1;
return true;
}
return false;
}
void refill() {
long now = System.currentTimeMillis();
double newTokens = (now - lastRefill) * rate / 1000;
tokens = Math.min(capacity, tokens + newTokens);
lastRefill = now;
}
}
3. 漏桶算法(Leaky Bucket)
- 作用:用于冷启动(Warm-up)模式的流量控制。
- 原理:
- 请求以固定速率从漏桶中流出,模拟系统逐渐“加热”。
- 冷启动期间,初始速率较低,逐渐增加到目标速率。
- 实现:
- Sentinel 的冷启动模式基于漏桶算法。
- 配置冷启动时间(如 10s)和目标 QPS,系统根据时间线性增加允许的 QPS。
- 公式:当前允许 QPS = 初始 QPS + (目标 QPS - 初始 QPS) * (当前时间 / 冷启动时间)。
- 应用:
- 系统启动、缓存失效等场景,防止瞬时流量过载。
代码示例(伪代码):
class LeakyBucket {
double targetQps; // 目标 QPS
double initialQps; // 初始 QPS
long warmupPeriod; // 冷启动时间
long startTime; // 开始时间
boolean allowRequest() {
long now = System.currentTimeMillis();
double currentQps = calculateCurrentQps(now);
// 基于当前 QPS 判断是否允许通过
return checkQps(currentQps);
}
double calculateCurrentQps(long now) {
if (now - startTime >= warmupPeriod) {
return targetQps;
}
return initialQps + (targetQps - initialQps) * (now - startTime) / warmupPeriod;
}
}
4. 熔断降级算法
- 作用:检测资源异常并触发熔断。
- 原理:
- Sentinel 支持两种熔断策略:
- 慢调用比例(Slow Request Ratio):
- 当请求的平均 RT 超过阈值,且慢调用比例超过设定值时触发熔断。
- 例如:RT > 500ms 的请求占比 > 50%,则熔断。
- 异常比例/异常数(Error Ratio/Error Count):
- 当异常请求比例或异常总数超过阈值时触发熔断。
- 例如:异常比例 > 60% 或异常数 > 10。
- 慢调用比例(Slow Request Ratio):
- 熔断后进入“断开”状态,持续一段时间(可配置)。
- 随后进入“半开”状态,允许少量请求通过,若成功则恢复,否则继续熔断。
- Sentinel 支持两种熔断策略:
- 实现:
- 使用滑动窗口统计慢调用和异常数据。
- 定期检查是否满足熔断条件。
- 熔断状态通过状态机(State Machine)管理(闭合、断开、半开)。
- 应用:
- 保护下游服务,防止级联失败。
代码示例(伪代码):
class CircuitBreaker {
enum State { CLOSED, OPEN, HALF_OPEN }
State state = State.CLOSED;
long openTime; // 熔断开始时间
double errorRatioThreshold; // 异常比例阈值
int minRequestCount; // 最小请求数
boolean allowRequest() {
if (state == State.OPEN) {
if (System.currentTimeMillis() > openTime + recoveryTimeout) {
state = State.HALF_OPEN;
return true; // 允许尝试恢复
}
return false;
}
if (state == State.HALF_OPEN) {
return tryRecover();
}
// CLOSED 状态,检查是否需要熔断
if (shouldOpen()) {
state = State.OPEN;
openTime = System.currentTimeMillis();
return false;
}
return true;
}
boolean shouldOpen() {
Metric metric = getMetric();
if (metric.requestCount < minRequestCount) {
return false;
}
return metric.errorCount / metric.requestCount > errorRatioThreshold;
}
}
5. 系统自适应限流算法
- 作用:根据系统负载动态调整流量。
- 原理:
- Sentinel 监控系统指标(CPU 使用率、负载、RT、入口 QPS、线程数)。
- 当指标超过阈值时,动态降低允许的入口流量。
- 算法参考了 TCP 拥塞控制思想,使用类似“加性增、乘性减”(AIMD)的策略:
- 系统正常时,缓慢增加流量。
- 系统过载时,快速减少流量。
- 实现:
- 使用滑动窗口统计入口 QPS 和系统指标。
- 根据负载情况计算动态 QPS 阈值。
- 公式(简化):
allowedQps = min(maxQps, maxQps * (1 - loadFactor))
。
- 应用:
- 防止系统整体崩溃,适合高并发场景。
代码示例(伪代码):
class AdaptiveLimiter {
double maxQps; // 最大 QPS
double cpuThreshold; // CPU 使用率阈值
boolean allowRequest() {
double cpuUsage = getCpuUsage();
double loadFactor = Math.max(0, cpuUsage - cpuThreshold) / (1 - cpuThreshold);
double allowedQps = maxQps * (1 - loadFactor);
// 基于 allowedQps 判断是否允许通过
return checkQps(allowedQps);
}
}
五、Sentinel 的使用示例
以下是一个简单的 Sentinel 使用示例,展示如何定义资源并配置限流规则。
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import java.util.ArrayList;
import java.util.List;
public class SentinelDemo {
public static void main(String[] args) {
// 配置限流规则
initFlowRules();
// 模拟请求
for (int i = 0; i < 20; i++) {
try (Entry entry = SphU.entry("HelloWorld")) {
// 业务逻辑
System.out.println("Request passed: " + i);
} catch (BlockException e) {
// 被限流
System.out.println("Request blocked: " + i);
}
}
}
private static void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("HelloWorld"); // 资源名称
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 基于 QPS 限流
rule.setCount(10); // QPS 阈值
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
输出示例:
Request passed: 0
Request passed: 1
...
Request passed: 9
Request blocked: 10
Request blocked: 11
...
六、Sentinel 的优势与不足
优势:
- 高性能:基于内存计算和高效算法,单机性能极高。
- 灵活性:支持多种限流、熔断策略,适配主流框架。
- 动态配置:规则支持实时修改,适合动态场景。
- 丰富的监控:提供详细的指标和 Dashboard,方便调试。
- 社区活跃:背靠阿里巴巴,文档完善,生态丰富。
不足:
- 学习成本:概念较多,初学者需理解资源、规则、Slot 等。
- 分布式限流复杂:集群流控需要额外部署 Token Server。
- 功能重叠:与 Hystrix、Resilience4j 等工具功能部分重叠,选型需权衡。
七、总结
Sentinel 是一个功能强大、性能优异的流量治理中间件,适用于分布式系统的高可用保护。其核心算法(如滑动窗口、令牌桶、漏桶、熔断降级、系统自适应)提供了灵活且高效的流量控制能力。通过合理的配置和集成,Sentinel 可以显著提升系统的稳定性和可靠性。