NGINX的速率限制(限流)

NGINX 的速率限制(限流)

NGINX最有用但经常被误解和配置错误的功能之一是限流。它允许您限制用户在给定时间段内可以发出的HTTP请求量。

限流可以用于安全目的,例如减慢暴力破解密码的攻击。它可以通过限制请求速率为真实用户的典型值来帮助防御分布式拒绝服务(DDoS)攻击,并且(通过记录日志)可以识别被攻击的URL。更一般地说,它用于保护上游应用服务器免受过多用户请求同时到达而导致的压力过大。

在本博客中,我们将介绍 NGINX 限流的基础知识以及更高级的配置。当然限流在 NGINX Plus 中的工作方式相同。

NGINX限流的工作原理

NGINX 限流使用漏桶算法,该算法广泛用于电信和数据包交换计算机网络,用于在带宽有限时处理突发性。好比一个水桶,水从上面倒入,从下面漏出;如果倒入水的速度超过漏水的速度,水桶就会溢出。在请求处理方面,水代表客户端的请求,桶代表一个队列,请求按照先进先出(FIFO)调度算法等待处理。漏水代表退出缓冲区供服务器处理的请求,溢出代表被丢弃且从未得到服务的请求。

限流基本配置

限流由两个主要指令limit_req_zone和进行配置limit_req,如下例所示:

需要注意的一个点是rate速率是正整数,/s是每秒;/m是每分

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
 
server {
    location /qhyu/ {
        limit_req zone=mylimit;
        
        proxy_pass http://my_upstream;
    }
}

limit_req_zone指令定义了速率限制的参数,同时limit_req在它出现的上下文中启用速率限制(在示例中,对于 /qhyu/ 的所有请求)。

我用postman做了一个并发测试,除了第一个接口返回200,其他的都被限流了。
在这里插入图片描述

nginx日志如下:

