redis-ratelimit: 限制多个 NGINX 实例之间的请求处理速率,后端使用 Redis
安装
如果您尚未设置 RPM 仓库订阅,请 注册。然后您可以继续以下步骤。
CentOS/RHEL 7 或 Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-redis-ratelimit
CentOS/RHEL 8+、Fedora Linux、Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-redis-ratelimit
要在 NGINX 中使用此 Lua 库,请确保已安装 nginx-module-lua。
本文档描述了 lua-resty-redis-ratelimit v0.3,发布于 2019 年 10 月 03 日。
此 Lua 库是 ngx_lua 的请求处理速率限制模块:
http://wiki.nginx.org/HttpLuaModule
它用于限制多个 NGINX 实例之间每个定义键的请求处理速率。限制是通过 "漏桶" 方法实现的。

此模块使用 Redis (>= 2.6.0) 作为后端存储,因此您还需要 lua-resty-redis 库与之配合使用。
注意: 如果您不使用 duration 功能,并且传入流量是 均匀分布 的,建议使用模块 resty.limit.req 以避免不必要的网络延迟。
概述
server {
listen 9090;
location /t {
access_by_lua_block {
local ratelimit = require "resty.redis.ratelimit"
local lim, err = ratelimit.new("one", "2r/s", 0, 2)
if not lim then
ngx.log(ngx.ERR,
"无法实例化 resty.redis.ratelimit 对象: ", err)
return ngx.exit(500)
end
-- 注意:以下调用必须是每个请求。
-- local redis = require "resty.redis"
-- local red = redis:new()
-- red:set_timeout(1000)
-- local ok, err = red:connect("127.0.0.1", 6379)
-- if not ok then
-- ngx.log(ngx.ERR, "连接 Redis 失败: ", err)
-- return ngx.exit(500)
-- end
local red = { host = "127.0.0.1", port = 6379, timeout = 1 }
local key = ngx.var.binary_remote_addr
local delay, err = lim:incoming(key, red)
if not delay then
if err == "rejected" then
return ngx.exit(503)
end
ngx.log(ngx.ERR, "请求限制失败: ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
-- 第二个返回值表示指定键每秒的超出请求数量。
local excess = err
ngx.sleep(delay)
end
'}
echo Logged in;
}
}
方法
new
语法: obj, err = class.new(zone, rate, burst, duration)
实例化该类的对象。类值由调用 require "resty.redis.ratelimit" 返回。
此方法接受以下参数:
zone:设置命名空间,特别是我们使用<zone>:<key>字符串作为 Redis 中的唯一状态标识符。rate:速率以每秒请求数 (r/s) 指定。如果希望的速率少于每秒一个请求,则以每分钟请求数 (r/m) 指定。例如,每秒半个请求为 30r/m。burst:定义可以超出 zone 指定速率的请求数量,默认为 0。duration:在恢复到正常状态之前的时间延迟(以秒为单位),在此期间,请求始终被rejected,默认为 0。
如果失败,此方法返回 nil 和描述错误的字符串。
incoming
语法: delay, err = obj:incoming(key, redis)
触发新的请求到达事件,并计算当前请求在指定键上所需的延迟(如果有的话),或者用户是否应该立即拒绝它。
此方法接受以下参数:
key:键是指定变量的任何非空值。redis:设置 Redis 配置,包括host、port、timeout等(见下文);您也可以直接设置连接的 Redisobject。
- redis.host:默认值 127.0.0.1。
- redis.port:默认值 80。
- redis.timeout:默认值 1s。
- redis.pass:请求在受密码保护的 Redis 服务器上的身份验证。
- redis.dbid:选择 Redis 逻辑数据库。
返回值取决于以下情况:
- 如果请求未超过 new 方法中指定的
rate值,则此方法返回0作为延迟和当前时间的(零)超出请求数量。 - 如果请求超过了 new 方法中指定的
rate限制,但未超过rate+burst值,则此方法返回当前请求的适当延迟(以秒为单位),以使其仍符合rate阈值,就好像稍后而不是现在到达。第二个返回值指示此时每秒的超出请求数量(包括当前请求)。 - 如果请求超过了
rate+burst限制,则此方法返回nil和错误字符串"rejected"。 - 如果发生错误,则此方法返回
nil和描述错误的字符串。例如,"failed to create redis - connection refused"。
此方法本身不会休眠。它仅在必要时返回延迟,并要求调用者稍后调用 ngx.sleep 方法进行休眠。
set_burst
语法: obj:set_burst(burst)
覆盖 new 方法中指定的 burst 阈值。
另请参阅
- 使用 NGINX 进行速率限制: https://www.nginx.com/blog/rate-limiting-nginx/
- ngx_lua 模块: https://github.com/openresty/lua-nginx-module
- OpenResty: https://openresty.org/
GitHub
您可以在 nginx-module-redis-ratelimit 的 GitHub 仓库 中找到此模块的其他配置提示和文档。