插件窝 干货文章 如何使用nginx实现分布式限流

如何使用nginx实现分布式限流

limit 分布式 Redis Nginx 483    来源:    2025-04-26

使用Nginx实现分布式限流方案

Nginx可以通过多种方式实现分布式限流,以下是几种常见的实现方法:

1. 基于Nginx的limit_req模块

这是Nginx内置的限流模块,适合单机限流,可以通过分布式存储扩展为分布式限流。

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

    server {
        location /api/ {
            limit_req zone=api_limit burst=20 nodelay;
            proxy_pass http://backend;
        }
    }
}

分布式扩展方案: - 使用Redis存储限流计数 - 通过Lua脚本实现Redis原子操作

2. 使用Nginx+Lua+Redis实现分布式限流

需要安装OpenResty或Nginx+Lua模块。

http {
    lua_shared_dict my_limit_req_store 100m;

    server {
        location /api/ {
            access_by_lua_block {
                local limit_req = require "resty.limit.req"
                local lim, err = limit_req.new("my_limit_req_store", 10, 20)
                if not lim then
                    ngx.exit(500)
                end

                local key = ngx.var.binary_remote_addr
                local delay, err = lim:incoming(key, true)
                if not delay then
                    if err == "rejected" then
                        return ngx.exit(503)
                    end
                    ngx.exit(500)
                end
            }

            proxy_pass http://backend;
        }
    }
}

3. 使用Nginx+Lua+Redis集群实现

local redis = require "resty.redis"
local red = redis:new()

red:set_timeout(1000) -- 1秒超时

local ok, err = red:connect("redis-cluster-ip", 6379)
if not ok then
    ngx.log(ngx.ERR, "failed to connect to redis: ", err)
    return ngx.exit(500)
end

-- 使用Redis的INCR和EXPIRE实现限流
local key = "rate_limit:" .. ngx.var.binary_remote_addr
local limit = 10 -- 每秒10次
local current = tonumber(red:get(key)) or 0

if current + 1 > limit then
    red:close()
    return ngx.exit(503)
else
    red:incr(key)
    if current == 0 then
        red:expire(key, 1) -- 1秒过期
    end
    red:close()
end

4. 使用Nginx的limit_req模块结合一致性哈希

http {
    upstream backend {
        hash $remote_addr consistent;
        server backend1.example.com;
        server backend2.example.com;
    }

    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    server {
        location /api/ {
            limit_req zone=api_limit burst=20 nodelay;
            proxy_pass http://backend;
        }
    }
}

5. 高级分布式限流方案

对于大规模分布式系统,可以考虑:

  1. 令牌桶算法实现

    • 使用Redis + Lua实现分布式令牌桶
    • 每个Nginx节点从中央Redis获取令牌
  2. 滑动窗口算法

    • 使用Redis的ZSET实现滑动窗口计数
    • 更精确的控制单位时间内的请求量
  3. 结合Nginx和API网关

    • 在Nginx前置层做粗粒度限流
    • 在API网关做细粒度限流

注意事项

  1. 性能考虑:Redis操作会增加延迟,确保Redis集群高性能
  2. 容错处理:Redis不可用时要有降级方案
  3. 限流粒度:可按IP、用户ID、API端点等不同维度限流
  4. 监控报警:实时监控限流触发情况
  5. 动态配置:支持热更新限流规则

以上方案可以根据实际业务需求和系统规模进行选择和组合。