在这里插入图片描述

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

  • key-定义应用的请求特征。在示例中,它是nginx变量 $binary_remote_addr,它保存客户端IP地址的二进制表现形式。这意味着我们将每个唯一的IP地址限制为第三个参数定义的请求速率。(我们使用此变量是因为它比客户端 IP 地址的字符串表示占用的空间更少$remote_addr

  • zone-定义用于存储每个IP地址的状态及其访问请求限制URL的频率的共享内存区域。将信息保存在共享内存中意味着它可以在nginx工作进程之间共享。该定义有两部分:由关键字标识的区域名称zone=,以及冒号后面的大小。大约16000个IP地址的状态信息需要1兆字节,因为我们的区域可以存储大约160000个地址。

    如果nginx需要添加新条目时存储空间耗尽,它将删除最旧的条目。如果释放的空间仍不足以容纳新记录,nginx将返回状态码。此外,为了防止内存耗尽,每次nginx创建条目时,它都会删除最多两个在前60s内未使用的条目。503 Service Temporarily Unavailable

  • rate-设置最大请求速率。在示例中,速率不能超过每秒10个请求。nginx实际上以毫秒粒度跟踪请求,因此此限制对应于每 100 毫秒 (ms) 1 个请求。因为我们不允许突发(请参阅下一节),这意味着如果请求在上一个允许的请求之后不到 100 毫秒到达,则该请求将被拒绝。

limit_req_zone指令设置了速率限制和共享内存区域的参数,但它实际上并不限制请求速率。为此,您需要通过在其中包含指令来将限制应用于特定location或块。在示例中,我们对 /qhyu/ 的请求进行速率限制。limit_req

因此,现在每个唯一的 IP 地址限制为每秒 10 次 /qhyu/ 请求 ,或者更准确地说,不能在前一个 URL 的 100 毫秒内对该 URL 发出请求。

处理突发

如果我们在 100 毫秒内收到 2 个请求怎么办?对于第二个请求,NGINX 将状态代码返回503给客户端。一些业务场景下这可能不是我们想要的,因为应用程序本质上往往是突发性的。相反,我们希望缓冲任何多余的请求并及时为它们提供服务。如这个更新的配置所示:

location /qhyu/ {
    limit_req zone=mylimit burst=20;
 
    proxy_pass http://my_upstream;
}

该burst参数定义客户端可以发出超出区域指定速率的请求数量(对于我们的示例mylimit区域,速率限制为每秒 10 个请求,或每 100 毫秒 1 个请求)。比上一个请求晚 100 毫秒到达的请求将被放入队列中,这里我们将队列大小设置为 20。

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

排队无延迟

这种配置burst可以使流量流畅,但不太实用,因为它会使您的网站显得很慢。在我们的示例中,队列中的第 20 个数据包等待 2 秒才能转发,此时对其的响应可能不再对客户端有用。为了解决这种情况,将nodelay参数与参数burst一起添加:

location /qhyu/ {
    limit_req zone=mylimit burst=20 nodelay;
 
    proxy_pass http://my_upstream;
}

使用该nodelay参数,NGINX 仍然根据该burst参数在队列中分配插槽并施加配置的速率限制,但不会间隔转发排队的请求。相反,当请求“太快”到达时,NGINX 会立即转发它,只要队列中有可用的槽位。它将该插槽标记为“已占用”,并且在经过适当的时间(在我们的示例中,100 毫秒后)之前不会将其释放以供其他请求使用。

与之前一样,假设 20 槽队列为空,并且有 21 个请求同时从给定 IP 地址到达。NGINX 立即转发所有 21 个请求,并将队列中的 20 个槽标记为已占用,然后每 100 毫秒释放 1 个槽。(如果有 25 个请求,NGINX 将立即转发其中 21 个,将 20 个槽标记为已占用,并拒绝 4 个状态为503的请求。)

现在假设第一组请求转发后 101 毫秒,另外 20 个请求同时到达。队列中只有 1 个槽被释放,因此 NGINX 转发 1 个请求并拒绝其他 19 个状态为 的请求 503。相反,如果在 20 个新请求到达之前已经过去了 501 毫秒,则有 5 个插槽空闲,因此 NGINX 会立即转发 5 个请求并拒绝 15 个。

效果相当于每秒 10 个请求的速率限制。nodelay如果您想要施加速率限制而不限制请求之间允许的间距,则该选项非常有用。

注意: 对于大多数部署,我们建议 在指令limit_req中包含burstnodelay 参数。

两阶段限速

综合上述内容,我们可以将nginx配置为允许突发请求以适应典型的web浏览器请求模式,然后将额外的过多请求限制到某个点,通过阈值拒绝其他过多的请求。使用limit_req指令的delay参数启用两级速率限制。

为了说明两阶段速率限制,这里我们配置 NGINX 通过施加每秒 5 个请求 (r/s) 的速率限制来保护网站。该网站通常每页有 4-6 个资源,但永远不会超过 12 个资源。该配置允许突发最多 12 个请求,其中前 8 个请求将立即得到处理。在 8 个过多请求后添加延迟以强制执行 5 r/s 限制。超过 12 次请求后,任何进一步的请求都会被拒绝。

limit_req_zone $binary_remote_addr zone=ip:10m rate=5r/s;

server {
    listen 80;
    location / {
        limit_req zone=ip burst=12 delay=8;
        proxy_pass http://website;
    }
}

delay参数定义了在突发大小内限制(延迟)过多请求以符合定义的速率限制的点。完成此配置后,以 8 r/s 发出连续请求流的客户端会经历以下行为。
在这里插入图片描述

前 8 个请求( delay的值)由 NGINX无延迟地代理。接下来的 4 个请求 ( burst - delay) 将被延迟,以便不超过定义的 5 r/s 速率。接下来的 3 个请求将被拒绝,因为已超出总突发大小。后续请求将被延迟。

高级配置示例

通过将基本速率限制与其他 NGINX 功能相结合,您可以实现更细致的流量限制。

列入白名单

此示例演示如何对不在“允许列表”中的任何人的请求施加速率限制。

geo $limit {
    default 1;
    10.0.0.0/8 0;
    192.168.0.0/24 0;
}
 
map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}
 
limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;
 
server {
    location / {
        limit_req zone=req_zone burst=10 nodelay;
 
        # ...
    }
}

此示例同时使用了geomap指令

  • 如果$limit0$limit_key设置为空字符串
  • 如果$limit1$limit_key则设置为二进制格式的客户端 IP 地址

将两者放在一起,$limit_key对于列入白名单的 IP 地址,设置为空字符串,否则设置为客户端的 IP 地址。当目录的第一个参数limit_req_zone(密钥)为空字符串时,不应用限制,因此列入白名单的 IP 地址(在 10.0.0.0/8 和 192.168.0.0/24 子网中)不受限制。所有其他 IP 地址限制为每秒 5 个请求。

limit_req指令将限制应用于 / 位置,并允许突发超过配置限制的最多 10 个数据包,且转发无延迟

在一个位置中包含多个limit_req指令

可以limit_req在一个位置包含多个指令。应用与给定请求匹配的所有限制,这意味着使用最严格的限制。例如,如果多个指令施加延迟,则使用最长的延迟。同样,如果这是任何指令的效果,则请求将被拒绝,即使其他指令允许它们通过。

