当前位置: 首页 > news >正文

sentinel滑动窗口及熔断限流实现原理

滑动窗口机制通过将一个时间窗口拆分为多个时间槽,每个时间槽都有独立的计数器,时间槽划分的越细,那么滑动窗口的滚动就越平滑,统计就会越精确。

Sentinel滑动窗口的核心是抽象类LeapArray:

public abstract class LeapArray<T> {//滑动窗口大小protected int windowLengthInMs;//一个滑动窗口中时间槽的数量protected int sampleCount;//时间槽数组,存储每个槽的统计数据,该数组大小等于sampleCount,随着窗口推移,过期的时间槽被重置,重置现有对象可以减少 GC 压力protected final AtomicReferenceArray<WindowWrap<T>> array;private final ReentrantLock updateLock = new ReentrantLock();//根据当前时间戳获取当前时间槽public WindowWrap<T> currentWindow(long timeMillis) {if (timeMillis < 0) {return null;}int idx = calculateTimeIdx(timeMillis);long windowStart = calculateWindowStart(timeMillis);while (true) {WindowWrap<T> old = array.get(idx);if (old == null) {WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));if (array.compareAndSet(idx, null, window)) {return window;} else {Thread.yield();}} else if (windowStart == old.windowStart()) {return old;} else if (windowStart > old.windowStart()) {if (updateLock.tryLock()) {try {return resetWindowTo(old, windowStart);} finally {updateLock.unlock();}} else {Thread.yield();}} else if (windowStart < old.windowStart()) {return new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));}}}private int calculateTimeIdx(long timeMillis) {long timeId = timeMillis / windowLengthInMs;return (int)(timeId % array.length());}protected long calculateWindowStart(long timeMillis) {return timeMillis - timeMillis % windowLengthInMs;}public abstract T newEmptyBucket(long timeMillis);protected abstract WindowWrap<T> resetWindowTo(WindowWrap<T> windowWrap, long startTime);//......}

WindowWrap类包含以下属性:

  • long windowStart 时间槽开始时间,等于当前时间戳 - 当前时间戳 %  窗口时长windowLengthInMs,用于判断时间槽是否过期
  • T value 统计数据对象,范型类型,根据统计数据的类型,初始化及重置统计对象有不同的实现

获取当前时间槽首先通过calculateTimeIdx方法获取当前时间槽在array中的下标,检查该槽是否存在或过期,不存在则初始化槽对象,过期则重置槽对象中的统计对象。

以Sentinel异常数及异常比例断路器ExceptionCircuitBreaker为例,该类继承LeapArray<SimpleErrorCounter>,其中SimpleErrorCounter包含请求总量及异常数两个属性,每次处理完请求时都获取当前时间槽的SimpleErrorCounter对象,累加请求总量字段,请求异常时累加异常数字段,且当请求异常时,遍历时间槽数组array,统计所有时间槽的请求总量及异常数,计算异常数或异常比例是否达到熔断阈值。

只有当请求到达时才创建或重置时间槽,减少空窗口的资源占用。通过偏移量计算快速定位有效时间槽减少不必要的遍历。重用过期时间槽,减少内存消耗。

Sentinel责任链:

Sentinel熔断限流规则的执行是通过责任链模式(ProcessorSlotChain)实现的,每个 Slot 负责特定的功能(如限流、熔断、系统保护等),用户可以动态将规则注册到对应的Slot中。

Sentinel 核心 Slot 包括:

NodeSelectorSlot:构建调用链路的上下文(Context)和节点(Node),负责收集资源的路径,并将资源的调用路径以树状结构存储起来,可用于根据调用路径进行限流降级。

ClusterBuilderSlot:构建集群节点,用于统计全局数据

LogSlot:日志记录

StatisticSlot:主要功能是记录、统计不同维度的运行时指标监控信息。它会在请求进入和退出时,更新相关的统计数据,如记录请求通过数、阻塞数、异常数等,为后续的规则判断提供数据支持

AuthoritySlot:黑白名单控制

SystemSlot:系统保护(负载、CPU 使用率等)

FlowSlot:流量控制(限流)

DegradeSlot:熔断降级(基于异常比例 / 数量、RT)

Sentinel槽链中各Slot的执行顺序是固定好的。但并不是绝对不能改变的。SentinelProcessorSlot 作为 SPI 接口进行扩展,使得 SlotChain 具备了扩展能力。用户可以自定义Slot并编排Slot 间的顺序。

