Nginx--流量控制

前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除

一、流量限制

1、介绍

流量限制 (rate-limiting);可用来限制用户在给定时间内HTTP请求的数量。请求,可以是一个简单网站首页的GET请求,也可以是登录表单的 POST 请求。流量限制可以用作安全目的

  • 减慢暴力密码破解的速率。
  • 通过将传入请求的速率限制为真实用户的典型值,并标识目标URL地址(通过日志),还可以用来抵御DDOS攻击。
  • 更常见的情况:该功能被用来保护上游应用服务器不被同时太多用户请求所压垮

2、Nginx如何限流

Nginx的”流量限制”使用漏桶算法(leaky bucket algorithm),该算法在通讯和分组交换计算机网络中广泛使用,用以处理带宽有限时的突发情况。就好比,一个桶口在倒水,桶底在漏水的水桶。如果桶口倒水的速率大于桶底的漏水速率,桶里面的水将会溢出;同样,在请求处理方面,水代表来自客户端的请 求,水桶代表根据”先进先出调度算法”(FIFO)等待被处理的请求队列,桶底漏出的水代表离开缓冲区被服务器处理的请求,桶口溢出的水代表被丢弃和不被处理的请求

二、配置基本的限流

1、实验环境

主机名IP地址角色
centos10.0.0.2web服务器
centos-210.0.0.3代理服务器

2、配置文件

流量限制”配置两个主要的指令, limit_req_zonelimit_req ,如下所示:

 #-------------------10.0.0.3代理服务器配置-------------------#
 # 定义一个共享内存区域,用于存储限流状态
 limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
 upstream myweb {
   server 10.0.0.2:80 weight=1 max_fails=1 fail_timeout=1;
 }
 server {
   listen 80;
   server_name localhost;
   location /login {
     limit_req zone=mylimit; 
     proxy_pass http://myweb;
     # 发送到上游服务器的HTTP头
     proxy_set_header Host $host:$server_port;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }
 }
 # -------------------10.0.0.2配置---------------------------#
 server {
   listen 80;
   server_name localhost;
   location /login {
     root /usr/share/nginx/html;
     index index.html index.html;
   }
 }

limit_req_zone指令定义了流量限制相关的参数,而limit_req指令在出现的上下文中启用流量限制(示例中,对于”/login/”的所有请求)

limit_req_zone 指令通常在HTTP块中定义,使其可在多个上下文中使用,它需要以下三个参数:

参数说明
key定义应用限制的请求特性
zone定义用于存储每个IP地址状态以及被限制请求URL访问频率的共享内存区域
rate定义最大请求速率

当Nginx需要添加新条目时存储空间不足,将会删除旧条目。如果释放的空间仍不够容纳新记录,Nginx将会返回 503状态码(Service Temporarily Unavailable)另外,为了防止内存被耗尽,Nginx每次创建新条目时,最多删除两条60秒内未使用的条目。

limit_req_zone 指令设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。所以需要通过添加limit_req 指令,将流量限制应用在特定的 location 或者 server 块。在上面示例中,我们对 /login/ 请求进行流量限制。现在每个IP地址被限制为每秒只能请求10次 /login/ ,更准确地说,在前一个请求的100毫秒内不能请求该URL

3、测试访问

当我刷新一次时,正常访问

当访问超过设置的次数时:(本例为方便测试,设置1秒内1次访问)

三、处理突发

如果我们在100毫秒内接收到2个请求,怎么办?对于第二个请求,Nginx将给客户端返回状态码503。这可能并不是我们想要的结果,因为应用本质上趋向于突发性。相反地,我们希望缓冲任何超额的请求,然后及时地处理它们。我们更新下配置,在 limit_req 中使用 burst 参数

 limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
 upstream myweb {
   server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;
 }
 server {
   listen 80;
   server_name localhost;
   location /login {
     limit_req zone=mylimit burst=20;
     proxy_pass http://myweb;
     proxy_set_header Host $host:$server_port;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }
 }

