zoukankan      html  css  js  c++  java
  • RateLimiter 平滑限流之非突发、非预热

    平滑限流

    什么是平滑限流? 平就是平稳、滑是没有折线(好像也不太准确),没有曲线?(曲线其实也可以有Smooth的意思)丝滑?总之是比较Smooth就对了。guava中RateLimiter 的实现只有平滑限流的实现,即SmoothRateLimiter。 而SmoothRateLimiter 也是抽象的,它有两个实现,一个是突发实现即SmoothBursty,一个是预热实现即SmoothWarmingUp。

    突发限流的方法是一个参数,而预热限流的方法是三个参数的方法,具体可见源码:

    static RateLimiter create(
          SleepingStopwatch stopwatch, double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
        RateLimiter rateLimiter = new SmoothWarmingUp(stopwatch, warmupPeriod, unit);
        rateLimiter.setRate(permitsPerSecond);
        return rateLimiter;
      }
    

    可见预热限流是SmoothWarmingUp

    预热时间为0 的预热限流

    预热时间为0 的预热限流 是一个什么情况?

    注意到上方法的第一个参数是和突发限流的方法是一样的,都是每秒的许可数。上方法的第二个参数是预热时间。最后一个参数是时间单位。 第一个参数自然是不能小于等于0的, 不能失去了意义。 第二个参数当然不能小于0,否则无法解释;那它是否可以等于0? 测试发现是可以的。

    当预热限流的方法的第二个参数是0的时候,预热的效果就消失,也就是没有了预热。这就变成了一个特殊的情况, 也就是也非突发、既非预热。SmoothWarmingUp的图形变成了一个点! 尽管如此,虽然此时预热时间为0,那么它是否就没有了任何的缓存许可的功能? 非也!

    通过上文的分析,加上测试,发现SmoothWarmingUp 并不会积累permits。 就是说,使用的时候立即达到最高速度,不使用的时候立即冷却,此时速度呢? 其实冷却的时候速度都也不重要,实际上是无穷大,但是没有意义,因为加速的过程为0, 所以也可以把冷却的速度理解为0(更好理解)。就是说,基本上SmoothWarmingUp 只会使用2个速度:使用时max,不使用时0;

    RateLimiter r = RateLimiter.create(2, 0, TimeUnit.MILLISECONDS);
    漏桶,因为它本质上是令牌桶上做了修改。SmoothWarmingUp

    SmoothWarmingUp 到底是漏桶还是令牌桶

    其实上文说错了。答案是明确的,SmoothWarmingUp 应该算是漏桶,一般情况下,也就是当预热时间不为0的时候。我们知道SmoothWarmingUp有一个冷却的过程,而这个冷却的过程,就是可以理解为漏桶的令牌漏出的过程!但是呢, 正常理解的漏桶,如果桶内令牌足够,应该是可以直接获取而不用等待的(不管是否已经开始了冷却)。而我们知道SmoothWarmingUp不是的,SmoothWarmingUp一旦开始了冷却,它就必须要至少需要等待一些些的预热时间,也就是说需要比稳定状态时更久的时间!!

    而且,我们知道,SmoothWarmingUp的整个加热过程(包括预热和准稳定过程) 并不是一个直线,而是折线,这和我们想象中的理想的漏桶恐怕还是不一样。

    测试观察

    @org.junit.Test
        public void testSmoothWarmingWith0() {
            RateLimiter r = RateLimiter.create(2, 0, TimeUnit.MILLISECONDS);
            while (true)
            {
                System.out.println("get 2 tokens: " + r.acquire(2) + "s");// 2个需要1s,但许可获取时间由下一次获取承担; 循环的首次,此行等待时间为0,第二次以后的等待时间为⑤ 行的许可获取时间,即0.5s
                try {
                    Thread.sleep(1500);// 休息1.5s,可以完全消耗上行的2个许可,并剩出来0.5s,但是因为 预热/冷却时间为0,所以这个0.5s 其实是完全白白的流逝了..
                } catch (Exception e) {
                }
                System.out.println("get 3 tokens: " + r.acquire(3) + "s");// 因为 预热/冷却时间为0,前面的许可已经完全被补偿,所以此处3个需要1.5s,但时间地点时间为0,许可获取时间由下一次获取承担
                System.out.println("get 1 tokens: " + r.acquire(1) + "s");// 上一个方法的实际等待时间为0,因为它由此方法承担—— 此方法实际等待时间为上一个方法的3个许可获取时间,即1.5s
                System.out.println("get 1 tokens: " + r.acquire(1) + "s");// 此方法实际等待时间为上一个方法的1个许可获取时间,即0.5s
                System.out.println("get 1 tokens: " + r.acquire(1) + "s");// ⑤ 此方法实际等待时间为上一个方法的1个许可获取时间,即0.5s
                System.out.println("end");
            }
        }
    

    观察日志打印,发现符合预期。

    get 2 tokens: 0.0s
    get 3 tokens: 0.0s
    get 1 tokens: 1.499681s
    get 1 tokens: 0.494564s
    get 1 tokens: 0.498945s
    end
    get 2 tokens: 0.499013s
    get 3 tokens: 0.0s
    get 1 tokens: 1.499839s
    get 1 tokens: 0.499698s
    get 1 tokens: 0.499081s
    end
    get 2 tokens: 0.499659s
    get 3 tokens: 0.0s
    get 1 tokens: 1.499842s
    get 1 tokens: 0.498895s
    get 1 tokens: 0.499479s
    

    SmoothWarmingUp 整个加热过程是不是可以为一条直线?

    理论上来讲,SmoothWarmingUp 的斜率变成0,那么整个加热过程的就是一天直线。但是其实这个在SmoothWarmingUp 中是不可能发生的。 因为SmoothWarmingUp 的一个假设是 预热时间 = 冷却时间。如果斜率变成了0,那么预热时间 = 冷却时间 就不可能满足,除非预热时间变成了0,这就又回到了我们开始讨论的情况,也就是变成了一个点。


    版权声明
    本文原创发表于 博客园,作者为 阿K .     本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
    欢迎关注本人微信公众号:觉醒的码农,或者扫码进群:

  • 相关阅读:
    DLL注入之Appinit_Dlls
    VC下遍历文件夹中的所有文件的几种方法
    Windows下C语言的Socket编程例子(TCP和UDP)
    Windows进程间共享内存通信实例
    window下线程同步之(Mutex(互斥器) )
    如何安装win10和linux [ubuntu14]双系统
    Windows虚拟地址转物理地址(原理+源码实现,附简单小工具)
    Windows驱动中通过MDL实现用户态与核心态共享内存
    C# Label显示多行文本及换行(WinForm/WebForm)
    使用delegate实现简单的查询功能
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/14646372.html
Copyright © 2011-2022 走看看