Nginx 限流 ngx_http_limit_req_module

FreeGuideOnline 最新 2026-07-14

Nginx 限流模块 ngx_http_limit_req_module 完全指南

在高并发场景下,保护后端服务不被突发流量冲垮是架构设计中的重要一环。Nginx 通过 ngx_http_limit_req_module 模块提供了基于**漏桶算法(Leaky Bucket)**的请求频率限制功能,能够对单个 IP 或自定义键的请求速率进行精确控制。本教程将从零开始,带你掌握该模块的配置与最佳实践。

模块简介与工作原理

ngx_http_limit_req_module 默认编译进 Nginx,用于限制请求处理速率,而非连接数。其核心是漏桶算法

  1. 请求以任意速率到达,首先进入一个“桶”(共享内存区域)。
  2. 桶以固定速率“漏水”(处理请求),多余请求会被暂存或直接拒绝。
  3. 如果桶已满,新请求将触发限制。

该模块通过两个核心指令协同工作:limit_req_zone 定义共享内存和速率参数,limit_req 在具体上下文中启用限制。

注意:该模块仅作用于 HTTP 请求处理阶段,对 TCP/UDP 层的流量无效(需使用 stream 模块)。


核心配置指令详解

1. limit_req_zone —— 定义限流共享内存区域

语法

limit_req_zone key zone=name:size rate=rate;

上下文http

  • key:限流依据,通常是客户端 IP($binary_remote_addr),也可以是其它变量组合。
  • zone:共享内存名称与大小(如 mylimit:10m),10MB 大约可存储 16 万个 IP 状态。
  • rate:请求速率,格式为 r/sr/m(如 10r/s 表示每秒 10 个请求)。

示例:

http {
    limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
}

2. limit_req —— 启用限流规则

语法

limit_req zone=name [burst=number] [nodelay | delay=number];

上下文http, server, location

  • zone:引用 limit_req_zone 定义的区域名称。
  • burst:允许的突发请求数,超出平均速率但未超过 rate+burst 的请求会被排队延迟处理。
  • nodelay:与 burst 配合,让 burst 内的请求立即处理,不延迟;超出 burst 的直接拒绝。
  • delay(商业版):更精细的延迟控制。开源版本不适用,此处不展开。

典型用法:

location /api/ {
    limit_req zone=perip burst=10 nodelay;
}

3. limit_req_log_level —— 设置日志级别

语法

limit_req_log_level info | notice | warn | error;

默认error
上下文http, server, location

当请求被限流时,Nginx 会记录一条错误日志。可设置为 warninfo 以减少日志干扰。

4. limit_req_status —— 自定义拒绝状态码

语法

limit_req_status code;

默认503
上下文http, server, location

当请求被拒绝时返回的 HTTP 状态码。可改为 429 Too Many Requests 以符合 RESTful 惯例:

limit_req_status 429;

配置实战:从基础到进阶

场景一:简单的固定速率限流

全局限制每个 IP 每秒最多 2 个请求:

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s;

    server {
        location / {
            limit_req zone=one;
            proxy_pass http://backend;
        }
    }
}

效果:超过 2r/s 的请求立返 503。

场景二:允许突发流量(burst + nodelay)

正常速率 1r/s,但允许瞬时 5 个突发请求,且不延迟处理:

http {
    limit_req_zone $binary_remote_addr zone=two:10m rate=1r/s;

    server {
        location / {
            limit_req zone=two burst=5 nodelay;
        }
    }
}
  • 若客户端瞬时发送 6 个请求,前 6 个中,1 个按固定速率处理,剩下 5 个消耗突发额度立刻处理(因为 nodelay),超出 5 个的才拒绝。
  • 若去掉 nodelay,则第 2~6 个请求会被排队,按固定速率依次处理,用户感知为延迟。

场景三:多条件精细限流

对特定 URI 设置不同速率:

http {
    limit_req_zone $binary_remote_addr zone=static:10m rate=30r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/m;

    server {
        location /static/ {
            limit_req zone=static burst=20 nodelay;
        }

        location /login/ {
            limit_req zone=login burst=2 nodelay;
            limit_req_status 429;
        }
    }
}

静态资源允许较高频率,登录接口严格限制,有效防止暴力破解。

场景四:基于其他键的限流

除了 IP,还可以对 $http_apikey 或者 $server_name 限流。例如按 API 密钥限流:

limit_req_zone $http_apikey zone=apikey:10m rate=100r/s;

server {
    location /api/ {
        # 从查询参数或头部获取 api_key,这里假设头部
        set $api_key $http_x_api_key;
        limit_req zone=apikey;
    }
}

注意:自定义变量需要在区域声明中直接使用,若需要在 limit_req_zone 中使用组合变量,需确保变量在请求处理早期可达。


测试与验证

使用压力测试工具 ab(ApacheBench)或 wrk 验证配置效果。

示例:假设单 IP 限速 2r/s,用 ab 发送 10 个并发请求:

ab -n 10 -c 10 http://example.com/api/test

查看返回状态码,非 2xx/3xx 的数量即为被拒绝请求。同时观察 Nginx 错误日志(默认 /var/log/nginx/error.log)中是否有 limiting requests 的记录。

注意事项:测试时请使用真实客户端 IP,确保没有被代理或前端设备替换。若 Nginx 位于反向代理之后,应使用 $http_x_forwarded_for$realip_remote_addr(需配合 realip 模块)来获取真实 IP。


常见问题与最佳实践

  1. 共享内存不足?
    zone=name:size,若内存耗尽,所有请求将被限流。预估容量:每个键占用约 64 字节,10MB 约可存 160,000 个键。监控内存使用,适当扩大。

  2. burst 与 nodelay 如何搭配?
    对实时性要求高的 API,建议使用 nodelay,让用户在突发额度内无感知;对可容忍延迟的下载类服务,可仅用 burst 平滑处理。

  3. 如何返回更友好的错误信息?

    limit_req_status 429;
    error_page 429 = @toomany;
    location @toomany {
        default_type application/json;
        return 429 '{"error":"too many requests"}';
    }
    
  4. 不要将 $remote_addr 直接作为 key
    推荐使用 $binary_remote_addr,它占用固定 4 字节(IPv4)或 16 字节(IPv6),比 $remote_addr(字符串)节省内存并加快哈希速度。

  5. 与 limit_conn 的区别
    limit_req 控制请求速率,limit_conn 控制并发连接数。两者可组合使用,形成双重防护。

  6. 白名单机制
    对内部 IP 或特定 UA 放行,可通过 if 指令或 geo 映射变量实现,然后将该变量作为 key 条件限制值为空时跳过限制。
    示例:

    geo $limit {
        default 1;
        10.0.0.0/8 0;
    }
    map $limit $limit_key {
        0      "";
        1      $binary_remote_addr;
    }
    limit_req_zone $limit_key zone=white:10m rate=10r/s;
    

    $limit_key 为空时,limit_req 不生效。


总结

ngx_http_limit_req_module 是 Nginx 防御突发流量、保护后端服务的利器。通过合理设置速率、突发缓冲和自定义键,你能实现从简单 IP 限流到复杂业务逻辑的流量整形。记住:先估算正常流量,再设置略高于峰值的限制,配合 burst 吸收突发,用 nodelay 提升用户体验,最后通过日志和监控持续迭代参数。

现在,打开你的 nginx.conf,尝试为关键接口加上一道限流保护吧。