date: 2020-07-18title: nginx限制资源的访问 #标题
tags: nginx #标签
categories: nginx # 分类
此博文记录了nginx如何设置连接请求的最大数量,或从nginx下载内容的最大速率。
参考:官方文档
nginx可以限制哪些?
nginx可以限制:
limit_conn_zone 模块: 限制同一 IP 地址并发连接数;
limit_request 模块: 限制同一 IP 某段时间的访问量;
core 模块提供: limit_rate 限制同一 IP 流量。
注意:客户端很有可能是在NAT设备后面共享IP地址,因此应谨慎使用IP地址限制。如果一定要使用,建议使用 IP + url 的方式进行判断。
限制同一IP并发连接数
http {
.......... # 省略部分内容
limit_conn_zone $binary_remote_addr$uri zone=perip:30m;
limit_conn_status 503;
server {
listen 80;
location / {
root html;
index index.html index.htm;
limit_conn perip 1;
}
指令解释
指令名称:limit_conn_zone
- 语法: limit_conn_zone key zone=name:size;
- 默认: no
- 区域: http
- 功能: 定义一个zone,用于存储会话的状态。
- 示例: 上面的示例,就是用客户IP及访问uri作为键值进行存储。键值一样的则被认为是同一个会话。
指令名称:limit_conn
- 语法:limit_conn zone number;
- 默认:no
- 区域:http、server、location
- 功能:该指令用于为一个会话设定最大并发连接数。如果并发请求超过这个限制,那么将返回预定错误( limit_conn_status )
限制请求速率
速率限制可用于防止DDoS攻击,或防止上游服务器同时被太多请求淹没。该方法基于以下算法:请求以各种速率到达存储桶,并以固定速率离开存储桶。
在使用速率限制之前,需要配置“泄漏桶”的全局参数:
- 键:用于区分一个客户端与另一个客户端的参数,通常是一个变量。
- 共享内存区域:保留这些键的状态的区域的名称和大小(“漏斗”)。
- rate:以每秒请求数(r/s)或每分钟请求数(r/m)指定的请求速率限制(“漏斗排放”)。每分钟请求数用于指定小于每秒一个请求的速率。
这些参数是通过limit_req_zone指令设置的。定义在http{}字段中。
当limit_req_zone
被设置后,我们可以在nginx上需要限制的地方指定limit_req,比如:server{}、location{}以及http{}。
http {
.................
limit_req_zone $binary_remote_addr zone=limit_html:10m rate=1r/s;
................
server {
.................
location / {
limit_req zone=limit_html burst=5 delay=3;
}
.................
}
}
上述部分配置解释:
- burst:当前请求已经超过了rate限制的链接数,但是nignx不会直接拒绝,而是放入队列进行排队,如上述指定了
burst=5
,表示队列的大小为5个请求,如果此时同一个客户端进来10个请求,那么只有5个请求可以按每秒一个的频率被处理,剩下五个将会拒绝处理,返回503状态码。- delay:由于上述指定的burst是将队列的大小设置了为5,但客户端请求的一个页面上可能会访问到nginx多次,那这样的话,假设客户端要的资源是访问nignx 3次才能获取到完整内容的,那么整个过程就需要3秒,非常影响客户体验,此时可以通过delay参数来实现不延迟的处理队列中一定数量的请求,在上述配置中,delay=3,表示会立即处理队列中的3个请求,而不用每秒一个的去处理。如果我们想让队列中的所有连接都无需延迟,那么可以直接设置为
nodelay
即可。
上述配置,将创建名为limit_html,大小为10MB的共享内存区域,该区域保留使用binary_remote_addr以二进制的方式保存IP地址,比较省内存空间。
$binary_remote_addr对于IPv4地址,值的大小为4个字节,在64位平台上,存储状态占128个字节。因此,大约16000个IP地址的状态信息占用该区域的1MB。
如果NGINX需要添加新条目时存储空间已用尽,它将删除最旧的条目。如果释放的空间仍然不足以容纳新记录,则NGINX返回状态码。可以使用伪指令limit_req_status
重新定义状态代码,如:limit_req_status 503;
。
示例摘要
# uri 访问速率限制
# 说明: uri匹配.html结尾, 则赋值变量 $limit_html 为客户端IP+uri
map $uri $limit_html {
~\.html$ $binary_remote_addr$uri;
}
# 访问 次/秒
# 说明: 结合上面的map, 限制为1次/秒相同 (IP + uri <.html> )
limit_req_zone $limit_html zone=limit_html:50m rate=1r/s;
limit_req_status 503;
限制带宽
如果要限制带宽(是不是想起某盘了),可以使用limit_rate指令。
http {
limit_req_zone $binary_remote_addr zone=limit_html:10m;
server {
location /download {
# auto开头的是配置文件服务器
autoindex on; # 开启索引功能
autoindex_exact_size off; # 关闭计算文件确切大小(单位bytes),只显示大概大小(单位kb、mb、gb)
autoindex_localtime on; # 显示本机时间而非 GMT 时间
# 下面才是带宽限制相关配置
limit_conn limit_html 1; # 限制同一个IP只能建立一个连接
limit_rate_after 100m; # 在100M以后的数据才开始进行速率限制
limit_rate 50k; # 限制速率为50k
}
}
}
$ ll /usr/share/nginx/html/download/ # 文件服务根目录内容如下
总用量 289532
-rw-r--r-- 1 root root 296477546 5月 1 14:24 elasticsearch-7.6.2-linux-x86_64.tar.gz
浏览器下载测试:
由于我是本地虚拟机做的nginx,所以前100M很快,然后,接下来就一直是四五十kb的样子。
如果你还想再打开个窗口下载此文件,只会看到一个error页面,因为设置了limit_conn limit_html 1;
。齐活!