分布式系统架构--限流


一 什么是限流

在开发高并发系统时,有很多手段来保护系统,如缓存降级限流,限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的请求进行限速来保护系统。一旦达到限速之后可以通过拒绝服务(定向页面跳转)或者排队等待的方式,以保证系统的高可用,防止瞬时的大并发访问冲垮系统

一般开发高并发系统常见的限流有:
限制总并发数(比如数据库连接池,线程池),限制瞬时并发数,限制时间窗口内的平局时速(可以通过guava中的RateLimiter实现)

二 常见的限流算法

1,计数器

计数器算法是限流算法中最简单的,它是针对于固定时间范围内,对于访问总数的一个限流,假如系统要求在一分钟内访问不超过100次,大致的设计原理如下:
在这里插入图片描述
主要的设计逻辑是,首先定义一个计数器regCount,每当系统访问就加一,如果当前访问时间间隔处于指定时间间隔内之后,并且当前的regCount小于访问阈值,即可以访问,如果当前访问时间超过当前指定时间间隔(系统重新计算),直接设置当前记时时间未当前访问时间,并且regCount设置1

这个算法虽然简单,但是有一个十分致命的问题,那就是临界问题,我们看下图:
在这里插入图片描述
从上图中我们可以看到,假设有一个恶意用户,他在0:59时,瞬间发送了100个请求,并且1:00又瞬间发送了100个请求,那么其实这个用户在 1秒里面,瞬间发送了200个请求。我们刚才规定的是1分钟最多100个请求,也就是每秒钟最多1.7个请求,用户通过在时间窗口的重置节点处突发请求, 可以瞬间超过我们的速率限制。用户有可能通过算法的这个漏洞,瞬间压垮我们的应用。

聪明的朋友可能已经看出来了,刚才的问题其实是因为我们统计的精度太低。那么如何很好地处理这个问题呢?或者说,如何将临界问题的影响降低呢?我们可以看下面的滑动窗口算法。

滑动窗口
在这里插入图片描述
在上图中,整个红色的矩形框表示一个时间窗口,在我们的例子中,一个时间窗口就是一分钟。然后我们将时间窗口进行划分,比如图中,我们就将滑动窗口 划成了6格,所以每格代表的是10秒钟。每过10秒钟,我们的时间窗口就会往右滑动一格。每一个格子都有自己独立的计数器counter,比如当一个请求 在0:35秒的时候到达,那么0:30~0:39对应的counter就会加1。
那么滑动窗口怎么解决刚才的临界问题的呢?我们可以看上图,0:59到达的100个请求会落在灰色的格子中,而1:00到达的请求会落在橘黄色的格 子中。当时间到达1:00时,我们的窗口会往右移动一格,那么此时时间窗口内的总请求数量一共是200个,超过了限定的100个,所以此时能够检测出来触 发了限流。
我再来回顾一下刚才的计数器算法,我们可以发现,计数器算法其实就是滑动窗口算法。只是它没有对时间窗口做进一步地划分,所以只有1格。
由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。

2,令牌桶算法

令牌桶算法,是一个存放固定容量令牌的桶,按照固定速率网桶里面添加令牌,大致的逻辑如下:

  • 1)、所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
  • 2)、根据限流大小,设置按照一定的速率往桶里添加令牌;
  • 3)、桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
  • 4)、请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
  • 5)、令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;
    在这里插入图片描述
3,漏桶算法

漏桶作为计量工具时,可以用于流量整形和流量控制,漏桶算法的描述如下:

  • 一个固定容量的漏桶,按照常量固定速率流出水滴
  • 如果桶式空的,则不需要流出水滴
  • 可以以任意速率流入水滴到漏桶
  • 如果流入水滴超出了桶的容量,则流入的水滴溢出了(被丢弃),而漏桶容量是不变的

在这里插入图片描述

4,区别
  • 1,令牌桶限制的是平均流入速率(允许突发请求,只要有令牌就可以处理,支持一次拿三个令牌,或者四个令牌),并允许一定程度的突发流量
  • 2,漏桶限制的是常量流出速率(即流出速率是一个固定常量值,比如都是1的速率流出,而不能一次是1,一次是2),从而平滑突发流入速率
  • 3,令牌桶允许一定程度的突发,而漏桶主要目的是平滑流入速率
  • 4,两个算法实现可以一样,但是方向是相反的,对于相同的参数得到的限流效果是一样的

三 限流场景

1,应用级限流

Tomcat中和一些基本的容器配置参数

  • acceptCount:如果Tomcat的线程都忙于响应,新来的连接会进入队列排队,如果超出排队大小,则拒绝连接
  • maxConnections:瞬时最大连接数
  • maxThreads:Tomcat能启动用来处理请求的最大线程数

限制总资源数
限制某个接口的总并发/请求 数
限制某个接口的时间窗请求数
平滑限制某个接口的请求数(gavva RateLimiter)

2,分布式限流

分布式限流最关键的是要将限流服务做成原子化,Redis+Lua 或者是Nginx+Lua

3,接入层限流
发布了55 篇原创文章 · 获赞 14 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/zcswl7961/article/details/102762455