 Sentinel 提供如下的扩展点:

初始化过程扩展:提供 InitFunc SPI接口,可以添加自定义的一些初始化逻辑,如动态规则源注册等。
Slot/Slot Chain 扩展:用于给 Sentinel 功能链添加自定义的功能并自由编排。
指标统计扩展(StatisticSlot Callback):用于扩展 StatisticSlot 指标统计相关的逻辑。
Transport 扩展:提供 CommandHandler、CommandCenter 等接口,用于对心跳发送、监控 API Server 进行扩展。
集群流控扩展:可以方便地定制 token client/server 自定义实现,可参考对应文档
日志扩展:用于自定义 record log Logger,可用于对接 slf4j 等标准日志实现。

Sentinel规则注册:

熔断限流规则 由 FlowSlot 和 DegradeSlot 处理。用户动态配置的规则会通过 XxxRuleManager 注册到对应的 Slot 中。

// 注册限流规则
List<FlowRule> flowRules = new ArrayList<>();
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);// 注册熔断规则
List<DegradeRule> degradeRules = new ArrayList<>();
degradeRules.add(degradeRule);
DegradeRuleManager.loadRules(degradeRules);

每个Slot被执行时会从对应的RuleManager 获取熔断规则,如DegradeSlot 会从 DegradeRuleManager 获取熔断规则,然后基于 StatisticSlot 统计的 RT 或异常数据进行熔断判断。

http://www.lqws.cn/news/592867.html

相关文章:

  • STM32作为主机识别鼠标键盘
  • Gradio全解13——MCP协议详解(5)——Python包命令:uv与uvx实战
  • Easy Window UI设计器 - 图表组件 10秒完成UI效果
  • Xposed框架深度解析:Android系统级Hook实战指南
  • Flask+LayUI开发手记(十):构建统一的选项集合服务
  • QGIS合并、拆分SHP文件
  • 深入理解栈的合法弹出序列验证算法
  • docusaurus初步体验
  • Bootstrap 安装使用教程
  • 多bin技术:为LoRa项目赋能的高效远程升级方案
  • OpenCV CUDA模块设备层-----双曲正切函数tanh()
  • Terraform Helm:微服务基础设施即代码
  • 《UE5_C++多人TPS完整教程》学习笔记39 ——《P40 远程过程调用(Remote Procedure Calls)》
  • LabVIEW自动扶梯振动监测
  • RabbitMQ简单消息发送
  • Node.js与Express框架的深度整合
  • beego打包发布到Centos系统及国产麒麟系统完整教程
  • react-数据Mock实现——json-server
  • 飞算 JavaAI 开发助手:深度学习驱动下的 Java 全链路智能开发新范式
  • 发票PDF处理工具,智能识别合并一步到位
  • Foundation 5 安装使用教程
  • 【Unity实战】UI按钮回调管理:职责分离与持久化策略
  • 基于 Vue + RuoYi 架构设计的商城Web/小程序实训课程
  • 网络基础知识与代理配置
  • Java 大视界 -- Java 大数据在智能交通共享单车智能调度与停放管理中的应用(329)
  • 数字雨动画背景
  • 深入剖析AI大模型:TensorFlow
  • 浅谈「线性代数的本质」 - 系列合集
  • 系统思考力量与实践
  • 从数据资产识别与防泄密看零信任产品