文档章节

Alibaba Sentinel 源码阅读(Part 2 LeapArray)

OrangeJoke
 OrangeJoke
发布于 2018/10/21 12:00
字数 678
阅读 825
收藏 0

前言

这一篇是上一篇的继续,如果不了解Sentinel ,请先阅读[Alibaba Sentinel 源码阅读(Part1 执行流程)](Alibaba Sentinel 源码阅读(Part1 执行流程))

入口

在上一篇我们看到 我们获取的所有信息,都是从StatisticNode 的这两个数据结构中获取的

private transient volatile Metric rollingCounterInSecond = new ArrayMetric(1000 / SampleCountProperty.SAMPLE_COUNT,
        IntervalProperty.INTERVAL);

    /**
     * Holds statistics of the recent 120 seconds. The windowLengthInMs is deliberately set to 1000 milliseconds,
     * meaning each bucket per second, in this way we can get accurate statistics of each second.
     */
    private transient Metric rollingCounterInMinute = new ArrayMetric(1000, 2 * 60);

rollingCounterInMinute 这个两分钟之内的每一秒中数据的一个list,而每一秒中的数据是存储在 MetricBucket,

ArrayMetric

// ArrayMetric 实现了Metric 接口,同时包含了 MetricsLeapArray数据结构,接口的实现就是通过这个MetricsLeapArray来实现的
// MetricsLeapArray 是从 LeapArray 继承的,所以这一篇的重点就是LeapArray了
public class ArrayMetric implements Metric {
    private final MetricsLeapArray data;

    /**
     * Constructor
     *
     * @param windowLengthInMs a single window bucket's time length in milliseconds.
     * @param intervalInSec    the total time span of this {@link ArrayMetric} in seconds.
     */
    public ArrayMetric(int windowLengthInMs, int intervalInSec) {
        this.data = new MetricsLeapArray(windowLengthInMs, intervalInSec);
    }
}

LeapArray

实际上就是一个环形数组,来给张官方的图就明白了

看文档其实很清晰,整个是基于时间窗口滑动算法来实现的

新增当前统计数据

@Override
    public void addSuccess() {
        WindowWrap<MetricBucket> wrap = data.currentWindow();
        wrap.value().addSuccess();
    }

获取时间窗口内统计数据

@Override
    public long success() {
        data.currentWindow();
        long success = 0;

        List<MetricBucket> list = data.values();
        for (MetricBucket window : list) {
            success += window.success();
        }
        return success;
    }

所以重点的方法就是 data.currentWindow()方法了

protected final AtomicReferenceArray<WindowWrap<T>> array;

public LeapArray(int windowLengthInMs, int intervalInSec) {
        this.windowLengthInMs = windowLengthInMs;
        this.intervalInMs = intervalInSec * 1000;
        this.sampleCount = intervalInMs / windowLengthInMs;
        // 初始化容量大小
        this.array = new AtomicReferenceArray<WindowWrap<T>>(sampleCount);
    }


  /**
     * Get window at provided timestamp.
     *
     * @param time a valid timestamp
     * @return the window at provided timestamp
     */
    public WindowWrap<T> currentWindow(long time) {
        long timeId = time / windowLengthInMs;
        // Calculate current index.
        int idx = (int)(timeId % array.length());

        // Cut the time to current window start.
        time = time - time % windowLengthInMs;

        while (true) {
            WindowWrap<T> old = array.get(idx);
            if (old == null) {
                WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, time, newEmptyBucket());
                if (array.compareAndSet(idx, null, window)) {
                    return window;
                } else {
                    Thread.yield();
                }
            } else if (time == old.windowStart()) {
                return old;
            } else if (time > old.windowStart()) {
                if (updateLock.tryLock()) {
                    try {
                        // if (old is deprecated) then [LOCK] resetTo currentTime.
                        return resetWindowTo(old, time);
                    } finally {
                        updateLock.unlock();
                    }
                } else {
                    Thread.yield();
                }

            } else if (time < old.windowStart()) {
                // Cannot go through here.
                return new WindowWrap<T>(windowLengthInMs, time, newEmptyBucket());
            }
        }
    }


