Nginx之限流

news2025/1/19 16:20:18

文章目录

      • Nginx如何限流
      • 配置基本的限流
      • 处理突发
      • 无延迟的排队
      • 高级配置示例
      • location包含多limit_req指令
      • 配置相关功能
      • 发送到客户端的错误代码
      • 指定location拒绝所有请求
      • 总结

流量限制(rate-limiting),是 Nginx 中一个非常实用,却经常被错误理解和错误配置的功能。我们可以用来限制用户在给定时间内 HTTP 请求的数量。请求,可以是一个简单网站首页的 GET 请求,也可以是登录表单的 POST 请求。

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

本篇文章将会介绍 Nginx 的流量限制 的基础知识和高级配置,”流量限制”在 Nginx Plus 中也适用。

Nginx如何限流

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

配置基本的限流

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

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
    location /login/ {
        limit_req zone=mylimit;

        proxy_pass http://my_upstream;
    }
}

limit_req_zone指令定义了流量限制相关的参数,而limit_req指令在出现的上下文中启用流量限制(示例中,对于”/login/”的所有请求)。limit_req_zone指令通常在 HTTP 块中定义,使其可在多个上下文中使用,它需要以下三个参数:

  • Key - 定义应用限制的请求特性。示例中的 Nginx 变量remote_addr,占用更少的空间)
  • Zone - 定义用于存储每个 IP 地址状态以及被限制请求 URL 访问频率的共享内存区域。保存在内存共享区域的信息,意味着可以在 Nginx 的 worker 进程之间共享。定义分为两个部分:通过zone=keyword标识区域的名字,以及冒号后面跟区域大小。16000 个 IP 地址的状态信息,大约需要 1MB,所以示例中区域可以存储 160000 个 IP 地址。
  • Rate - 定义最大请求速率。在示例中,速率不能超过每秒 10 个请求。Nginx 实际上以毫秒的粒度来跟踪请求,所以速率限制相当于每 100 毫秒 1 个请求。因为不允许”突发情况”,这意味着在前一个请求 100 毫秒内到达的请求将被拒绝。

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

limit_req_zone指令设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。所以需要通过添加limit_req指令,将流量限制应用在特定的 location 或者 server 块。在上面示例中,我们对/login/请求进行流量限制。

图片

现在每个 IP 地址被限制为每秒只能请求 10 次 /login/,更准确地说,在前一个请求的 100 毫秒内不能请求该 URL。

处理突发

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

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

burst 参数定义了超出 zone 指定速率的情况下(示例中的 mylimit 区域,速率限制在每秒 10 个请求,或每 100 毫秒一个请求),客户端还能发起多少请求。上一个请求 100 毫秒内到达的请求将会被放入队列,我们将队列大小设置为 20。

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

无延迟的排队

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

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

    proxy_pass http://my_upstream;
}

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

假设如前所述,队列中有 20 个空位,从给定的 IP 地址发出的 21 个请求同时到达。Ngin x会立即转发这个 21 个请求,并且标记队列中占据的 20 个位置,然后每 100 毫秒释放一个位置。如果是25个请求同时到达,Nginx 将会立即转发其中的 21 个请求,标记队列中占据的 20 个位置,并且返回 503 状态码来拒绝剩下的 4 个请求。

现在假设,第一组请求被转发后 101 毫秒,另 20 个请求同时到达。队列中只会有一个位置被释放,所以 Nginx 转发一个请求并返回503状态码来拒绝其他 19 个请求。如果在 20 个新请求到达之前已经过去了 501 毫秒,5 个位置被释放,所以 Nginx 立即转发 5 个请求并拒绝另外 15 个。

效果相当于每秒 10 个请求的“流量限制”。如果希望不限制两个请求间允许间隔的情况下实施“流量限制”,nodelay 参数是很实用的。

注意:对于大部分部署,我们建议使用 burst 和 nodelay 参数来配置limit_req指令。

高级配置示例

通过将基本的“流量限制”与其他 Nginx 功能配合使用,我们可以实现更细粒度的流量限制。

「白名单」

下面这个例子将展示,如何对任何不在白名单内的请求强制执行“流量限制”:

geo $limit {
    default         1;
    10.0.0.0/8         0;
    192.168.0.0/64     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;

        # ...
    }
}

这个例子同时使用了 geo 和 map 指令。geo 块将给在白名单中的 IP 地址对应的 $limit 变量分配一个值 0,给其它不在白名单中的分配一个值 1。然后我们使用一个映射将这些值转为 key,如下:

  • 如果变量的值是,limit_key变量将被赋值为空字符串
  • 如果变量的值是,limit_key变量将被赋值为客户端二进制形式的 IP 地址 两个指令配合使用,白名单内 IP 地址的$limit_key变量被赋值为空字符串,不在白名单内的被赋值为客户端的 IP 地址。当limit_req_zone后的第一个参数是空字符串时,不会应用“流量限制”,所以白名单内的 IP 地址(10.0.0.0/8 和192.168.0.0/24 网段内)不会被限制。其它所有 IP 地址都会被限制到每秒 5 个请求。

