Nginx配置限流

Nginx 配置限流:基于漏桶算法的流量控制策略

在高并发场景中,突发流量可能导致服务器过载、响应延迟甚至崩溃。Nginx 提供了基于漏桶算法的限流功能,通过limit_req_zonelimit_req指令控制请求速率,保护后端服务稳定。本文详细讲解 Nginx 限流的配置方法、核心参数及实战场景,帮助合理管控流量。

限流核心原理:漏桶算法

Nginx 限流基于漏桶算法(Leaky Bucket),其核心逻辑如下:

  • 想象一个 “漏桶”,请求如同水流注入桶中,桶底有一个固定速率的 “漏洞”;
  • 若请求注入速度超过漏洞的漏水速度,多余的水(请求)会溢出(被拒绝);
  • 通过控制漏洞的速率(rate)和桶的容量(burst),实现请求的匀速处理,避免瞬间压力。

基础配置:limit_req_zonelimit_req

Nginx 限流需两步配置:先在http块定义限流规则(limit_req_zone),再在location/server块应用规则(limit_req)。

定义限流区域(limit_req_zone

http {
    # 定义限流规则
    # $binary_remote_addr:以客户端IP的二进制形式作为key(节省内存)
    # zone=mylimit:1m:创建名为mylimit的共享内存区域,大小1M(约可存储16000个IP状态)
    # rate=1r/m:限制速率为每分钟1个请求(r/s表示每秒,r/m表示每分钟)
    limit_req_zone $binary_remote_addr zone=mylimit:1m rate=1r/m;
}
  • 参数说明:
    • key:用于区分请求的标识(如$binary_remote_addr按 IP 限流,$request_uri按 URL 限流);
    • zone:定义共享内存区域(多 Worker 进程共享状态,确保计数准确);
    • rate:请求速率上限(格式为N r/sN r/m,如10r/s表示每秒最多 10 个请求)。

应用限流规则(limit_req

server {
    listen 80;
    server_name example.com;

    location /api {
        # 应用名为mylimit的限流规则
        # burst=10:允许10个请求排队等待
        # nodelay:队列中的请求不延迟,立即处理(超出burst的请求被拒绝)
        limit_req zone=mylimit burst=10 nodelay;
        
        # 转发到后端服务
        proxy_pass http://backend;
    }
}

核心参数详解

1. burst:排队缓冲大小

burst定义允许临时超出rate的请求数量(即 “漏桶” 的容量)。例如:

  • rate=1r/sburst=10,则每秒最多处理 1 个请求,额外 10 个请求会进入队列等待;
  • 队列按rate速率依次处理,若队列满(超过 10 个),新请求会被拒绝(返回 503)。

示例

# 速率1r/s,允许10个请求排队,排队请求不延迟
limit_req zone=mylimit burst=10 nodelay;

2. nodelaydelay:控制排队延迟

  • nodelay:队列中的请求不等待,立即处理(但总速率不超过rate)。适合允许突发流量但需控制并发的场景;
  • delay=N:队列中前N个请求立即处理,从第N+1个请求开始按rate延迟处理。用于精确控制并发数。

示例

# 前5个请求立即处理,第6个及以后按rate延迟处理
limit_req zone=mylimit burst=10 delay=5;

3. limit_req_log_levellimit_req_status

  • limit_req_log_level:指定限流时的日志级别(默认error),如notice
  • limit_req_status:指定被限流的请求返回的 HTTP 状态码(默认 503)。

示例

location /api {
    limit_req zone=mylimit burst=10 nodelay;
    limit_req_log_level notice;  # 限流日志记为notice级别
    limit_req_status 429;        # 限流时返回429(Too Many Requests)
}

实战场景:不同维度的限流配置

1. 按 IP 限流(最常用)

限制单个 IP 的请求速率,防止单 IP 恶意攻击:

http {
    # 按IP限流,每秒最多5个请求
    limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=5r/s;
}

server {
    location /login {
        limit_req zone=ip_limit burst=20 nodelay;  # 允许20个突发请求
        proxy_pass http://backend;
    }
}

2. 按 URL 限流(保护特定接口)

限制对某一 URL 的总请求速率,避免热点接口被冲垮:

http {
    # 按URL限流,每秒最多100个请求
    limit_req_zone $request_uri zone=url_limit:20m rate=100r/s;
}

server {
    location /api/payment {  # 支付接口,需严格限流
        limit_req zone=url_limit burst=50;  # 允许50个突发请求
        proxy_pass http://payment_service;
    }
}

3. 结合if条件限流

仅对特定请求限流(如非内部 IP):

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

server {
    location / {
        # 若客户端IP不是内部网段,则应用限流
        if ($remote_addr !~* ^192\.168\.) {
            limit_req zone=external_limit burst=10 nodelay;
        }
        proxy_pass http://backend;
    }
}

注意事项与优化

  1. 共享内存大小zone的大小需根据key的数量调整(如按 IP 限流,1M 约存 16000 个 IP,10M 可存 16 万个);

  2. 避免过度限流burstrate需根据业务峰值设置(如正常峰值 100r/s,可设rate=120r/sburst=50);

  3. 配合连接数限制:限流(limit_req)控制请求速率,limit_conn控制并发连接数,二者结合更安全:

# 限制单个IP最大并发连接数为10
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn conn_limit 10;
  1. 白名单配置:对内部 IP 或信任来源关闭限流,避免影响正常业务:
# 定义白名单变量
geo $limit {
    default 1;
    192.168.0.0/24 0;  # 内部网段不限流
}

# 仅对白名单外的IP应用限流
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s if=$limit;

效果验证与日志分析

  • 验证方法:使用ab(Apache Bench)工具模拟并发请求:

    ab -n 20 -c 5 http://example.com/api  # 发送20个请求,并发5个
  • 日志查看:Nginx 日志会记录被限流的请求(默认状态码 503),可通过日志分析限流效果:

    192.168.1.100 - - [10/Jul/2025:10:00:00 +0800] "GET /api HTTP/1.1" 503 199 "-" "ApacheBench/2.3"