浅谈Nginx 中的两种限流方式


Posted in Servers onMarch 31, 2021

系统设计时一般会预估负载,当系统暴露在公网中时,恶意攻击或正常突发流量等都可能导致系统被压垮,而限流就是保护措施之一。限流即控制流量,本文将记录 Nginx 的二种限流设置。

生活中的 “限流”?

限流并非新鲜事,在生活中亦无处不在,下面例举一二:

博物馆:限制每天参观总人数以保护文物

高铁安检:有若干安检口,旅客依次排队,工作人员根据安检快慢决定是否放人进去。遇到节假日,可以增加安检口来提高处理能力(横向拓展),同时增加排队等待区长度(缓存待处理任务)。

办理银行业务:所有人先领号,各窗口叫号处理。每个窗口处理速度根据客户具体业务而定,所有人排队等待叫号即可。若快下班时,告知客户明日再来(拒绝流量)。

水坝泄洪:水坝可以通过闸门控制泄洪速度(控制处理速度)。

以上"限流"例子,可以让服务提供者稳定的服务客户。

Nginx 限流

Nginx 提供两种限流方式,一是控制速率,二是控制并发连接数。

控制速率

正常限流

ngx_http_limit_req_module 模块提供限制请求处理速率能力,使用了漏桶算法(leaky bucket)。下面例子使用 nginx limit_req_zone 和 limit_req 两个指令,限制单个IP的请求处理速率。

在 nginx.conf http 中添加限流配置:

格式:limit_req_zone key zone rate

http {
 limit_req_zone $binary_remote_addr zone=myRateLimit:10m rate=10r/s;
}

配置 server,使用 limit_req 指令应用限流。

server {
 location / {
 limit_req zone=myRateLimit;
 proxy_pass http://my_upstream;
 }
}

key :定义限流对象,binary_remote_addr 是一种key,表示基于 remote_addr(客户端IP) 来做限流,binary_ 的目的是压缩内存占用量。

zone:定义共享内存区来存储访问信息, myRateLimit:10m 表示一个大小为10M,名字为myRateLimit的内存区域。1M能存储16000 IP地址的访问信息,10M可以存储16W IP地址访问信息。

rate 用于设置最大访问速率,rate=10r/s 表示每秒最多处理10个请求。Nginx 实际上以毫秒为粒度来跟踪请求信息,因此 10r/s 实际上是限制:每100毫秒处理一个请求。这意味着,自上一个请求处理完后,若后续100毫秒内又有请求到达,将拒绝处理该请求。

处理突发流量

上面例子限制 10r/s,如果有时正常流量突然增大,超出的请求将被拒绝,无法处理突发流量,可以结合 burst 参数使用来解决该问题。

server {
 location / {
 limit_req zone=myRateLimit burst=20;
 proxy_pass http://my_upstream;
 }
}

burst 译为突发、爆发,表示在超过设定的处理速率后能额外处理的请求数。当 rate=10r/s 时,将1s拆成10份,即每100ms可处理1个请求。

此处,**burst=20 **,若同时有21个请求到达,Nginx 会处理第一个请求,剩余20个请求将放入队列,然后每隔100ms从队列中获取一个请求进行处理。若请求数大于21,将拒绝处理多余的请求,直接返回503.

不过,单独使用 burst 参数并不实用。假设 burst=50 ,rate依然为10r/s,排队中的50个请求虽然每100ms会处理一个,但第50个请求却需要等待 50 * 100ms即 5s,这么长的处理时间自然难以接受。

因此,burst 往往结合 nodelay 一起使用。

server {
 location / {
 limit_req zone=myRateLimit burst=20 nodelay;
 proxy_pass http://my_upstream;
 }
}

nodelay 针对的是 burst 参数,burst=20 nodelay 表示这20个请求立马处理,不能延迟,相当于特事特办。不过,即使这20个突发请求立马处理结束,后续来了请求也不会立马处理。burst=20 相当于缓存队列中占了20个坑,即使请求被处理了,这20个位置这只能按 100ms一个来释放。

这就达到了速率稳定,但突然流量也能正常处理的效果。

限制连接数

ngx_http_limit_conn_module 提供了限制连接数的能力,利用 limit_conn_zone 和 limit_conn 两个指令即可。下面是 Nginx 官方例子:

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;

server {
 ...
 limit_conn perip 10;
 limit_conn perserver 100;
}

limit_conn perip 10 作用的key 是 $binary_remote_addr,表示限制单个IP同时最多能持有10个连接。

limit_conn perserver 100 作用的key是 $server_name,表示虚拟主机(server) 同时能处理并发连接的总数。

需要注意的是:只有当 request header 被后端server处理后,这个连接才进行计数。

设置白名单

限流主要针对外部访问,内网访问相对安全,可以不做限流,通过设置白名单即可。利用 Nginx ngx_http_geo_modulengx_http_map_module 两个工具模块即可搞定。

在 nginx.conf 的 http 部分中配置白名单:

geo $limit {
 default 1;
 10.0.0.0/8 0;
 192.168.0.0/24 0;
 172.20.0.35 0;
}

map $limit $limit_key {
 0 "";
 1 $binary_remote_addr;
}

