Sentinel滑动窗口前言
Sentinel 是一个开源的高可用性、高扩展性的实时流量控制框架,它可以用于保护服务稳定性,防止系统因为流量过大而崩溃。今天我们所介绍的,是滑动窗口,它是 Sentinel 实现限流和降级的重要组件之一。
Sentinel滑动窗口原理
滑动窗口通常由一个固定大小的时间窗口和一个可滑动的数据结构组成 ,例如队列或滑动块。在 Sentinel 中,滑动窗口被分为计数器类型和预算类型:
计数器滑动窗口:计数器滑动窗口维护一个周期内请求的总数,当周期结束后,滑动窗口会被清空,开始下一个周期的计数。在 Sentinel 中,计数器滑动窗口通过 AtomicLong 数组实现,数组的长度代表时间窗口的大小,每个元素代表该时间片保存的请求次数。
预算滑动窗口:预算滑动窗口维护周期内预算资源的使用情况,以便根据实际资源需要进行限流或降级。预算类型的滑动窗口可以设置阈值,并支持动态调整。在 Sentinel 中,预算滑动窗口通常用于 CPU 使用率、线程池等容量资源的控制。
除此之外,Sentinel 还提供了基于单机、集群和分布式三种模式的滑动窗口实现。其中,单机模式下将使用本地内存来维护滑动窗口数据结构;集群模式下,各节点会通过多播或 Redis 等方式共享相同的计数器数据;分布式模式下,则允许多个服务节点公用同一组滑动窗口数据。
在使用 Sentinel 进行限流和降级时,用户可以通过配置规则来指定需要监控的目标资源,并设置相应的阈值和处理策略。例如,在限流场景下,用户可以设置最大 QPS,并指定超过该阈值的请求将会被丢弃或返回特定的错误码。在降级场景下,用户可以设置响应时间、异常比例等阈值,并指定相应的降级策略,例如返回默认值或者直接抛出异常。
如何在项目中使用滑动窗口
以实际的项目为例子,我们有一个服务用于提供用户信息查询接口,每秒钟最多只能处理 10 次查询请求,并且如果连续 5 秒内的请求次数超过 50 次,则触发限流或降级操作。
在 Sentinel 中,我们首先需要定义一个 FlowRule 数组用于配置针对该服务的限流规则,在这块项目例子中,它们是每秒钟限流到 10 个请求和 5 秒内超过 50 次请求两种限制:
java
FlowRule rule1 = new FlowRule();
rule1.setResource("queryUser");
rule1.setCount(10);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
FlowRule rule2 = new FlowRule();
rule2.setResource("queryUser");
rule2.setCount(50);
rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule2.setStrategy(RuleConstant.STRATEGY_CHAIN);
rule2.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
我们先对以上代码进行解释,"queryUser" 代表资源名称,这个可以自己定义,然后设置了resource、count、grade以及对于第二个规则还增加了三个属性stratety, controlBehavior和controlBehavior。其中 count 表示限流阈值,即每秒钟最多可以处理多少个请求;grade 表示限流模式,QPS(每秒钟最多允许通过的请求数量);strategy 表示限流策略;controlBehavior 表示流量控制的行为。
接下来,我们需要通过执行如下代码初始化 Sentinel:
java
List<FlowRule> rules = new ArrayList<>();
rules.add(rule1);
rules.add(rule2);
FlowRuleManager.loadRules(rules);
我们这里定义了一个 FlowRule 数组,将前面定义好的两个规则加入到列表中,然后通过 FlowRuleManager.loadRules() 方法加载这些规则。
现在,我们可以在查询用户信息的方法上增加 @SentinelResource 注解,并在该注解中设置 blockHandler 和 fallback 属性来处理限流和降级异常:
java
@SentinelResource(value = "queryUser", blockHandler = "queryUserBlockHandler",
fallback = "queryUserFallback")
public UserInfo queryUser(String userId) {
// 查找用户信息的实现
}
// 限流/降级处理函数
public UserInfo queryUserBlockHandler(String userId, BlockException ex) {
// 返回具体的错误信息
}
// 降级处理
public UserInfo queryUserFallback(String userId, Throwable ex) {
// 返回降级后的响应
}
以上代码中我们定义了一个名为"queryUser"的资源,它被 @SentinelResource 注解所修饰,blockHandler 属性表示当该服务触发限流或降级时调用的函数,fallback 属性表示服务出现异常时的回退函数。
最后,我们可以通过对定时任务进行调度,模拟10秒内对同一个 API 请求用户数据的场景,例如代码如下:
java
public class QueryUserTask implements Runnable {
private static final Random random = new Random();
@Override
public void run() {
// 模拟 10 秒内对同一个 API 请求用户数据
for (int i = 0; i < 20; i++) {
String userId = "user-" + (i % 5);
queryUser(userId);
try {
Thread.sleep(random.nextInt(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我们可以在 QueryUserTask 内部实现每隔一秒获取一次用户信息,检测系统是否触发限流或降级保护。如果触发了规则中配置的限流规则,那么 Sentinel 将执行相应的措施进行处理。
好了,本篇文章就先分享到这里了,后续将会继续介绍sentinel详细的其他方面的知识,感谢大佬认真读完支持咯~