redis-ratelimit: Limitar la tasa de procesamiento de solicitudes entre múltiples instancias de NGINX respaldadas por Redis
Instalación
Si no has configurado la suscripción al repositorio RPM, regístrate. Luego puedes proceder con los siguientes pasos.
CentOS/RHEL 7 o 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
Para usar esta biblioteca Lua con NGINX, asegúrate de que nginx-module-lua esté instalado.
Este documento describe lua-resty-redis-ratelimit v0.3 lanzado el 03 de octubre de 2019.
Esta biblioteca lua es un módulo de límite de tasa de procesamiento de solicitudes para ngx_lua:
http://wiki.nginx.org/HttpLuaModule
Se utiliza para limitar la tasa de procesamiento de solicitudes por una clave definida entre múltiples instancias de NGINX. La limitación se realiza utilizando el método de "cubeta con fugas".

Este módulo utiliza Redis (>= 2.6.0) como almacenamiento backend, por lo que también necesitas la biblioteca lua-resty-redis para trabajar con ella.
AVISO: Si no utilizas la función duration y el tráfico entrante está distribuido uniformemente, se recomienda utilizar el módulo resty.limit.req para evitar retrasos innecesarios en la red.
Sinopsis
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,
"falló al instanciar un objeto resty.redis.ratelimit: ", err)
return ngx.exit(500)
end
-- AVISO: la siguiente llamada debe ser por solicitud.
-- 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, "falló al conectar con 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, "falló al limitar la solicitud: ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
-- el 2º valor de retorno contiene el número de solicitudes excesivas
-- por segundo para la clave especificada.
local excess = err
ngx.sleep(delay)
end
'}
echo Logged in;
}
}
Métodos
new
sintaxis: obj, err = class.new(zone, rate, burst, duration)
Instancia un objeto de esta clase. El valor de la clase es devuelto por la llamada require resty.redis.ratelimit.
Este método toma los siguientes argumentos:
zone: Establece el espacio de nombres, en particular, utilizamos la cadena<zone>:<key>como un identificador de estado único dentro de Redis.rate: La tasa se especifica en solicitudes por segundo (r/s). Si se desea una tasa de menos de una solicitud por segundo, se especifica en solicitudes por minuto (r/m). Por ejemplo, media solicitud por segundo es 30r/m.burst: Define cuántas solicitudes pueden hacerse en exceso de la tasa especificada por la zona, por defecto 0.duration: El tiempo de retraso (en segundos) antes de volver al estado normal, durante este período, la solicitud es siemprerejected, por defecto 0.
En caso de fallo, este método devuelve nil y una cadena que describe el error.
incoming
sintaxis: delay, err = obj:incoming(key, redis)
Dispara un nuevo evento de solicitud entrante y calcula el retraso necesario (si lo hay) para la solicitud actual sobre la clave especificada o si el usuario debe rechazarla inmediatamente.
Este método acepta los siguientes argumentos:
key: La clave es cualquier valor no vacío de la variable especificada.redis: Establece la configuración de Redis,host,port,timeout, etc. (ver abajo); En lugar de la configuración específica de Redis, también puedes establecer elobjectde Redis conectado directamente.
- redis.host: Por defecto 127.0.0.1.
- redis.port: Por defecto 80.
- redis.timeout: Por defecto 1s.
- redis.pass: Solicitud de autenticación en un servidor Redis protegido por contraseña.
- redis.dbid: Selecciona la base de datos lógica de Redis.
Los valores de retorno dependen de los siguientes casos:
- Si la solicitud no excede el valor de
rateespecificado en el método new, entonces este método devuelve0como el retraso y el (cero) número de solicitudes excesivas por segundo en el momento actual. - Si la solicitud excede el límite de
rateespecificado en el método new pero no el valor derate+burst, entonces este método devuelve un retraso adecuado (en segundos) para la solicitud actual de modo que aún se ajuste al umbral deratecomo si llegara un poco más tarde en lugar de ahora. El 2º valor de retorno indica el número de solicitudes excesivas por segundo en este punto (incluyendo la solicitud actual). - Si la solicitud excede el límite de
rate+burst, entonces este método devuelvenily la cadena de error"rejected". - Si ocurrió un error, entonces este método devuelve
nily una cadena que describe el error. Como por ejemplo"falló al crear redis - conexión rechazada".
Este método nunca duerme por sí mismo. Simplemente devuelve un retraso si es necesario y requiere que el llamador invoque más tarde el método ngx.sleep para dormir.
set_burst
sintaxis: obj:set_burst(burst)
Sobrescribe el umbral de burst como se especifica en el método new.
Ver También
- Limitación de Tasa con NGINX: https://www.nginx.com/blog/rate-limiting-nginx/
- el módulo ngx_lua: https://github.com/openresty/lua-nginx-module
- OpenResty: https://openresty.org/
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-redis-ratelimit.