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
Чтобы использовать эту библиотеку Lua с NGINX, убедитесь, что nginx-module-lua установлен.
Этот документ описывает lua-resty-redis-ratelimit v0.3, выпущенный 3 октября 2019 года.
Эта библиотека lua является модулем ограничения скорости обработки запросов для ngx_lua:
http://wiki.nginx.org/HttpLuaModule
Она используется для ограничения скорости обработки запросов по определенному ключу между несколькими экземплярами NGINX. Ограничение осуществляется с использованием метода "leaky bucket".

Этот модуль использует 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: Определяет, сколько запросов можно сделать сверх скорости, указанной в зоне, по умолчанию 0.duration: Время задержки (в секундах) перед возвратом к нормальному состоянию, в течение этого периода запрос всегдаrejected, по умолчанию 0.
В случае ошибки этот метод возвращает nil и строку, описывающую ошибку.
incoming
синтаксис: delay, err = obj:incoming(key, redis)
Запускает новое событие входящего запроса и вычисляет необходимую задержку (если такая есть) для текущего запроса по указанному ключу или решает, следует ли немедленно его отклонить.
Этот метод принимает следующие аргументы:
key: Ключ — это любое непустое значение указанной переменной.redis: Устанавливает конфигурацию Redis,host,port,timeoutи так далее (см. ниже); Вместо конкретной конфигурации Redis вы также можете установить подключенный объект Redis напрямую.
- redis.host: По умолчанию 127.0.0.1.
- redis.port: По умолчанию 80.
- redis.timeout: По умолчанию 1s.
- redis.pass: Запрос для аутентификации на сервере Redis с защитой паролем.
- redis.dbid: Выбор логической базы данных Redis.
Возвращаемые значения зависят от следующих случаев:
- Если запрос не превышает значение
rate, указанное в методе new, то этот метод возвращает0как задержку и (ноль) количество избыточных запросов в секунду в текущий момент. - Если запрос превышает лимит
rate, указанный в методе new, но не значениеrate+burst, тогда этот метод возвращает соответствующую задержку (в секундах) для текущего запроса, чтобы он все еще соответствовал порогуrate, как если бы он пришел немного позже, а не сейчас. Второе возвращаемое значение указывает количество избыточных запросов в секунду в этот момент (включая текущий запрос). - Если запрос превышает лимит
rate+burst, тогда этот метод возвращаетnilи строку ошибки"rejected". - Если произошла ошибка, тогда этот метод возвращает
nilи строку, описывающую ошибку. Например,"не удалось создать redis - соединение отклонено".
Этот метод никогда не спит сам по себе. Он просто возвращает задержку, если это необходимо, и требует от вызывающего позже вызвать метод ngx.sleep для ожидания.
set_burst
синтаксис: obj:set_burst(burst)
Перезаписывает порог burst, как указано в методе new.
См. также
- Ограничение скорости с NGINX: https://www.nginx.com/blog/rate-limiting-nginx/
- Модуль ngx_lua: https://github.com/openresty/lua-nginx-module
- OpenResty: https://openresty.org/
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-redis-ratelimit.