一、为什么需要请求限流

想象一下,你开了一家网红奶茶店,突然有一天因为某个明星的推荐,顾客蜂拥而至。如果不控制人流,店员忙不过来,顾客等太久会走,甚至可能因为拥挤发生意外。服务器也是一样——当大量请求瞬间涌来时,如果没有限流机制,轻则响应变慢,重则直接崩溃。

Nginx 作为高性能的 Web 服务器和反向代理,提供了 limit_reqlimit_conn 两个模块,能有效控制请求速率和连接数,避免服务器被突发流量冲垮。

二、limit_req:限制请求速率

limit_req 的核心思想是“漏桶算法”——想象一个底部有孔的桶,无论倒入多少水(请求),漏出的速度(处理速率)是恒定的。如果水太多,桶(缓冲区)满了就会溢出(拒绝请求)。

基础配置示例

http {
    # 定义一个名为 "one" 的限流规则,速率 10 请求/秒,缓冲区 5 个请求
    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

    server {
        location /api/ {
            # 应用限流规则 "one",突发请求超过 5 个时直接拒绝
            limit_req zone=one burst=5 nodelay;
            proxy_pass http://backend;
        }
    }
}

关键参数解释:

  • limit_req_zone:定义共享内存区(zone=one:10m 表示 10MB 内存),$binary_remote_addr 按客户端 IP 限流。
  • rate=10r/s:允许每秒 10 个请求。
  • burst=5:允许瞬时超出 5 个请求(缓冲队列)。
  • nodelay:不延迟处理缓冲的请求,直接尽快处理。

高级场景:多级限流

如果某些接口特别重要,可以分层限流:

http {
    limit_req_zone $binary_remote_addr zone=low:10m rate=20r/s;
    limit_req_zone $binary_remote_addr zone=high:10m rate=5r/s;

    server {
        location /api/common/ {
            limit_req zone=low burst=10;
            proxy_pass http://backend;
        }

        location /api/vip/ {
            limit_req zone=high burst=2;
            proxy_pass http://backend;
        }
    }
}

三、limit_conn:限制并发连接数

limit_conn 控制的是同一时刻的活跃连接数。比如你的服务器最多同时处理 1000 个连接,超过的直接拒绝。

基础配置示例

http {
    # 定义名为 "addr" 的连接数限制区,每个 IP 最多 10 个连接
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    server {
        location /download/ {
            # 每个 IP 限制 2 个并发连接
            limit_conn addr 2;
            limit_rate 100k;  # 限速 100KB/s
            alias /data/files/;
        }
    }
}

关键参数解释:

  • limit_conn_zone:类似 limit_req_zone,但统计的是连接数。
  • limit_conn addr 2:每个 IP 最多 2 个并发连接。
  • limit_rate:可搭配限速,避免单个连接占满带宽。

四、实际应用与注意事项

1. 应用场景

  • 防御 CC 攻击:限制单个 IP 的请求速率。
  • 保护登录接口:防止暴力破解密码。
  • 下载限速:避免带宽被单个用户耗尽。

2. 技术优缺点

优点:

  • 配置简单,无需修改业务代码。
  • 高性能,基于 Nginx 的异步事件驱动模型。

缺点:

  • 分布式环境下需结合 Redis 等外部存储(Nginx 原生不支持)。
  • 精确度不如令牌桶算法(如 ngx_http_limit_req_module 的漏桶算法会有误差)。

3. 注意事项

  • 内存分配zone 的大小需根据预期 IP 数量调整(1MB 约存 1.6 万 IP)。
  • 日志监控:被拒绝的请求会返回 503,建议监控日志调整阈值。
  • 白名单设置:内网 IP 或爬虫可能需要豁免限流:
geo $limit {
    default 1;
    192.168.0.0/24 0;  # 内网不限流
}

map $limit $limit_key {
    0 "";          # 不限流
    1 $binary_remote_addr;
}

limit_req_zone $limit_key zone=api:10m rate=10r/s;

五、总结

Nginx 的 limit_reqlimit_conn 是服务稳定的“守门人”,能有效避免突发流量导致的雪崩效应。配置时需结合实际业务调整速率和缓冲区大小,并通过监控持续优化。对于分布式系统,可考虑结合 Lua + Redis 或 OpenResty 实现更灵活的限流策略。