别让“机器人”把你的网站搞垮!Nginx 速率限制实战指南


嘿,各位开发者和运维小伙伴们,大家好!

想象一下,你的网站或 API 运行得好好的,突然间,一个“不速之客”——可能是一个恶意脚本或者一个写得不怎么样的爬虫——开始疯狂地向你的服务器发送请求。很快,你的服务器就不堪重负,响应越来越慢,最后甚至直接“罢工”了。这可不是我们想看到的。

今天,我们就来聊聊如何用 Nginx 这个“看门大爷”来解决这个问题,也就是大名鼎鼎的 **速率限制 (Rate Limiting)**。说白了,就是给每个访问者规定一个“额度”,超过这个额度,就得“排队”或者直接被“拒之门外”。这样一来,我们就能有效地防止恶意请求,保护我们的应用服务。

速率限制的“幕后英雄”:漏桶算法

在深入配置之前,我们先来简单了解一下 Nginx 速率限制背后的工作原理——**漏桶算法 (Leaky Bucket Algorithm)**。

你可以把这个算法想象成一个顶部可以进水,底部有一个小孔可以匀速出水的桶。

  • 水滴:就是来自客户端的一个个请求。
  • :是 Nginx 用来缓存请求的一个队列。
  • 底部的小孔:代表 Nginx 处理请求的能力,它会以一个固定的速率来处理请求。

当请求(水滴)进来时,如果桶里还有空间,请求就会被缓存起来。然后,Nginx 会以固定的速率从桶底“漏”出请求进行处理。如果请求进来的速度太快,把桶装满了,后面再来的请求就会被直接丢弃,或者收到一个错误提示。

这个算法的好处在于,它能够平滑突发流量,保证后端服务收到的请求速率是稳定可控的。

核心配置:limit_req_zonelimit_req

要实现 Nginx 的速率限制,我们主要跟两个指令打交道:limit_req_zonelimit_req

  1. limit_req_zone: 这位是“规则制定者”。它用来定义一个速率限制的“区域”,规定了限制的依据、内存大小和速率。这个指令通常放在 Nginx 配置文件的 http 块中。
  2. limit_req: 这位是“规则执行者”。它在你想要应用速率限制的 serverlocation 块中使用,告诉 Nginx 在这里要使用哪个“区域”的规则。

limit_req_zone 指令详解

我们来看一个具体的例子:

http {
    # ... 其他配置 ...

    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;

    # ... 其他配置 ...
}

这行代码的意思是:

  • $binary_remote_addr: 这是 Nginx 的一个变量,代表了客户端的 IP 地址(二进制格式,更省内存)。我们用它作为限制的依据,也就是说,我们是针对单个 IP 地址进行速率限制。
  • zone=mylimit:10m: 这里我们定义了一个名为 mylimit 的共享内存区域,大小为 10MB。这个内存区域用来存放每个 IP 地址的访问记录。10MB 的空间大概可以存储 16 万个 IP 地址的状态。
  • rate=1r/s: 这是最重要的部分,定义了允许的请求速率。1r/s 表示每秒只允许 1 个请求。你也可以设置为 30r/m,表示每分钟允许 30 个请求。

limit_req 指令的应用

定义好了规则区域,我们就要在具体的地方把它用起来。比如,我们想对网站的登录接口 /login 进行速率限制:

server {
    # ... 其他配置 ...

    location /login {
        limit_req zone=mylimit;
        # ... 其他配置,比如 proxy_pass ...
    }
}

这样一来,当有用户访问 /login 接口时,Nginx 就会检查这个用户的 IP,并根据 mylimit 区域定义的规则(每秒 1 个请求)来处理。如果一个 IP 在 1 秒内连续发起了两个请求,那么第二个请求就会被 Nginx 拒绝,通常会返回一个 503 Service Unavailable 的错误。

进阶玩法:应对突发流量的 burst

上面的配置虽然简单有效,但在实际场景中可能会有点“不近人情”。比如,一个用户在打开网页时,浏览器可能会同时发出好几个请求来加载页面上的 CSS、JS 和图片等资源。如果我们的速率限制太严格,这些正常的请求就可能被误伤。

为了解决这个问题,我们可以引入 burst (突发) 参数。

server {
    location /login {
        limit_req zone=mylimit burst=5;
    }
}