扩展前面的示例,我们可以对白名单上的 IP 地址应用速率限制:

http {
    # ...
 
    limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;
    limit_req_zone $binary_remote_addr zone=req_zone_wl:10m rate=15r/s;
 
    server {
        # ...
        location / {
            limit_req zone=req_zone burst=10 nodelay;
            limit_req zone=req_zone_wl burst=20 nodelay;
            # ...
        }
    }
}

允许名单上的 IP 地址与第一个速率限制 ( req_zone )不匹配,但与第二个速率限制 ( req_zone_wl )匹配,因此限制为每秒 15 个请求。不在允许列表中的 IP 地址与两个速率限制均匹配,因此选择限制性更强的速率限制:每秒 5 个请求。

配置相关功能

记录

日志条目中的字段包括:

  • 2023/08/25 04:20:00 – 写入日志条目的日期和时间
  • [error] – 严重程度
  • 120315#0 – NGINX工作线程的进程ID和线程ID,用符号#分隔
  • *32086 – 速率受限的代理连接的 ID
  • limiting requests – 指示日志条目记录速率限制
  • excess – 此请求所代表的配置速率上的每毫秒请求数
  • zone – 定义施加速率限制的区域
  • client – 发出请求的客户端的 IP 地址
  • server – 服务器的 IP 地址或主机名
  • request – 客户端发出的实际 HTTP 请求
  • hostHostHTTP 标头的值

默认情况下,NGINX 在该级别记录拒绝的请求,如上例error所示。[error](默认情况下,它会在低一级记录延迟请求warn。)要更改日志记录级别,请使用该limit_req_log_level指令。这里我们将拒绝的请求设置为日志级别warn

location /qhyu/ {
    limit_req zone=mylimit burst=20 nodelay;
    limit_req_log_level warn;
 
    proxy_pass http://my_upstream;
}

发送给客户端的错误代码

默认情况下,当客户端超出其速率限制时,NGINX 会返回状态代码503 ( Service Temporarily Unavailable) 。使用limit_req_status指令设置不同的状态代码(444在本例中):

location /login/ {
    limit_req zone=mylimit burst=20 nodelay;
    limit_req_status 444;
}

拒绝对特定位置的所有请求

如果您想拒绝对特定 URL 的所有请求,而不仅仅是限制它们,请location为其配置一个块并包含以下指令:

