Nginx连接与请求速率限制详解

Nginx连接与请求速率限制主要由两组指令组成,它们是非常核心的流量控制和防攻击手段:

第一组指令:限制并发连接数

limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;limit_conn conn_per_ip 10;

指令 1:limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;

这行指令的作用是定义一个共享内存区域,用于存储每个 IP 地址的并发连接计数

  • limit_conn_zone:这是 Nginx 的指令,用于创建一个“连接限制”的共享内存区域。
  • $binary_remote_addr:这是一个 Nginx 内置变量,代表客户端的 IP 地址。这里使用 $binary_remote_addr 而不是 $remote_addr 是因为前者是二进制格式,占用空间更小(固定 4 字节 for IPv4,16 字节 for IPv6),而后者是字符串格式(如 “192.168.1.1”),长度在 7 到 15 字节之间,更节省内存。
  • zone=conn_per_ip:10m:
    • zone= 关键字,后面跟区域定义。
    • conn_per_ip:这是你为这个共享内存区域起的名字,可以自定义。
    • 10m:分配给这个区域的内存大小。10m 表示 10 兆字节(MB)。根据官方文档,在 64 位平台上,10m 可以存储大约 16 万个 IP 地址的状态信息。这个大小需要根据你的服务器情况和预期 IP 数量来调整。

简单来说:这一行创建了一个名为 conn_per_ip、大小为 10MB 的“小黑板”,Nginx 会在这个小黑板上记录每个 IP ($binary_remote_addr) 当前建立了多少个连接。

指令 2:limit_conn conn_per_ip 10;

这行指令的作用是在特定的 location 或 server 块中,应用上面定义的限制规则

  • limit_conn:这是应用连接限制的指令。
  • conn_per_ip:指定使用我们上面定义的、名为 conn_per_ip 的共享内存区域。
  • 10:每个 IP 地址同时允许的最大并发连接数。这里设置为 10。

工作流程:

当一个新连接到来时,Nginx 会:

查看 conn_per_ip 这个“小黑板”,找到该客户端 IP 当前的连接数。

如果连接数已经 >=10,Nginx 会拒绝这个新连接(返回 503 Service Temporarily Unavailable 错误)。

如果连接数 <10,则允许连接建立,并将该 IP 的连接计数加 1。

当这个连接关闭时,Nginx 会将计数减 1。

应用场景:

防止单个用户或恶意程序用大量并发连接拖垮服务器。例如,防止下载工具开过多线程,或者防止 CC 攻击建立大量空连接消耗服务器资源。

第二组指令:限制请求速率

这组指令同样分为两部分:定义共享内存区和速率应用限制

指令 1:limit_req_zone $binary_remote_addr zone=req_per_ip:10m rate=10r/s;

这行指令的作用是定义一个共享内存区域,用于存储每个 IP 地址的请求访问状态(像一个漏桶)

  • limit_req_zone:这是 Nginx 的指令,用于创建一个“请求限制”的共享内存区域。
  • $binary_remote_addr:同上,客户端的 IP 地址。
  • zone=req_per_ip:10m
    • req_per_ip:为这个区域起的名字。
    • 10m:内存大小,同样是 10MB。
  • rate=10r/s:这是核心的速率限制参数。
    • 10r/s 表示每秒允许 10 个请求。r/srequests per second
    • 你也可以使用 r/m(每分钟),例如 rate=600r/m 同样表示每秒 10 个请求。

简单来说:这一行创建了一个名为 req_per_ip、大小为 10MB 的“漏桶”,这个桶的漏水速率是每秒 10 个请求。

指令 2:limit_req zone=req_per_ip burst=20 nodelay;

这行指令的作用是在特定的 location 或 server 块中,应用上面定义的“漏桶”规则,并配置突发流量处理。

  • limit_req:应用请求限制的指令。
  • zone=req_per_ip:指定使用名为 req_per_ip 的共享内存区域。
  • burst=20:突发容量。这相当于在“漏桶”上方加了一个缓冲区或队列。当请求的速率超过 rate 时,超出的请求不会立即被拒绝,而是先放入这个 burst 队列中排队等待处理。20 表示这个队列最多可以容纳 20 个请求。
  • nodelay:不延迟处理。这是一个非常重要的选项。
    • 如果没有 nodelay:进入 burst 队列的请求会被延迟处理,即以固定的 rate(每秒10个)的速度被处理,这会使请求的响应时间变长。
    • 如果有 nodelay:当请求到来时,只要 burst 队列还有空位,Nginx 会立即处理这些请求,而不会延迟。但是,这并不意味着速率限制消失了。一旦 burst 队列被填满,后续的请求会立即被拒绝。

工作流程(以 burst=20 nodelay 为例):

  1. 第 1 秒内,来了 15 个请求。
    • 前 10 个请求被正常处理(达到了 rate=10r/s 的速率)。
    • 因为设置了 burst=20,接下来的 5 个请求会被放入 burst 队列,并被 nodelay 立即处理。
    • 此时,burst 队列长度变为 5。
  2. 第 2 秒内,来了 30 个请求。
    • 前 10 个请求被正常处理(消耗了本秒的速率)。
    • 接下来的 15 个请求会填满 burst 队列(因为队列还剩 20 - 5 = 15 个空位),并被 nodelay 立即处理。
    • 此时,burst 队列已满(20/20)。
    • 还剩下的 5 个请求 (30 - 10 - 15 = 5) 因为超过了 rate + burst 的总容量,Nginx 会立即返回 503 错误拒绝它们。
  3. 第 3 秒,没有新请求。Nginx 会从 burst 队列中“排出”10 个请求(因为速率是 10r/s),队列长度变为 10。

应用场景:

防止恶意刷接口、暴力破解密码、爬虫抓取等高频请求行为。同时,burst nodelay 允许了正常的突发流量,避免了误伤那些在短时间内有合理高并发请求的正常用户(例如:页面加载时浏览器同时请求多个资源)。

总结与对比

特性 限制连接 (limit_conn) 限制请求 (limit_req)
限制对象 并发连接数(同时存在的连接) 请求速率(单位时间内的请求数)
工作方式 计数,超过即拒绝 漏桶算法,平滑处理流量
核心指令 limit_conn_zonelimit_conn limit_req_zonelimit_req
内存区域 zone=conn_per_ip:10m zone=req_per_ip:10m rate=10r/s
应用参数 limit_conn zone_name 10; (数字) limit_req zone_name burst=20 nodelay;
应对场景 下载线程、CC空连接 刷API、暴力破解、爬虫
错误码 503 (Service Unavailable) 503 (Service Unavailable)

配置建议:

通常你会把 limit_conn_zonelimit_req_zone 放在 http {} 块中,使其全局生效。而 limit_connlimit_req 则根据需要在 server {}location {} 块中配置。对于登录、提交等关键接口,可以设置更严格的 limit_req 规则。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部
×
问题求助