这里的 burst=5 是什么意思呢?它告诉 Nginx,在 mylimit 区域定义的速率基础上,允许客户端额外“突发”5 个请求。

当一个 IP 的请求速率超过了 1r/s 时,Nginx 不会马上拒绝,而是会将超出的请求先放到一个大小为 5 的队列(桶)里。然后,还是按照 1r/s 的速率从队列里取出请求来处理。只有当队列也满了之后,新的请求才会被拒绝。

这样一来,我们既能限制住总体的请求速率,又能应对短时间内的突发流量,用户体验会好很多。

极致体验:nodelay 让排队不再等待

使用了 burst 之后,虽然请求不会被立即拒绝了,但它们会在队列里“排队”等待处理,这会导致请求的响应时间变长,用户可能会感觉网站变慢了。

为了解决这个问题,我们还有一个“神器”——nodelay 参数。

server {
    location /login {
        limit_req zone=mylimit burst=5 nodelay;
    }
}

加上 nodelay 之后,即使请求超过了速率限制,只要队列(burst 定义的)里还有位置,Nginx 就会立即处理这个请求,而不是让它排队。当然,这个请求还是会占据队列里的一个“坑位”,并且在一定时间后才会释放。这样既保证了低延迟,也达到了速率限制的目的。

强烈建议:在大多数场景下,将 burstnodelay 配合使用,是实现速率限制的最佳实践。

实战案例

光说不练假把式,我们来看两个实际的案例。

案例一:保护登录接口,防止密码爆破

登录接口是暴力破解攻击的重灾区。攻击者会用程序不停地尝试各种用户名和密码组合。通过速率限制,我们可以大大增加攻击的成本和时间。

配置如下:

http {
    # 定义一个专门用于登录接口的速率限制区域
    # 限制每个 IP 每秒只能请求 1 次
    limit_req_zone $binary_remote_addr zone=loginlimit:10m rate=1r/s;

    server {
        listen 80;
        server_name yourdomain.com;

        location /login {
            # 应用速率限制规则
            # 允许 5 个突发请求,并且不延迟处理
            limit_req zone=loginlimit burst=5 nodelay;

            # 这里是你的后端服务地址
            proxy_pass http://backend_server;
        }

        # 其他 location 配置...
    }
}

解析:

这个配置专门为 /login 接口创建了一个名为 loginlimit 的规则。它限制了每个 IP 地址每秒只能尝试登录 1 次,但允许短时间内有 5 次的突发请求,以应对正常的网络波动或用户误操作。对于恶意的爆破程序来说,这个速率就非常低效了。

案例二:保护 API 接口,防止恶意调用

如果你的网站对外提供了 API 服务,那么速率限制就更加重要了。它可以防止某些用户滥用你的 API,保证资源的公平分配。

配置如下:

http {
    # 定义一个用于 API 的速率限制区域
    # 限制每个 IP 每分钟只能请求 60 次
    limit_req_zone $binary_remote_addr zone=apilimit:10m rate=60r/m;

    server {
        listen 80;
        server_name api.yourdomain.com;

        location /v1/ {
            # 对所有 /v1/ 下的 API 接口应用速率限制
            limit_req zone=apilimit burst=20 nodelay;

            # 你的 API 后端服务
            proxy_pass http://api_backend;
        }
    }
}

解析:

这个配置为所有 /v1/ 路径下的 API 接口设置了速率限制。rate=60r/m(每分钟 60 个请求)相比于登录接口要宽松一些,更符合 API 的使用场景。burst=20 也为客户端应用提供了一定的缓冲空间。

总结

好了,关于 Nginx 的速率限制,我们就聊到这里。回顾一下重点:

  • 为什么需要? 防止恶意攻击(如 DDoS、密码爆破),保护后端服务。
  • 核心指令? limit_req_zone (定义规则) 和 limit_req (应用规则)。
  • 关键参数? rate (速率)、burst (突发) 和 nodelay (无延迟)。
  • 最佳实践? burstnodelay 一起使用,效果更佳!

Nginx 的速率限制功能非常强大且灵活,上面的介绍只是冰山一角。但掌握了这些核心知识,你已经可以解决大部分常见的速率限制问题了。赶紧动手试试,给你的网站加上这把“安全锁”吧!


  目录