zoukankan      html  css  js  c++  java
  • 高并发之限流令牌桶和漏桶算法(一)

    在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流

    • 缓存 缓存的目的是提升系统访问速度和增大系统处理容量
    • 降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解决后再打开
    • 限流 限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理

    常用的限流算法

    漏桶算法

    漏桶算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。

     
    下面时伪代码:
    public class TokenBucketDemo {
        public long timeStamp = getNowTime();
        public int capacity; // 桶的容量
        public int rate; // 水漏出的速度
        public int water; // 当前水量(当前累积请求数)
        public boolean grant() {
            long now = getNowTime();
            water = max(0, water - (now - timeStamp) * rate); // 先执行漏水,计算剩余水量
            timeStamp = now;
            if ((water + 1) < capacity) {
                // 尝试加水,并且水还未满
                water += 1;
                return true;
            }
            else {
                // 水满,拒绝加水
                return false;
            }
        }
    }

    漏桶算法不能够有效地使用网络资源。因为漏桶的漏出速率是固定的参数,所以即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使某一个单独的流突发到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。

    令牌桶算法

    对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。如图所示,令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。

     

    令牌桶算法图例

     a. 按特定的速率向令牌桶投放令牌

     b. 根据预设的匹配规则先对报文进行分类,不符合匹配规则的报文不需要经过令牌桶的处理,直接发送;

     c. 符合匹配规则的报文,则需要令牌桶进行处理。当桶中有足够的令牌则报文可以被继续发送下去,同时令牌桶中的令牌 量按报文的长度做相应的减少;

     d. 当令牌桶中的令牌不足时,报文将不能被发送,只有等到桶中生成了新的令牌,报文才可以发送。这就可以限制报文的流量只能是小于等于令牌生成的速度,达到限制流量的目的。

    注意:当令牌不足时,这里报文:

    1、可以被丢弃

    2、可以排放在队列中以便当令牌桶中累积了足够多的令牌时再传输

    3、可以继续发送,但需要做特殊标记,网络过载的时候将这些特殊标记的包丢弃

     伪代码:

    public class TokenBucketDemo {
        public long timeStamp = getNowTime();
        public int capacity; // 桶的容量
        public int rate; // 令牌放入速度
        public int tokens; // 当前令牌数量
        public boolean grant() {
            long now = getNowTime();
            // 先添加令牌
            //min(桶的容量,当前令牌 + 上次请求获取令牌时间到当前时间内生成的令牌)
            tokens = min(capacity, tokens + (now - timeStamp) * rate);
            timeStamp = now;
            if (tokens < 1) {
                // 若不到1个令牌,则拒绝
                return false;
            }
            else {
                // 还有令牌,领取令牌
                tokens -= 1;
                return true;
            }
        }
    }

    令牌桶算法临界问题思考:

    场景:在0:59秒的时候有100个请求过来,此时令牌桶有100个token,瞬间通过。1:00的时候又有100个请求,但令牌放入令牌桶是有一定的速率的,假设rate<100,不可能100个请求都通过。避免了计数器算法瞬间请求过大,压垮系统。

    令牌桶和漏桶对比:

    • 令牌桶是按照固定速率往桶中添加令牌,请求是否被处理需要看桶中令牌是否足够,当令牌数减为零时则拒绝新的请求;

    • 漏桶则是按照常量固定速率流出请求,流入请求速率任意,当流入的请求数累积到漏桶容量时,则新流入的请求被拒绝;

    • 令牌桶限制的是平均流入速率(允许突发请求,只要有令牌就可以处理,支持一次拿3个令牌,4个令牌),并允许一定程度突发流量;

    • 漏桶限制的是常量流出速率(即流出速率是一个固定常量值,比如都是1的速率流出,而不能一次是1,下次又是2),从而平滑突发流入速率;

    • 令牌桶允许一定程度的突发,而漏桶主要目的是平滑流入速率;

    • 两个算法实现可以一样,但是方向是相反的,对于相同的参数得到的限流效果是一样的。

    参考:

    https://www.jianshu.com/p/5d4fe4b2a726

    https://www.cnblogs.com/xuwc/p/9123078.html

  • 相关阅读:
    bzoj-2748 2748: [HAOI2012]音量调节(dp)
    bzoj-2338 2338: [HNOI2011]数矩形(计算几何)
    bzoj-3444 3444: 最后的晚餐(组合数学)
    codeforces 709E E. Centroids(树形dp)
    codeforces 709D D. Recover the String(构造)
    codeforces 709C C. Letters Cyclic Shift(贪心)
    codeforces 709B B. Checkpoints(水题)
    codeforces 709A A. Juicer(水题)
    Repeat Number
    hdu 1003 Max Sum (动态规划)
  • 原文地址:https://www.cnblogs.com/xiaozhuanfeng/p/10616987.html
Copyright © 2011-2022 走看看