type
status
date
slug
summary
tags
category
password

1、限流算法

常用的限流算法有以下几种:
  1. 漏桶算法:原理是请求以任意速率放入一个固定容量的漏桶中,然后以固定的速率流出。当请求到来时,如果漏桶已满,则请求被拒绝。漏桶算法可以平滑限制请求的流量,但是对于突发流量无法应对。
  1. 令牌桶算法:原理是维护一个固定容量的令牌桶,每个请求需要消耗一个令牌才能被处理。当令牌桶中没有足够的令牌时,请求被拒绝。令牌桶算法可以应对突发流量,并且可以设置令牌桶的填充速率和最大容量。
  1. 固定窗口算法:原理是在一定时间内统计请求的数量,如果超过了设定的阈值,则拒绝请求。计数器算法可以快速应对突发流量,但是对于长时间的流量控制不够精确。
  1. 滑动窗口算法:原理是维护一个固定大小的窗口,记录在窗口时间内的请求数量。当请求到来时,将其加入窗口,并计算窗口内的请求总数。如果请求总数超过了设定的阈值,则拒绝请求。滑动窗口算法可以平滑限制请求的流量,并且可以根据实际情况动态调整窗口大小。

1.1 漏桶算法

漏桶算法的实现方式为,将请求放入一个固定容量的漏桶中,然后以固定的速率流出。当请求到来时,如果漏桶未满,则将请求放入漏桶中,否则拒绝请求。漏桶中的请求以固定的速率流出,可以平滑限制请求的流量。漏桶算法可以应对流量波动较小的情况,但是对于突发流量无法应对。
notion image
由于漏桶算法严格限制了请求的处理速率,绝不会超过预设的流出速率,所以无法处理突发的流量。例如服务器的处理能力是 1000/s,一共请求了 5 秒,每秒请求量分别为 1200、1300、1200、500、800,平均下来 QPS 也是1000/s,这个量对服务器来说完全是可以接受的,但是因为限制了速率是 1000/s,因此前面的三秒,每秒只能处理掉 1000 个请求而一共打回了700个请求,白白浪费了服务器资源。

1.2 令牌桶算法

从某种意义上来说,令牌桶算法是对漏桶算法的一种改进,主要在于令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。令牌桶算法的原理是:
  • 系统以恒定的速率产生令牌,然后将令牌放入固定容量的令牌桶中
  • 当令牌桶满了的时候,再向其中放入的令牌就会被丢弃
  • 每次一个请求过来,需要从令牌桶中获取一个令牌,假设有令牌,那么提供服务;假设没有令牌,那么拒绝服务
notion image
那么,我们再看一下,为什么令牌桶算法可以防止一定程度的突发流量呢?可以这么理解,假设我们想要的速率是 1000 QPS,那么往桶中放令牌的速度就是 1000/s,假设第 1 秒只有 800 个请求,那意味着第 2 秒可以容许 1200 个请求,这就是一定程度突发流量的意思,反之我们看漏桶算法,第一秒只有 800 个请求,那么全部放过,第二秒这 1200 个请求将会被打回 200 个。
注意上面多次提到一定程度这四个字,这也是我认为令牌桶算法最需要注意的一个点。假设还是 1000/s 的速率,那么 5 秒钟放 1000 个令牌,第 1 秒钟 800 个请求过来,第 2~4 秒没有请求,那么按照令牌桶算法,第 5 秒钟可以接受 4200 个请求,但是实际上这已经远远超出了系统的承载能力,因此使用令牌桶算法特别注意设置桶中令牌的上限即可。
总而言之,作为对漏桶算法的改进,令牌桶算法在限流场景下被使用更加广泛。
漏桶算法和令牌桶算法算法对比:
特性
漏桶算法
令牌桶算法
核心概念
水以任意速率流入,以恒定速率流出。
令牌以恒定速率生成,请求需要获取令牌才能被处理。
主要目的
平滑流量,强制恒定的输出速率。
允许突发流量,只要桶中有足够的令牌。
灵活性
低。无法处理突发,输出速率绝对固定。
高。可以应对突发(例如,短时间内消耗多个令牌)。
实现重点
控制流出的处理速率
控制令牌的生成速率桶的容量
典型应用
需要绝对平滑输出的场景,如视频流、音频流。
需要一定程度突发处理的Web API、网络设备。
  • 如果想彻底消除突发,保证绝对平滑的输出,用漏桶
  • 如果想限制平均速率但同时允许一定程度的突发,用令牌桶

2、Nginx的限流方式

Nginx 提供两种限流模块:
  • 按连接数限流(limit_conn_module):限制单个IP(或者其他的key)同时发起的连接数,超出这个限制后,Nginx将直接拒绝更多的连接。
  • 按请求速率限流(limit_req_module):限制单个IP(或者其他的key)发送请求的速率,超出指定速率后,Nginx将直接拒绝更多的请求。使用的是漏桶算法。

2.1 limit_conn_module

使用语法:
分为 limit_conn_zonelimit_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_zonelimit_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。
使用实例:
Docker系列:Docker镜像Nginx配置文件使用
Loading...