limit_req指令将限制应用到 /location块,允许在配置的限制上最多超过 10 个数据包的突发,并且不会延迟转发。

location包含多limit_req指令

我们可以在一个 location 块中配置多个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_wl,并且被限制到每秒 15 个请求。不在白名单内的 IP 地址两个限制能匹配到,所以应用限制更强的那个:每秒 5 个请求。

配置相关功能

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

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

日志条目中包含的字段:

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

默认情况下,Nginx 以 error 级别来记录被拒绝的请求,如上面示例中的[error]所示(Ngin 以较低级别记录延时请求,一般是 info 级别)。如要更改 Nginx 的日志记录级别,需要使用limit_req_log_level指令。这里,我们将被拒绝请求的日志记录级别设置为 warn:

location /login/ {
    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;
}

指定location拒绝所有请求

如果你想拒绝某个指定 URL 地址的所有请求,而不是仅仅对其限速,只需要在 location 块中配置 deny all 指令:

location /foo.php {
    deny all;
}
limit_req_status 444;

}

指定location拒绝所有请求

如果你想拒绝某个指定 URL 地址的所有请求,而不是仅仅对其限速,只需要在 location 块中配置 deny all 指令:


location /foo.php {
    deny all;
}

总结

前文已经涵盖了 Nginx 和 Nginx Plus 提供的“流量限制”的很多功能,包括为 HTTP 请求的不同 loation 设置请求速率,给“流量限制”配置 burst 和 nodelay 参数。还涵盖了针对客户端 IP 地址的白名单和黑名单应用不同“流量限制”的高级配置,阐述了如何去日志记录被拒绝和延时的请求。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript 数据处理 · 基本统计(文末附视频)

第 5 节 基本数据处理 基本统计 学习了如何对 JavaScript 中的数组数据进行操作之后&#xff0c;我们就要回到刚开始选择购买这本小册的目的了&#xff1a;使用 JavaScript 开发灵活的数据应用。既然说是数据应用&#xff0c;那么便离不开统计计算&#xff0c;而数组就可以说…

Android 设备自动重启分析[低内存]——MTK平台 debuglogger

大家有没有遇到和我一样的问题&#xff0c;android设备(我这里android 平板)用着用着突然就黑屏自动重启了&#xff0c;重启后一切正常&#xff0c;这个问题还是概率性的&#xff0c;复现都不好复现... 本人公司是做平板定制的&#xff0c;主要针对平板进行上网限制&#xff0c…

C语言进阶——字符函数

目录 一.前言 二.strlen 1.函数介绍 2.三种模拟实现 三.长度不受限制函数 1.strcpy 模拟实现 2.strcat 模拟实现 3.strcmp 模拟实现 四.长度受限制函数 1.strncpy 模拟实现 2.strncat 模拟实现 3.strncmp 模拟实现 五.字符串查找 1.strstr 模拟实现 2.st…

手把手教你快速搞定4个职场写作场景

“ 【写作能力提升】系列文章&#xff1a; 为什么建议你一定要学会写作? 手把手教你快速搞定 4 个职场写作场景 5 种搭建⽂章架构的⽅法”免费赠送! ”一、前言 Hello&#xff0c;我是小木箱&#xff0c;今天主要分享的内容是: 写作小白需要避免的五个写作误区和灵魂五问。 二…

好家伙谷歌翻译又不能用了(有效解决方法)

今天打开idea想翻译单词发现谷歌翻译又又又挂了。为什么挂掉&#xff0c;可能是那个ip节点太多人用了&#xff0c;我也不懂我就是一个小白。不bb了说一下解决方法。一、手动Ping可以连接的ip这里我使用的是&#xff1a;https://ping.chinaz.com然后我们输入&#xff1a; transl…

YoloV8简单使用

我们坐在阳光下&#xff0c;我们转眼间长大&#xff0c;Yolo系列都到V8了&#xff0c;来看看怎么个事。目标检测不能没有Yolo&#xff0c;就像西方不能没有耶路撒冷。这个万能的目标检测框架圈粉无数&#xff0c;经典的三段式改进也是改造出很多论文&#xff0c;可惜我念书时的…

