高并发——应用限流(五)

前言

高并发场景下,爆炸性大量的对数据库的请求操作不仅会占用十分高比例的网络带宽,导致其他应用对数据库的请求受阻,还会导致从库与主库的延迟大大增加,降低了从库数据的不准确率,也降低了缓存的命中率。

如图:

JAVA并发——高并发之应用限流(五)_2020-03-31-10-44-13.png

限流方式

  • 限制总并发数:如数据库连接池、线程池;
  • 限制瞬时并发数:如 nginx 的 limit_conn 模块,用来限制瞬时并发连接数;
  • 限制时间窗口内的平均速率:如 Guava 的 RateLimiter、nginx 的 limit_req 模块,限制每秒的平均速率;

限流算法

  1. 计数器法
  2. 滑动窗口
  3. 漏桶算法
  4. 令牌桶算法

计数器法

计数器法是最简单、最易实现的限流算法。通过重复设置计数器,对接口一定时间段内的访问频率进行限制。

弊端:存在临界问题。
如下图所示:

JAVA并发——高并发之应用限流(五)_2020-03-31-10-46-19.png

如上图所示,在临界的小时间段内,发送了 200 个请求,导致限流的不成功,可能会导致应用的崩溃。

滑动窗口

滑动窗口可以被看做是一个高精度的计数器算法。其中小窗口的个数越多,对限流中请求的统计会越精确,但占用的系统资源会多。

如下图所示:

JAVA并发——高并发之应用限流(五)_2020-03-31-10-47-28.png

其中,虚线包括了 6 个小窗口,这该 6 个小窗口组成了一个滑动窗口,滑动窗口对请求数量进行限定;每个小窗口都有一个计数器,都限定了相同的一定时间。每经过该小窗口的时间,滑动窗口就向右侧移动一格,如上图的所示,从而避免了计数器法中的弊端。

漏桶算法

漏桶算法(Leaky Bucket)作为计量工具(The Leaky Bucket Algorithm as a Meter)时,可以用于流量整形(Traffic Shaping)和流量控制(TrafficPolicing)。

其算法示意图如下:

JAVA并发——高并发之应用限流(五)_2020-03-31-10-48-41.png

漏桶算法构建一个容量固定的漏桶,请求数会先放入漏桶,以可控的一定速率流出来,当漏桶满了时,多余的请求会被丢弃。

令牌桶算法

令牌桶算法可以看做是漏桶算法和滑动窗口思想的结合体,构造一个存放固定容量令牌的桶,按照可控的固定速率往桶里添加令牌。

如下图所示:

JAVA并发——高并发之应用限流(五)_2020-03-31-10-49-30.png

当桶满了时,新添加的令牌会被丢弃或拒绝。当一个请求过来时,该桶就移除一个令牌;当桶中没了令牌时,请求也就无法通过。其中移除令牌是没有延迟时间的,若当设置该延迟时间后,就十分近似漏桶算法了。它通过将桶总量划分为多个令牌的容量,不会造成大量请求的突发,可以很好地解决临界问题。

令牌桶算法与漏桶算法的比较

  • 令牌桶是按照固定速率往桶中添加令牌,请求是否被处理需要看桶中令牌是否足够,当令牌数减为零时则拒绝新的请求;
  • 漏桶则是按照常量固定速率流出请求,流入请求速率任意,当流入的请求数累积到漏桶容量时,则新流入的请求被拒绝;
  • 令牌桶限制的是平均流入速率(允许突发请求,只要有令牌就可以处理,支持一次拿 3 个令牌,4 个令牌),并允许一定程度突发流量;
  • 漏桶限制的是常量流出速率(即流出速率是一个固定常量值,比如都是 1 的速率流出,而不能一次是 1,下次又是 2),从而平滑突发流入速率;
  • 令牌桶允许一定程度的突发,而漏桶主要目的是平滑流入速率;
    两个算法实现可以一样,但是方向是相反的,对于相同的参数得到的限流效果是一样的。

推荐阅读

限流特技

文章目录
  1. 1. 前言
  2. 2. 限流方式
  3. 3. 限流算法
    1. 3.1. 计数器法
    2. 3.2. 滑动窗口
    3. 3.3. 漏桶算法
    4. 3.4. 令牌桶算法
    5. 3.5. 令牌桶算法与漏桶算法的比较
  4. 4. 推荐阅读
|