一、限流算法
1.1 令牌桶算法
算法思想是:
- 令牌以固定速率产生,并缓存到令牌桶中;
- 令牌桶放满时,多余的令牌被丢弃;
- 请求要消耗等比例的令牌才能被处理;
- 令牌不够时,请求被缓存。
1.2 漏桶算法
算法思想是:
- 水(请求)从上方倒入水桶,从水桶下方流出(被处理);
- 来不及流出的水存在水桶中(缓冲),以固定速率流出;
- 水桶满后水溢出(丢弃)。
- 这个算法的核心是:缓存请求、匀速处理、多余的请求直接丢弃。
相比漏桶算法,令牌桶算法不同之处在于它不但有一只“桶”,还有个队列,这个桶是用来存放令牌的,队列才是用来存放请求的。
从作用上来说,漏桶和令牌桶算法最明显的区别就是是否允许突发流量(burst)的处理:
漏桶算法能够强行限制数据的实时传输(处理)速率,对突发流量不做额外处理;
令牌桶算法能够在限制数据的平均传输速率的同时允许某种程度的突发传输。
Nginx按请求速率限速模块使用的是漏桶算法,即能够强行保证请求的实时处理速度不会超过设置的阈值。
Nginx官方版本限制IP的连接和并发分别有两个模块:
limit_req_zone
用来限制单位时间内的请求数,即速率限制,采用的漏桶算法 “leaky bucket”。limit_req_conn
用来限制同一时间连接数,即并发限制。
限流示例
limit_req_zone
示例:采用漏桶算法
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; //限流配置
server {
location / {
limit_req zone=mylimit; //应用到需要限流的请求location上
proxy_pass http://my_upstream;
}
}
参数解释:
1、$binary_remote_addr — nginx变量,该变量代表了某个客户端IP地址的二进制形式。
2、zone — 定义了存储每个IP地址状态和它访问受限请求URL的频率的共享内存区域。
3、rate — 设置最大的请求速率。 10r/s 每秒10次,100毫秒一个请求,多出的请求在没有配置bursts情况下,拒绝
处理流量爆发
如果在100毫秒内得到2个请求会怎么样?对于第2个请求,NGINX返回503状态码给客户端。
这可能不是我们想要的,因为事实上,应用是趋向于突发性的。
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; //限流配置
location / {
limit_req zone=mylimit burst=20;
proxy_pass http://my_upstream;
}
无延迟排队
带有burst的配置产生平滑的网络流量,但是不实用,因为该配置会使得你的网站表现的很慢。
在上面的例子中,队列中第20个数据包等待2秒才能被转发,这时该数据包的响应可能对于客户端已经没有了意义。
为了处理这种情况,除了burst参数外,添加nodelay参数。
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; //限流配置
server{
location /login/ {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://my_upstream
}
}
带有nodelay参数,NGINX仍然会按照burst参数在队列中分配插槽(slot)以及利用已配置的限流,但是不是通过间隔地转发队列中的请求。相反,当某个请求来的太快,只要队列中有可用的空间(slot),NGINX会立即转发它。该插槽(slot)被标记为“已使用”,并且不会被释放给另一个请求,一直到经过适当的时间(在上面的例子中,是100毫秒)。
像之前一样假设有20个插槽的队列是空的,并且来自于给定的IP地址的21个请求同时地到达。NGINX立即转发这21个请求以及将队列中的20个插槽标记为“已使用”,然后每隔100毫秒释放一个插槽。(相反,如果有25个请求,NGINX会立即转发25个中的21个请求,标记20个插槽为“已使用”,并且用503状态拒绝4个请求。)
其中“limit_req zone=mylimit burst=120”既可以放在server层对整个server有效,也可以放在location中只对单独的location有效。
rate=1r/s的意思是每个地址每秒只能请求一次,也就是说令牌桶burst=120一共有120块令牌,并且每秒钟只新增1块令牌,120块令牌发完后,多出来的请求就会返回503.。
limit_conn_zone 示例
http{
limit_conn_zone $binary_remote_addr zone=one:10m;
server {
....
limit_conn one 10;
....
}
}
其中“limit_conn one 10”既可以放在server层对整个server有效,也可以放在location中只对单独的location有效。
该配置表明:客户端的并发连接数只能是10个。