limit_req_zone $limit_key zone=myRateLimit:10m rate=10r/s;

geo 对于白名单(子网或IP都可以) 将返回0,其他IP将返回1。

map 将 limit **转换为** limit_key,如果是 $limit 是0(白名单),则返回空字符串;如果是1,则返回客户端实际IP。

limit_req_zone 限流的key不再使用而是 **limit_key 来动态获取值。如果是白名单,limit_req_zone 的限流key则为空字符串,将不会限流;若不是白名单,将会对客户端真实IP进行限流。

拓展阅读

除限流外,ngx_http_core_module 还提供了限制数据传输速度的能力(即常说的下载速度)。

例如:

location /flv/ {
 flv;
 limit_rate_after 20m;
 limit_rate 100k;
}

这个限制是针对每个请求的,表示客户端下载前20M时不限速,后续限制100kb/s。

以上这篇浅谈Nginx 中的两种限流方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Servers 相关文章推荐
Apache压力测试工具的安装使用
Mar 31 Servers
nginx proxy_cache 缓存配置详解
Mar 31 Servers
Nginx代理同域名前后端分离项目的完整步骤
Mar 31 Servers
解决使用了nginx获取IP地址都是127.0.0.1 的问题
Sep 25 Servers
详解nginx安装过程并代理下载服务器文件
Feb 12 Servers
Ubuntu Server 安装Tomcat并配置systemctl
Apr 28 Servers
Windows Server 2012 R2 磁盘分区教程
Apr 29 Servers
CentOS7安装MySQL8的超级详细教程(无坑!)
Jun 10 Servers
Ubuntu安装Mysql+启用远程连接的完整过程
Jun 21 Servers
Windows server 2022创建创建林、域树、子域的步骤
Jun 25 Servers
本地搭建minio文件服务器(使用bat脚本启动)的方法
Jul 15 Servers
教你使用Ubuntu搭建DNS服务器
Sep 23 Servers
查看nginx配置文件路径和资源文件路径的方法
Mar 31 #Servers
nginx里的rewrite跳转的实现
Mar 31 #Servers
nginx基于域名,端口,不同IP的虚拟主机设置的实现
Mar 31 #Servers
Nginx设置日志打印post请求参数的方法
Mar 31 #Servers
nginx 多个location转发任意请求或访问静态资源文件的实现
nginx简单配置多个server的方法
nginx proxy_cache 缓存配置详解
You might like
PHP简单日历实现方法
2016/07/20 PHP
tp5.1 框架查询表达式用法详解
2020/05/25 PHP
分析 JavaScript 中令人困惑的变量赋值
2007/08/13 Javascript
JavaScript 捕获窗口关闭事件
2009/07/26 Javascript
js用Date对象处理时间实现思路及代码
2013/01/31 Javascript
排序算法的javascript实现与讲解(99js手记)
2014/09/28 Javascript
js实现照片墙功能实例
2015/02/05 Javascript
jQuery通过deferred对象管理ajax异步
2016/05/20 Javascript
JS实现n秒后自动跳转的两种方法
2020/11/30 Javascript
Angular.Js的自动化测试详解
2016/12/09 Javascript
xmlplus组件设计系列之文本框(TextBox)(3)
2017/05/03 Javascript
ionic2屏幕适配实现适配手机、平板等设备的示例代码
2017/08/11 Javascript
JavaScript实现动态添加Form表单元素的方法示例
2017/08/14 Javascript
hammer.js实现图片手势放大效果
2017/08/29 Javascript
javascript实现数字配对游戏的实例讲解
2017/12/14 Javascript
Ajax请求时无法重定向的问题解决代码详解
2019/06/21 Javascript
使用VUE实现在table中文字信息超过5个隐藏鼠标移到时弹窗显示全部
2019/09/16 Javascript
微信小程序实现音乐播放器
2019/11/20 Javascript
JavaScript仿京东秒杀倒计时
2020/03/17 Javascript
[46:44]VG vs TNC Supermajor小组赛B组败者组决赛 BO3 第一场 6.2
2018/06/03 DOTA
[22:59]VGJ.S vs VG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
pymongo实现多结果进行多列排序的方法
2015/05/16 Python
利用python对Excel中的特定数据提取并写入新表的方法
2018/06/14 Python
python读取文件名并改名字的实例
2019/01/07 Python
Python 、Pycharm、Anaconda三者的区别与联系、安装过程及注意事项
2019/10/11 Python
python中的selenium安装的步骤(浏览器自动化测试框架)
2020/03/17 Python
Python Map 函数的使用
2020/08/28 Python
详解BeautifulSoup获取特定标签下内容的方法
2020/12/07 Python
用HTML5 Canvas API中的clearRect()方法实现橡皮擦功能
2016/03/15 HTML / CSS
客户表扬信范文
2014/01/10 职场文书
本科生职业生涯规划书范文
2014/01/21 职场文书
十八大演讲稿
2014/05/22 职场文书
新闻编辑专业自荐信
2014/07/02 职场文书
加强机关作风建设心得体会
2014/10/22 职场文书
2015年党性分析材料
2014/12/19 职场文书
导游词之海南-南湾猴岛
2019/10/12 职场文书