sentinel-滑动时间窗口算法探索

本文深入探讨了Sentinel的滑动时间窗口算法原理及其应用。通过具体实例解释了如何利用滑动时间窗口进行流量统计,并展示了算法背后的代码实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

    其实sentinel核心原理并不难理解,就是在访问被保护资源时,根据实时的统计信息和预先定义的规则,检查是否可以访问。对我自己而言,可能统计的算法是比较关心的,都知道sentinel的统计算法是滑动时间窗口算法,这个算法一这么说就不接地气了,下面谈谈我们农村的说法。

探索

    说这个算法主要要解决什么事呢?就是说在某个时间间隔要做点统计,比如说现在时间是16:06:21,320,我现在想知道16:06:21,000-16:06:21,320我的应用app通过了多少个请求,即当前的320ms通过了多少请求?哎这个简单啊,等我数数。。。,直接说说sentinel怎么搞的,想想文字说起来苍白无力,来点图片看看。

sentinel时间窗口

 

    就如图片展示的,想统计一段时间内的数据,就定义一个WindowWrap(时间窗口)来实现,在时间轴上随着时间的流逝,会有无限多连续的时间窗口,时间窗口通过MetricBucket来统计数据,都统计什么数据呢,MetricEvent定义了相关的统计数据类型,不同的统计数据类型由一个LongAdder来计数,这样在请求到来的时候先根据当前时间戳定位时间窗口,由当前的时间窗口来记录需要统计的信息,至于LeapArray是怎么回事,代码逻辑比较容易理解,但是设计意图在这里还不是特别清晰,可以看看其sampleCount这个属性,应该能有所猜测,再多的可以到下文再仔细品味下。

    咋就好像说完了呢,还不到10块钱的,再继续聊聊,上代码,不详细说为什么代码执行流程了,就看看关键的代码。

public class{
    private final LeapArray<MetricBucket> data;
    public void addPass(int count) {
       WindowWrap<MetricBucket> wrap = data.currentWindow();
       wrap.value().addPass(count);
    }
}
public abstract class LeapArray{
    public WindowWrap<T> currentWindow(long timeMillis) {
        if (timeMillis < 0) {
            return null;
        }
        //计算当前时间在数组中的位置
        int idx = calculateTimeIdx(timeMillis);
        //计算当前时间窗口的开始时间
        long windowStart = calculateWindowStart(timeMillis);
        while (true) {
            //在数组中获取时间窗口,注意这里的old是说时间窗口已经创建过了
            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();
                }
            //如果开始时间等于old的开始时间就把old返回
            } else if (windowStart == old.windowStart()) {
                return old;
            //如果大于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));
            }
        }
    }
}
public class MetricBucket {
    public MetricBucket add(MetricEvent event, long n) {
        //找到对应的事件LongAdder递增
        counters[event.ordinal()].add(n);
        return this;
    }
}

    结合代码又进一步了解了sentinel的滑动时间窗口算法,一段时间(事件窗口)+统计对象,即时间在时间窗口中滑动并作数据统计。说到这里其实算法这块差不多结束了,不行我这暴脾气上来了,就说咋统计了,那统计完咋用的啊?那就再看看。

public class StatisticNode implements Node {
    public long totalPass() {
        return rollingCounterInMinute.pass();
    }
}
public class ArrayMetric implements Metric {
    public long pass() {
        data.currentWindow();
        long pass = 0;
        List<MetricBucket> list = data.values();

        for (MetricBucket window : list) {
            pass += window.pass();
        }
        return pass;
    }
}
public class MetricBucket {
    public long pass() {
        return get(MetricEvent.PASS);
    }
    public long get(MetricEvent event) {
        return counters[event.ordinal()].sum();
    }
}

    这就明白了,不就是找在固定时间间隔内所有时间窗口样本的统计数据嘛,还记得sampleCount(LeapArray)吗?好像有点内味了,再看看qps。

public class StatisticNode implements Node {
    public double passQps() {
        return rollingCounterInSecond.pass() / rollingCounterInSecond.getWindowIntervalInSec();
    }
}

    qps=所有样本请求通过数/固定时间间隔,呦,这么一看我可以把时间间隔搞得小一点比如(500ms,默认1000ms),那样本数我也不搞那么多,我让窗口长度就是500,那统计qps的时候就是1个500ms的qps,这样好像避免了统计学的误差哈,那要是。。。,剩下的自己动手吧。

总结

    有兴趣可以自己实现下滑动时间窗口算法,有了sentinel的启发,相信实现起来难度不会太大,那再多说一下啊如果去掉时间二字,就变成了滑动窗口算法,这个算法的定义百度一下都能找得到,那我们可以再思索下sentinel的滑动时间窗口算法在算法角度,到底带来了多大的好处。

