You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Nginx中基于并发连接数动态调整速率限制?

如何在Nginx中基于并发连接数动态调整速率限制?

嘿,这个需求挺实用的——根据服务器并发连接数动态调整速率限制,避免高并发时服务被冲垮。我来给你一步步拆解实现方案,分两种场景(按IP统计并发/全局并发),还有不同Nginx版本的兼容方案。


核心思路

要实现这个需求,我们需要结合Nginx的三个核心模块:

  1. ngx_http_limit_conn_module:用来统计并发连接数(单IP或全局)
  2. ngx_http_map_module:根据并发数的范围映射对应的速率限制值
  3. ngx_http_limit_req_module:应用动态计算出的速率限制

方案1:按单个IP的并发连接数调整速率(Nginx 1.17.6+)

如果你的Nginx版本在1.17.6及以上,支持limit_req_zonerate参数使用变量,配置会更简洁:

http {
    # 1. 统计每个IP的并发连接数,创建一个10M的存储区域
    limit_conn_zone $binary_remote_addr zone=ip_conn:10m;

    # 2. 根据并发数映射对应的速率限制
    # 区间匹配需要Nginx 1.13.10+,低版本可以用正则替代
    map $limit_conn_ip_conn $dynamic_rate {
        0-19  10r/m;  # 0-19并发 → 10请求/分钟
        20-29 9r/m;   # 20-29并发 → 9请求/分钟
        30-39 8r/m;
        40-49 7r/m;
        50-59 6r/m;
        60-69 5r/m;
        70-79 4r/m;
        80-89 3r/m;
        90-100 2r/m;  # 90-100并发 → 最低2请求/分钟
        default 2r/m; # 超过100并发也保持最低值
    }

    # 3. 定义速率限制区域,使用动态计算的速率
    limit_req_zone $binary_remote_addr zone=dynamic_limit:10m rate=$dynamic_rate;

    # 你的上游服务器配置
    upstream myservers {
        server 127.0.0.1:8081;
        server 127.0.0.1:8082;
        server 127.0.0.1:8083;
        server 127.0.0.1:8084;
    }

    server {
        listen 80; # 主监听端口,可根据你的需求修改
        server_name your-domain.com;

        # 限制单个IP的最大并发连接数为100
        limit_conn ip_conn 100;

        # 应用动态速率限制,burst=5允许5个突发请求,nodelay不排队直接处理/拒绝
        limit_req zone=dynamic_limit burst=5 nodelay;

        # 自定义429速率限制超出错误页
        error_page 429 /rate-limit-exceeded.html;
        location = /rate-limit-exceeded.html {
            root /path/to/your/error-files; # 替换成你的错误页目录
            internal; # 只允许内部跳转访问
        }

        # 转发请求到上游服务器
        location / {
            proxy_pass http://myservers;
            # 补充你的proxy配置(比如proxy_set_header等)
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }

        # 你的后端服务器配置(原来的8081等端口)
        server {
            listen 8081;
            # 后端服务的具体配置...
        }
        # 其他后端server块同理...
    }
}

方案2:按全局服务器的并发连接数调整速率

如果你的需求是基于整个服务器的总并发数(而不是单个IP),只需要修改limit_conn_zone的统计变量:

# 替换原来的limit_conn_zone,用$server_name统计全局并发
limit_conn_zone $server_name zone=global_conn:10m;

# map部分改用全局并发数变量
map $limit_conn_global_conn $dynamic_rate {
    0-19  10r/m;
    20-29 9r/m;
    # ... 其他区间和之前一致
    90-100 2r/m;
    default 2r/m;
}

兼容低版本Nginx(<1.17.6)

如果你的Nginx版本低于1.17.6,不支持rate参数用变量,那就需要创建多个速率限制区域,再通过map选择对应的区域:

http {
    limit_conn_zone $binary_remote_addr zone=ip_conn:10m;

    # 预先创建所有需要的速率限制区域
    limit_req_zone $binary_remote_addr zone=rate10:10m rate=10r/m;
    limit_req_zone $binary_remote_addr zone=rate9:10m rate=9r/m;
    limit_req_zone $binary_remote_addr zone=rate8:10m rate=8r/m;
    limit_req_zone $binary_remote_addr zone=rate7:10m rate=7r/m;
    limit_req_zone $binary_remote_addr zone=rate6:10m rate=6r/m;
    limit_req_zone $binary_remote_addr zone=rate5:10m rate=5r/m;
    limit_req_zone $binary_remote_addr zone=rate4:10m rate=4r/m;
    limit_req_zone $binary_remote_addr zone=rate3:10m rate=3r/m;
    limit_req_zone $binary_remote_addr zone=rate2:10m rate=2r/m;

    # map选择对应的速率区域
    map $limit_conn_ip_conn $rate_zone {
        0-19  rate10;
        20-29 rate9;
        30-39 rate8;
        40-49 rate7;
        50-59 rate6;
        60-69 rate5;
        70-79 rate4;
        80-89 rate3;
        90-100 rate2;
        default rate2;
    }

    upstream myservers {
        # 上游配置不变...
    }

    server {
        listen 80;
        server_name your-domain.com;

        limit_conn ip_conn 100;
        # 使用选择好的速率区域
        limit_req zone=$rate_zone burst=5 nodelay;

        # 错误页配置不变...
        location / {
            proxy_pass http://myservers;
        }
    }
}

关键注意事项

  1. 版本要求:区间匹配(0-19这种写法)需要Nginx 1.13.10+;rate用变量需要1.17.6+,低版本请用正则或多区域方案。
  2. 并发数统计:要明确是统计单IP还是全局并发,选择对应的limit_conn_zone变量。
  3. 错误处理:除了429速率限制错误,当并发超过100时会返回503错误,你可以添加error_page 503 /maintenance.html;来处理。
  4. 存储区域大小zone=xxx:10m的10M是存储区域大小,根据你的并发量调整,一般1M可以存储约16000个IP的信息。

备注:内容来源于stack exchange,提问作者Ilgar

火山引擎 最新活动