全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-20 9 分钟 ✍️ juanwangdev

流量控制与限流

Nginx 通过连接数限制、请求速率限制实现流量控制,保护后端服务免受突发流量冲击。

连接数限制

limit_conn 模块

nginx
http {
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_conn_zone $server_name zone=perserver:10m;

    server {
        location / {
            limit_conn perip 10;      # 每 IP 10 个并发连接
            limit_conn perserver 1000; # 总连接数 1000
            limit_conn_status 503;     # 超限返回状态码
            limit_conn_log_level warn; # 超限日志级别
        }
    }
}

共享内存计算

zone 大小可存储 IP 数
1m~8,000
10m~80,000
100m~800,000

每个 IP 状态占用约 128 字节(32 位 IP)或 256 字节(128 位 IPv6)。

请求速率限制

limit_req 模块

nginx
http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

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

算法参数

参数说明
rate平均请求速率(r/s 或 r/m)
burst突发队列大小
nodelay立即处理突发请求,不排队
delay延迟处理的阈值

漏桶算法

nginx
请求到达速率: 20r/s
配置速率:     10r/s
burst:        20

时间轴:
0s:   20 个请求到达
      → 10 个立即处理(符合 rate)
      → 10 个进入 burst 队列
      → 后续每秒处理 10 个 + 队列消费

无 nodelay: 排队等待
有 nodelay: 立即处理(占用 burst)

多级别限流

nginx
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=5r/s;
limit_req_zone $server_name zone=server_limit:10m rate=100r/s;

location /api/ {
    limit_req zone=ip_limit burst=10 nodelay;
    limit_req zone=server_limit burst=200;
}

突发流量处理

burst 与 delay

nginx
# 允许突发 20 个请求,立即处理
limit_req zone=api burst=20 nodelay;

# 允许突发 20 个请求,前 5 个立即,剩余排队
limit_req zone=api burst=20 delay=5;

限流状态码

lua
# 自定义限流响应
limit_req_status 429;
limit_req_log_level info;

# 自定义错误页
error_page 429 /429.json;
location = /429.json {
    default_type application/json;
    return 429 '{"error": "rate limit exceeded", "retry_after": 1}';
}

分布式限流

OpenResty + Redis

lua
-- redis_limit.lua
local redis = require("resty.redis")

local function check_rate_limit(key, limit, window)
    local red = redis:new()
    red:connect("127.0.0.1", 6379)

    local count = red:incr(key)
    if count == 1 then
        red:expire(key, window)
    end

    if count > limit then
        return false, count
    end
    return true, count
end

-- 使用
local ok, count = check_rate_limit("rate:" .. ngx.var.binary_remote_addr, 100, 60)
if not ok then
    ngx.status = 429
    ngx.say('{"error": "rate limit exceeded", "count": ' .. count .. '}')
    return ngx.exit(429)
end

令牌桶算法

nginx
-- token_bucket.lua
local function token_bucket(key, capacity, refill_rate)
    local redis = require("resty.redis")
    local red = redis:new()
    red:connect("127.0.0.1", 6379)

    local now = ngx.time()
    local data = red:hmget(key, "tokens", "last_refill")

    local tokens = tonumber(data[1]) or capacity
    local last_refill = tonumber(data[2]) or now

    -- 补充令牌
    local elapsed = now - last_refill
    tokens = math.min(capacity, tokens + elapsed * refill_rate)

    if tokens >= 1 then
        tokens = tokens - 1
        red:hmset(key, "tokens", tokens, "last_refill", now)
        red:expire(key, 3600)
        return true
    end

    return false
end

限流策略

API 分级限流

nginx
# 不同 API 不同限流
limit_req_zone $binary_remote_addr zone=read_api:10m rate=50r/s;
limit_req_zone $binary_remote_addr zone=write_api:10m rate=10r/s;

location /api/read/ {
    limit_req zone=read_api burst=100 nodelay;
}

location /api/write/ {
    limit_req zone=write_api burst=20 nodelay;
}

白名单配置

text
geo $white_list {
    default     0;
    10.0.0.0/8  1;
    172.16.0.0/12 1;
    192.168.0.0/16 1;
}

map $white_list $limit_key {
    0   $binary_remote_addr;
    1   "";  # 白名单不限流
}

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

要点总结

  • limit_conn 限制并发连接数,limit_req 限制请求速率(漏桶算法)
  • burst 控制突发队列,nodelay 立即处理,delay 延迟处理
  • 共享内存 zone 大小决定可存储的 IP 状态数量(1m ≈ 8000 IP)
  • OpenResty + Redis 实现分布式限流,支持跨 Nginx 节点统一限流
  • 令牌桶算法比漏桶算法更灵活,支持突发流量平滑处理
  • 通过 geo/map 模块配置白名单,避免内部服务被限流

📝 发现内容有误?点击此处直接编辑

← 上一篇 健康检查机制
下一篇 → 灰度发布策略
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库