burst 参数定义了超出zone指定速率的情况下,客户端还能发起多少请求。上一个请求100毫秒内到达的请求将会被放入队列,我们将队列大小设置为20;

意味着,如果从一个给定IP地址发送21个请求,Nginx会立即将第一个请求发送到上游服务器群,然后将余下20个请求放在队列中。然后每100毫秒转发一个排队的请求,只有当传入请求使队列中排队的请求数超过20时,Nginx才会向客户端返回503

四、无延迟排队

配置 burst 参数将会使通讯更流畅,但是可能会不太实用,因为该配置会使站点看起来很慢。在上面的示例中,队列中的第20个包需要等待2秒才能被转发,此时返回给客户端的响应可能不再有用。要解决这个情况,可以在 burst 参数后添加 nodelay 参数

 limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
 upstream myweb {
   server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;
 }
 server {
   listen 80;
   server_name localhost;
   location /login {
     limit_req zone=mylimit burst=20 nodelay;
     proxy_pass http://myweb;
     proxy_set_header Host $host:$server_port;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
 }

使用 nodelay 参数,Nginx仍将根据 burst 参数分配队列中的位置,并应用已配置的速率限制,而不是清理队列中等待转发的请求。相反地,当一个请求到达“太早”时,只要在队列中能分配位置,Nginx将立即转发这个请求。将队列中的该位置标记为”taken”(占据),并且不会被释放以供另一个请求使用,直到一段时间后才会被释放(在这个示例中是,100毫秒后)

如果希望不限制两个请求间允许间隔的情况下实施“流量限制”, nodelay 参数是很实用的;注意: 对于大部分部署,建议使用 burst 和 nodelay 参数来配置 limit_req 指令

五、配置流量控制相关功能

1、配置日志记录

默认情况下,Nginx会在日志中记录由于流量限制而延迟或丢弃的请求,如下所示:

 2023/02/13 04:20:00 [error] 120315#0: *32086 limiting requests, excess: 1.000
 by zone "mylimit", client: 192.168.1.2, server: nginx.com, request: "GET /
 HTTP/1.0", host: "nginx.com"

日志条目中包含的字段:

参数说明
limiting requests表明日志条目记录的是被“流量限制”请求
excess每毫秒超过对应“流量限制”配置的请求数量
zone定义实施“流量限制”的区域
client发起请求的客户端IP地址
server服务器IP地址或主机名
request客户端发起的实际HTTP请求
hostHTTP报头中host的值

默认情况下,Nginx以error级别来记录被拒绝的请求,如上所示(Nginx以较低级别记录延迟请求,一般是info级别);如果要更改Nginx的日志记录级别,需要使用limit_req_log_level指令。下面修改为warn:

 limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
 upstream myweb {
   server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;
 }
 server {
   listen 80;
   server_name localhost;
   location /login {
     limit_req zone=mylimit burst=20 nodelay;
     limit_req_log_level warn;
     proxy_pass http://myweb;
     proxy_set_header Host $host:$server_port;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }
 }

2、发送到客户端到错误代码

一般情况下,客户端超过配置的流量限制时,Nginx响应状态码为503(Service Temporarily Unavailable)可以使用 limit_req_status 指令来设置为其它状态码(例如下面的404状态码):

 limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
 upstream myweb {
   server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;
 }
 server {
   listen 80;
   server_name localhost;
   location /login {
     limit_req zone=mylimit burst=20 nodelay;
     limit_req_log_level warn;
     limit_req_status 404;
     proxy_pass http://myweb;
     proxy_set_header Host $host:$server_port;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }
 }

致谢

在此,我要对所有为知识共享做出贡献的个人和机构表示最深切的感谢。同时也感谢每一位花时间阅读这篇文章的读者,如果文章中有任何错误,欢迎留言指正。 

学习永无止境,让我们共同进步!!

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李学不完

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值