这部分的内容会维持一个有效的环形数组以统计数据,具体要自己debug 看了。

总结

这里也只是把大致流程梳理了一下方便大家看源码而已,很多地方没有具体分析,这部分还是需要自己亲力亲为。

参考

Window Sliding Technique

© 著作权归作者所有

OrangeJoke
粉丝 40
博文 57
码字总数 39185
作品 0
江北
高级程序员
私信 提问
聊聊sentinel的ArrayMetric

序 本文主要研究一下sentinel的ArrayMetric ArrayMetric com/alibaba/csp/sentinel/slots/statistic/metric/ArrayMetric.java ArrayMetric底层使用WindowLeapArray作为数据存取 该类实现了指......

go4it
2018/08/21
49
0
Spring Cloud Alibaba迁移指南2:一行代码从Hystrix迁移到Sentinel

本文对Hystrix、Resilience4j、Sentinel进行对比,并探讨如何使用一行代码将Hystrix迁移到Sentinel。 作者:洛夜,校对:周立 在本博客首发,欢迎转载。 前段时间,Netflix宣布Hystrix进入维...

周立_ITMuch
01/28
1K
7
Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel

本文对Hystrix、Resilience4j、Sentinel进行对比,并探讨如何使用一行代码这种极简的方式,将Hystrix迁移到Sentinel。 Hystrix 自从前段时间 宣布停止维护之后,社区推荐了 resilience4j。这...

中间件小哥
02/22
0
0
公益:开放一台Nacos服务端给各位Spring Cloud爱好者

之前开放过一台公益Eureka Server给大家,以方便大家在阅读我博客中教程时候做实验。由于目前在连载Spring Cloud Alibaba,所以对应的也部署了一台Nacos,并且也开放出来,给大家学习测试之用...

程序猿DD
05/14
129
0
Sentinel 1.6.3 正式发布,引入网关流控控制台的支持

Sentinel 1.6.3 正式发布,引入网关流控控制台的支持,同时带来一些 bug 修复和功能改进,欢迎使用! Release Notes: https://github.com/alibaba/Sentinel/releases/tag/1.6.3 新版本特性介...

阿里巴巴中间件
07/30
2.7K
2

没有更多内容

加载失败,请刷新页面

加载更多

springboot初探---spring-boot-starter-web究竟干了啥

上一篇已经简单介绍了启动类的部分,这一篇主要讨论一下springboot引入的哪些依赖 我们都知道想用springboot做一个web应用,首先要做的是引入相关依赖,两步操作: 1、添加spring-boot-start...

计算机狼
31分钟前
5
0
基于Rocket.chat搭建内网聊天系统(使用docker,本机不需要安装meteor)

您可能不希望使用标准的Docker命令,而是希望对部署进行更多的自动化管理。这就是使用Docker-compose可能会派上用场的地方。 确保您已安装Docker和Docker-compose并且可以正常运行。 docker...

吴伟祥
33分钟前
6
0
conda 更新源

更新conda 源为阿里源 conda config --add channels http://mirrors.aliyun.com/pypi/simple conda config --set show_channel_urls yes 阿里云: http://mirrors.aliyun.com/pypi/simple/ 豆......

Mr_Tea伯奕
33分钟前
4
0
java 泛型使用

每次写泛型方法都翻下百度,还是自己记录下把。 1、定义一个泛型方法,使用传入参数类型来传递泛型。这种用法在封装json序列化工具类应该会用到。 List<xxx> aa = getList(xxx.class);pr...

朝如青丝暮成雪
37分钟前
6
0
深入了解Java模板引擎Freemarker

前言 常用的Java模板引擎包括:JSP、Freemarker、Thymeleaf、Velocity,从Github上查阅到这几款主流的模板引擎的性能的对比,总体上看,JSP、Freemarker、Thymeleaf、Velocity在性能上差别不...

code-ortaerc
38分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部