location /foo.php {
    deny all;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/90608.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI推出GPT-3.5Turbo微调功能并更新API;Midjourney更新局部绘制功能

🦉 AI新闻 🚀 OpenAI推出GPT-3.5Turbo微调功能并更新API,将提供GPT-4微调功能 摘要:OpenAI宣布推出GPT-3.5Turbo微调功能,并更新API,使企业和开发者能够定制ChatGPT,达到或超过GPT-4的能力。通…

c语言每日一练(11)

前言:每日一练系列,每一期都包含5道选择题,2道编程题,博主会尽可能详细地进行讲解,令初学者也能听的清晰。每日一练系列会持续更新,暑假时三天之内必有一更,到了开学之后,将看学业情…

C#-集合小例子

目录 背景: 过程: 1.添加1-100数: 2.求和: 3.平均值: 4.代码:​ 总结: 背景: 往集合里面添加100个数,首先得有ArrayList导入命名空间,这个例子分为3步,1.添加1-100个数2.进行1-100之间的总和3.求总和的平均值&…

安全帽穿戴检测人脸闸机联动

安全帽穿戴检测人脸闸机联动系统实通过yolov8网络深度学习算法模型,安全帽穿戴检测人脸闸机联动系统现对进入工地施工区域人员是否穿戴安全帽进行精准监测和身份识别,只有在满足这两个条件的情况下,闸机才会打开,允许其进入工地施…

ICT产教融合创新实训基地物联网实训室建设方案

一、概述 1.1物联网定义 物联网工程(Internet of Things Engineering)是一种以信息技术(IT)来改善实体世界中人们生活方式的新兴学科,它利用互联网技术为我们的日常生活活动提供服务和增益,从而让各种智能…

怎么借助ChatGPT处理数据结构的问题

目录 使用ChatGPT进行数据格式化转换 代码示例 ChatGPT格式化数据提示语 代码示例 批量格式化数据提示语 代码示例 ChatGPT生成的格式化批处理代码 使用ChatGPT合并不同数据源的数据 合并数据提示语 自动合并数据提示语 ChatGPT生成的自动合并代码 结论 数据合并是…

软件设计师学习笔记6-存储系统

1.层次化存储体系 1.1层次化存储结构 局部性原理是层次化存储结构的支持 时空局部性:刚被访问的内容,立即又被访问(eg: 循环体 ) 空间局部性:刚被访问的内容,临近的空间很快被访问(eg:数组) 1.2层次化存储结构的分类 DRAM&…

VAE原理 代码详解 pin_memory

VAE代码 import torch from torch import nn import torch.nn.functional as F class VAE(nn.Module):def __init__(self, input_dim784, h_dim400, z_dim20): # 28x28784,20可能是这个手写体一共有20类?super(VAE, self).__init__()self.input_dim input_dimsel…

微信开放注册微信小号功能,工作人群福音!

微信,这个坐拥数亿用户的社交巨头,最近终于开放了注册微信小号的功能。这个功能对于需要多个微信账号进行工作的人来说,无疑是一场及时雨,极大地提高了工作便利性。 在之前的版本中,每个微信账号都绑定了一个手机号&am…

主从、哨兵、集群模式有什么区别 ?

目录 1.Redis 多机部署的方式 2.主从、哨兵、集群模式有什么区别 2.1 主从同步 2.2 哨兵模式 2.3 集群模式 1.Redis 多机部署的方式 Redis 多机部署主要有 3 种方式: 1. 主从同步:主要存储数据的节点叫做主节点(master)&…

限时 180 天,微软为 RHEL 9 和 Ubuntu 22.04 推出 SQL Server 2022 预览评估版

导读近日消息,微软公司今天发布新闻稿,宣布面向 Red Hat Enterprise Linux(RHEL)9 和 Ubuntu 22.04 两大发行版,以预览模式推出 SQL Server 2022 评估版。 近日消息,微软公司今天发布新闻稿,宣布…

网络安全(黑客)零基础自学

网络安全是什么? 网络安全,顾名思义,网络上的信息安全。 随着信息技术的飞速发展和网络边界的逐渐模糊,关键信息基础设施、重要数据和个人隐私都面临新的威胁和风险。 网络安全工程师要做的,就是保护网络上的信息安…

数字 IC 设计职位经典笔/面试题(三)

共100道经典笔试、面试题目(文末可全领) 1. IC 设计中同步复位与异步复位的区别? 同步复位在时钟沿变化时,完成复位动作。异步复位不管时钟,只要复位信号满足条件,就完成复位动作。异步复位对复位信号要求…

开始MySQL之路——MySQL的DataGrip图形化界面

下载DataGrip 下载地址:Download DataGrip: Cross-Platform IDE for Databases & SQL 安装DataGrip 准备好一个文件夹,不要中文和空格 C:\Develop\DataGrip 激活DataGrip 激活码: VPQ9LWBJ0Z-eyJsaWNlbnNlSWQiOiJWUFE5TFdCSjBaIiwibGl…

用 Audacity 比较两段音频差异

工作中遇到相同的处理流程,处理同一段音频,看看处理结果是否一致,可以用audacity来处理。 假设待比较的音频分别为 1.wav 2.wav 1、用Audacity打开1.wav 2、用Audacity打开2.wav,选中音频,然后用 效果 -> 反向&am…

Linux内核学习(九)—— 虚拟文件系统(基于Linux 2.6内核)

虚拟文件系统(VFS)作为内核子系统,为用户空间程序提供了文件和文件系统相关的接口。通过虚拟文件系统,程序可以利用标准的 Unix 系统调用对不同的文件系统(甚至不同介质上的文件系统)进行读写操作。 一、通…

【算法系列篇】前缀和

文章目录 前言什么是前缀和算法1.【模板】前缀和1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 【模板】二维前缀和2.1 题目要求2.2 做题思路2.3 Java代码实现 3. 寻找数组的中心下标3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 除自身以外的数组的乘积4.1 题目要求4.2 做题思…

C++:构造方法(函数);拷贝(复制)构造函数:浅拷贝、深拷贝;析构函数。

1.构造方法(函数) 构造方法是一种特殊的成员方法,与其他成员方法不同: 构造方法的名字必须与类名相同; 无类型、可有参数、可重载 会自动生成,可自定义 一般形式:类名(形参); 例: Stu(int age); 当用户没自定义构造方法时&…

apache的ab工具测试网页优化效果速度以及服务器承载

今天为大家介绍一款apache自带的一种的测试网页优化效果速度以及服务器承载的工具——ab.exe。 大家在工作中或者开发中可以使用apache的ab工具来测试自己的网站并发量大小,和某个页面的访问时间。 一、基本用法 如果你是用的是apache的话,那么只要进…

基于swing的校园茶餐厅java jsp点餐订餐管理mysql源代码

本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 基于swing的校园茶餐厅 系统有1权限 二、主要功能 …