<think>好的,我现在需要回答用户关于Apache Sentinel的服务治理中的滑动窗口算法的问题。用户之前已经询问过Sentinel的各个方面,现在具体到Apache Sentinel滑动窗口算法,我需要详细解释这个算法的原理、作用以及应用场景。 首先,我需要确认自己是否正确理解滑动窗口算法Sentinel中的应用。Apache Sentinel是一个流量控制和熔断降级的框架,主要用于微服务架构中保护服务的稳定性。滑动窗口算法在这里应该是用来实时收集和统计流量数据,以便进行动态的流量控制决策。 接下来,我需要回顾一下滑动窗口的基本概念。滑动窗口通常用于流数据处理,通过维护一个时间窗口内的数据,随着时间推移,窗口向前滑动,丢弃旧数据,加入新数据。这样能够实时反映最新的数据状态,适用于需要实时监控的场景。 然后,我需要具体到Apache Sentinel的实现细节。Sentinel中的滑动窗口可能分为多个时间窗口,比如将1秒分成多个更小的窗口,例如2个500毫秒的窗口。这样的设计可以更细粒度地收集数据,并在每个时间窗口结束时汇总统计信息,如请求数、异常数等,从而实时更新流量指标。 需要区分滑动窗口的不同类型,比如时间窗口和计数窗口。在Sentinel中,可能主要使用基于时间的滑动窗口来统计QPS、响应时间等指标。同时,还要解释滑动窗口如何帮助Sentinel进行流量控制,比如根据窗口内的统计数据决定是否触发流控规则或熔断机制。 此外,需要举例说明滑动窗口的工作流程,比如当一个新的请求进入时,如何被分配到当前时间对应的子窗口,统计信息如何更新,以及如何根据这些信息判断是否超过阈值。同时,要提到滑动窗口的优势,比如低延迟、实时性强,以及资源的高效利用,避免维护大量历史数据。 最后,需要确保解释清晰,结构合理,使用中文,符合用户的要求,并且遵循之前设定的格式,如使用行内数学公式和独立公式的正确LaTeX格式。还要检查是否有遗漏的重要点,比如滑动窗口在熔断降级中的具体应用,或者与其他算法的对比,如漏桶算法、令牌桶算法的区别。</think>### Apache Sentinel 服务治理中的滑动窗口算法 Apache Sentinel 的**滑动窗口算法**是其流量控制与实时统计的核心机制,用于动态采集、聚合资源(如接口)的访问数据(如QPS、响应时间、异常比例),从而支持精准的**流量控制**和**熔断降级**策略。以下是详细解析: --- #### 一、算法原理 1. **时间窗口分割** Sentinel 将统计周期(例如 `1秒`)划分为多个**子窗口**(如 `2个500ms窗口`),每个子窗口独立记录当前时间段的指标数据。 - **示例**:统计周期为 `1秒`,分割为 `2个子窗口`,每个子窗口覆盖 `500ms`。 $$ \text{子窗口数量} = \frac{\text{统计周期}}{\text{子窗口长度}} $$ 2. **窗口滑动机制** - 系统以固定步长(如 `100ms`)向前滑动,淘汰过期子窗口,保留最新子窗口。 - **动态更新**:每次滑动时,丢弃最旧的子窗口数据,将新产生的子窗口加入统计范围。 $$ \text{当前有效窗口} = [\text{当前时间} - \text{统计周期}, \text{当前时间}] $$ 3. **数据聚合** 实时聚合当前所有有效子窗口的数据(如请求总数、异常数、响应时间总和),生成全局指标。 - **计算公式**: $$ \text{QPS} = \frac{\text{有效窗口内总请求数}}{\text{统计周期}} $$ --- #### 二、工作流程(以统计QPS为例) 1. **请求到达** 当资源(如API接口)收到请求时,系统根据当前时间戳确定所属的子窗口。 2. **子窗口更新** - 若子窗口已过期(超出统计周期),则创建新子窗口并重置计数。 - 若子窗口有效,则递增该子窗口的请求计数、记录响应时间等。 3. **滑动窗口维护** 周期性检查子窗口的有效性,淘汰超出统计周期的旧数据。 4. **实时指标计算** 聚合当前所有有效子窗口的数据,得到实时QPS、平均响应时间等指标。 5. **流量控制决策** 将实时指标与预设规则(如 `QPS阈值=100`)对比,触发流控(如拒绝请求)或熔断(如阻断链路)。 --- #### 三、核心优势 | 特性 | 说明 | |---------------------|--------------------------------------------------------------------| | **低延迟** | 细粒度子窗口(如500ms)确保统计数据更新延迟小于子窗口长度,实时性强。 | | **高精度** | 基于时间滑动避免固定窗口的“临界突变”问题(如窗口切换瞬间的流量尖峰)。 | | **资源高效** | 仅维护有限数量的子窗口(如10个子窗口),内存占用可控。 | --- #### 四、应用场景 1. **流量控制(Flow Control)** - 根据滑动窗口统计的实时QPS,触发**直接拒绝**或**排队等待**。 - **示例规则**:若 `/api` 的QPS超过100,则后续请求直接拒绝。 2. **熔断降级(Circuit Breaking)** - 基于异常比例或慢调用比例触发熔断。 - **示例规则**:若最近10秒内异常请求比例超过50%,则熔断该接口5秒。 3. **自适应系统保护** 结合CPU负载、平均响应时间等滑动窗口指标,动态调整流量阈值。 --- #### 五、代码示例(简化逻辑) ```java // 定义滑动窗口:1秒统计周期,分为2个子窗口 TimeWindowLeap
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

&一步

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值