论文投稿指南——中文核心期刊推荐(植物学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

English Learning - L1-12 情态动词 + 倒装 2023.1.12 周四

这里写目录标题9 情态动词9.2 may - mightmay(1) 表许可(2) 推测 --- 可能&#xff0c;或许&#xff08;50% 的概率&#xff09;might9.3 can - couldcan核心思维: 潜在的可能性&#xff0c;有某种知识和技能而能办到&#xff08;1&#xff09;能力&#xff08;有做 。。。的能…

java 计算机概述看这一篇文章就够了

第一章 计算机概述 第1节 计算机介绍 1广义上: 凡是可以帮助我们完成计算的工具统称为计算机(比如 算盘、计算器等...) 狭义上: 当前说计算机一般情况特指电子计算机(电脑)第2节 计算机历史 算盘(机械/手动) 源于中国具体作者不详,发明时间不详.我国第一颗原子弹的很多数据早期…

【论文速递】ACM2022 - 基于嵌入自适应更新和超类表示的增量小样本语义分割

【论文速递】ACM2022 - 基于嵌入自适应更新和超类表示的增量小样本语义分割 【论文原文】&#xff1a;Incremental Few-Shot Semantic Segmentation via Embedding Adaptive-Update and Hyper-class Representation 获取地址&#xff1a;https://arxiv.org/pdf/2207.12964.pd…

靶机测试djinn笔记

靶机地址https://www.vulnhub.com/entry/djinn-1,397/靶机测试信息收集nmap扫描nmap -p- -A 192.168.1.106 -oA dj 通过 nmap 扫描得到21 端口 可以匿名访问22 端口 ssh 但是被过滤了 1337 是一个游戏端口7331 是 python web测试 1337 端口访问端口nc -vv 192.168.0.177 1337这…

智慧工地安全帽智能识别检测 yolov5

智慧工地安全帽智能识别检测通过yolov5opencv深度学习技术&#xff0c;可自动对现场画面检测识别人员有没有戴安全帽。OpenCV基于C实现&#xff0c;同时提供python, Ruby, Matlab等语言的接口。OpenCV-Python是OpenCV的Python API&#xff0c;结合了OpenCV CAPI和Python语言的最…

【Spring(六)】彻底搞懂Spring的依赖注入

文章目录前言依赖注入setter注入构造器注入自动装配集合注入总结前言 在核心容器这一部分bean相关的操作&#xff0c;我们已经学完了&#xff0c;接下来我们就要进入到第二个大的模块&#xff0c;与我们的DI,也就是依赖注入相关知识的学习了&#xff0c;那我们先来学习第一个内…

ChatGPT!我是你的破壁人;比尔·盖茨不看好Web3与元宇宙;FIFA押中4届世界杯冠军;GitHub今日热榜 | ShowMeAI资讯日报

&#x1f440;日报合辑 | &#x1f3a1;AI应用与工具大全 | &#x1f514;公众号资料下载 | &#x1f369;韩信子 &#x1f3a1; 『GPTZero』用 ChatGPT 写论文糊弄老师&#xff1f;已经不灵了~ 语言生成模型的诞生与优化&#xff0c;给教育和学术界带来了不少困扰。继纽约教育…

前端工程化解决方案-Webpack编程

文章目录1. 前端工程化目前主流的前端工程化解决方案2.webpack2.1 主要供能2.2 webpack与webpack-cli的使用2.2.1 初始化项目2.2.2 安装2.2.3 配置2.2.3.1 webpack.config.js2.2.3.2 package.json2.2.3.3 打包构建2.2.3.4 项目中引入 dist/bundle.js2.3 动态部署2.3.1 webpack-…

微服务架构概述

微服务架构概述一、架构演变1.1 单体架构1.2 分布式架构1.3 微服务二、SpringCloud2.1 简介3.2 痛点三、SpringCloud Alibaba3.1 简介3.2 优点3.3 主要组件3.4 版本对应一、架构演变 1.1 单体架构 讲业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署。 优点&am…

SaaS架构实现理论(四)可伸缩多租户

目录1.伸缩性&#xff08;Scalable&#xff09;的概念2.应用服务器层的水平扩展2.1基于Session复制的水平扩展方式2.2基于Session Sticky的水平扩展方式2.3基于Cache的集中式Session实现水平扩展2.4三种水平扩展方式的比较3.数据库的水平扩展3.1数据库的垂直切分3.2数据库的读写…

ArcGIS基础实验操作100例--实验93插值模型的精度分析

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 空间分析篇--实验93 插值模型的精度分析 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;…

ESP-IDF:使用基本类型,指针,引用,指针的指针,指针的引用作为函数参数的几个例程

1.例程&#xff1a; /下面是使用基本类型&#xff0c;指针&#xff0c;引用&#xff0c;指针的指针&#xff0c;指针的引用作为函数参数的几个例程/ // 值拷贝 int add10(int a) { a 10; return a; } // 指针传参&#xff0c;是一种地址拷贝 void add101(int *a) { // int *…

(11)QWidget的使用(two)

目录 设置窗口图标和标题 设置窗口图标以及获取图标 设置窗口标题以及获取标题 窗口标题的特殊操作 设置窗口的状态 设置窗口的不透明度 设置窗口的状态 使用封装好的函数显示窗口 设置窗口标志 窗口标志简介 设置窗口图标和标题 设置窗口图标以及获取图标 void se…