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

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

简介

    其实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的滑动时间窗口算法在算法角度,到底带来了多大的好处。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

&一步

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

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

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

打赏作者

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

抵扣说明:

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

余额充值