Nginx可以通过多种方式实现分布式限流,以下是几种常见的实现方法:
这是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原子操作
需要安装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;
}
}
}
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
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;
}
}
}
对于大规模分布式系统,可以考虑:
令牌桶算法实现:
滑动窗口算法:
结合Nginx和API网关:
以上方案可以根据实际业务需求和系统规模进行选择和组合。