type
status
date
slug
summary
tags
category
icon
password
1、限流算法
常用的限流算法有以下几种:
- 漏桶算法:原理是将请求放入一个固定容量的漏桶中,然后以固定的速率流出。当请求到来时,如果漏桶已满,则请求被拒绝。漏桶算法可以平滑限制请求的流量,但是对于突发流量无法应对。
- 令牌桶算法:原理是维护一个固定容量的令牌桶,每个请求需要消耗一个令牌才能被处理。当令牌桶中没有足够的令牌时,请求被拒绝。令牌桶算法可以应对突发流量,并且可以设置令牌桶的填充速率和最大容量。
- 计数器算法:原理是在一定时间内统计请求的数量,如果超过了设定的阈值,则拒绝请求。计数器算法可以快速应对突发流量,但是对于长时间的流量控制不够精确。
- 滑动窗口算法:原理是维护一个固定大小的窗口,记录在窗口时间内的请求数量。当请求到来时,将其加入窗口,并计算窗口内的请求总数。如果请求总数超过了设定的阈值,则拒绝请求。滑动窗口算法可以平滑限制请求的流量,并且可以根据实际情况动态调整窗口大小。
1.1 漏桶算法
漏桶算法的实现方式为,将请求放入一个固定容量的漏桶中,然后以固定的速率流出。当请求到来时,如果漏桶未满,则将请求放入漏桶中,否则拒绝请求。漏桶中的请求以固定的速率流出,可以平滑限制请求的流量。漏桶算法可以应对流量波动较小的情况,但是对于突发流量无法应对。
因此,这个算法的核心为:
- 存下请求
- 匀速处理
- 多余丢弃
因此这是一种强行限制请求速率的方式,但是缺点非常明显,主要有两点:
- 无法面对突发的大流量:比如请求处理速率为 1000,容量为 5000,来了一波 2000/s 的请求持续 10s,那么后 5s 的请求将全部直接被丢弃,服务器拒绝服务,但是实际上网络中突发一波大流量尤其是短时间的大流量是非常正常的,超过容量就拒绝,非常简单粗暴。
- 无法有效利用网络资源:比如虽然服务器的处理能力是 1000/s,但这不是绝对的,这个 1000 只是一个宏观服务器处理能力的数字,实际上一共 5 秒,每秒请求量分别为 1200、1300、1200、500、800,平均下来qps也是1000/s,但是这个量对服务器来说完全是可以接受的,但是因为限制了速率是 1000/s,因此前面的三秒,每秒只能处理掉1000个请求而一共打回了700个请求,白白浪费了服务器资源。
所以,通常来说利用漏桶算法来限流,实际场景下用得不多。
1.2 令牌桶算法
从某种意义上来说,令牌桶算法是对漏桶算法的一种改进,主要在于令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。令牌桶算法的原理是:
- 系统以恒定的速率产生令牌,然后将令牌放入令牌桶中
- 令牌桶有一个容量,当令牌桶满了的时候,再向其中放入的令牌就会被丢弃
- 每次一个请求过来,需要从令牌桶中获取一个令牌,假设有令牌,那么提供服务;假设没有令牌,那么拒绝服务
那么,我们再看一下,为什么令牌桶算法可以防止一定程度的突发流量呢?可以这么理解,假设我们想要的速率是 1000QPS,那么往桶中放令牌的速度就是 1000/s,假设第 1 秒只有 800 个请求,那意味着第 2 秒可以容许 1200 个请求,这就是一定程度突发流量的意思,反之我们看漏桶算法,第一秒只有 800 个请求,那么全部放过,第二秒这 1200 个请求将会被打回 200 个。
注意上面多次提到一定程度这四个字,这也是我认为令牌桶算法最需要注意的一个点。假设还是 1000/s 的速率,那么 5 秒钟放 1000 个令牌,第 1 秒钟 800 个请求过来,第 2~4 秒没有请求,那么按照令牌桶算法,第 5 秒钟可以接受 4200 个请求,但是实际上这已经远远超出了系统的承载能力,因此使用令牌桶算法特别注意设置桶中令牌的上限即可。
总而言之,作为对漏桶算法的改进,令牌桶算法在限流场景下被使用更加广泛。
2、Nginx的限流方式
Nginx 提供两种限流模块:
- 按连接数限流(limit_conn_module):限制单个IP(或者其他的key)同时发起的连接数,超出这个限制后,Nginx将直接拒绝更多的连接。
- 按请求速率限流(limit_req_module):限制单个IP(或者其他的key)发送请求的速率,超出指定速率后,Nginx将直接拒绝更多的请求。使用的是漏桶算法。
2.1 limit_conn_module
使用语法:
分为
limit_conn_zone
和 limit_conn
两部分:limit_conn_zone
:一般作用在 http 全局块。这个模块的目的主要是对连接进行限制,那么我们就需要对连接的状态进行进行存储,limit_conn_zone 就是开辟一个空间用来存储连接的。- key :定义限流对象,
binary_remote_addr
是一种 key,表示基于 remote_addr(客户端 IP) 来做限流,binary_
的目的是压缩内存占用量。 - zone:定义共享内存区来存储访问信息,
myRateLimit:10m
表示一个大小为 10M,名字为 myRateLimit 的内存区域。1M 能存储 16000 IP 地址的访问信息,10M 可以存储 16W IP 地址访问信息。
limit_conn
:一般作用在 server 块,需要结合limit_conn_zone
使用。- zone:和
limit_conn_zone
的 zone 的 name 对应 - number:限制的连接数
使用实例:
2.2 limit_req_module
使用语法:
分为
limit_req_zone
和 limit_req
两部分:limit_req_zone
:- key :定义限流对象,
binary_remote_addr
是一种 key,表示基于 remote_addr(客户端 IP) 来做限流,binary_
的目的是压缩内存占用量。 - zone:定义共享内存区来存储访问信息,
myRateLimit:10m
表示一个大小为 10M,名字为 myRateLimit 的内存区域。1M 能存储 16000 IP 地址的访问信息,10M 可以存储 16W IP 地址访问信息。 - rate:表示限制请求的速率是多大,一般以秒为单位。例如 2r/s,表示 500ms 内单个IP只允许通过 1 个请求,从 501ms 开始才允许通过第二个请求。
limit_req
:- zone:和
limit_req_zone
的 zone 的 name 对应 - busrt:burst 表示在突发流量的情况下,每秒可以增加处理请求数。nginx 会把所有超过 rate 速率的请求缓存到
limit_req_zone
开辟的内存空间的缓存队列里面。 - nodelay:如果没有设置 nodelay,就按照 rate 定义的速率处理去处理缓存队列的请求,也就是说每秒最多处理 rate 个请求;如果设置了nodelay,就按照 burst + rate 的速率去处理请求,也就是说每秒最多处理 busrt + rate 个请求。超过阈值的请求直接返回 503。
使用实例:
- Author:mcbilla
- URL:http://mcbilla.com/article/115973de-ac17-4aa3-89d0-3e80e6a132f1
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts