limit-traffic: Lua библиотека для ограничения и контроля трафика в nginx-module-lua
Установка
Если вы еще не настроили подписку на репозиторий 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-limit-traffic
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-limit-traffic
Чтобы использовать эту Lua библиотеку с NGINX, убедитесь, что nginx-module-lua установлен.
Этот документ описывает lua-resty-limit-traffic v0.9, выпущенную 8 августа 2023 года.
## демонстрация использования модуля resty.limit.req (в одиночку!)
http {
lua_shared_dict my_limit_req_store 100m;
server {
location / {
access_by_lua_block {
-- ну, мы могли бы поместить вызовы require() и new() в наши собственные Lua
-- модули, чтобы сэкономить накладные расходы. здесь мы помещаем их ниже просто для
-- удобства.
local limit_req = require "resty.limit.req"
-- ограничить запросы до 200 req/sec с всплеском в 100 req/sec,
-- то есть мы задерживаем запросы ниже 300 req/sec и выше 200
-- req/sec и отклоняем любые запросы, превышающие 300 req/sec.
local lim, err = limit_req.new("my_limit_req_store", 200, 100)
if not lim then
ngx.log(ngx.ERR,
"не удалось создать объект resty.limit.req: ", err)
return ngx.exit(500)
end
-- следующий вызов должен быть на каждый запрос.
-- здесь мы используем удаленный (IP) адрес в качестве ключа ограничения
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.log(ngx.ERR, "не удалось ограничить запрос: ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
-- 2-й возвращаемый параметр содержит количество избыточных запросов
-- в секунду для указанного ключа. например, число 31
-- означает, что текущая скорость запросов составляет 231 req/sec для
-- указанного ключа.
local excess = err
-- запрос превышает 200 req/sec, но ниже 300 req/sec,
-- поэтому мы намеренно задерживаем его здесь немного, чтобы соответствовать
-- скорости 200 req/sec.
ngx.sleep(delay)
end
}
# обработчик контента идет сюда. если это content_by_lua, то вы можете
# объединить Lua код выше в access_by_lua в ваш обработчик Lua content_by_lua,
# чтобы сэкономить немного времени ЦП.
}
}
}
## демонстрация использования модуля resty.limit.conn (в одиночку!)
http {
lua_shared_dict my_limit_conn_store 100m;
server {
location / {
access_by_lua_block {
-- ну, мы могли бы поместить вызовы require() и new() в наши собственные Lua
-- модули, чтобы сэкономить накладные расходы. здесь мы помещаем их ниже просто для
-- удобства.
local limit_conn = require "resty.limit.conn"
-- ограничить запросы до 200 одновременных запросов (обычно это просто
-- входящие соединения, если не используются такие протоколы, как SPDY) с
-- всплеском в 100 дополнительных одновременных запросов, то есть мы задерживаем
-- запросы ниже 300 одновременных соединений и выше 200
-- соединений и отклоняем любые новые запросы, превышающие 300
-- соединений.
-- также мы предполагаем стандартное время запроса 0.5 сек, которое может быть
-- динамически скорректировано вызовом leaving() в log_by_lua ниже.
local lim, err = limit_conn.new("my_limit_conn_store", 200, 100, 0.5)
if not lim then
ngx.log(ngx.ERR,
"не удалось создать объект resty.limit.conn: ", err)
return ngx.exit(500)
end
-- следующий вызов должен быть на каждый запрос.
-- здесь мы используем удаленный (IP) адрес в качестве ключа ограничения
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.log(ngx.ERR, "не удалось ограничить запрос: ", err)
return ngx.exit(500)
end
if lim:is_committed() then
local ctx = ngx.ctx
ctx.limit_conn = lim
ctx.limit_conn_key = key
ctx.limit_conn_delay = delay
end
-- 2-й возвращаемый параметр содержит текущий уровень одновременности
-- для указанного ключа.
local conn = err
if delay >= 0.001 then
-- запрос превышает соотношение 200 соединений, но ниже
-- 300 соединений, поэтому
-- мы намеренно задерживаем его здесь немного, чтобы соответствовать
-- лимиту в 200 соединений.
-- ngx.log(ngx.WARN, "задержка")
ngx.sleep(delay)
end
}
# обработчик контента идет сюда. если это content_by_lua, то вы можете
# объединить Lua код выше в access_by_lua в ваш
# обработчик Lua content_by_lua, чтобы сэкономить немного времени ЦП.
log_by_lua_block {
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
-- если вы используете модуль upstream в фазе контента,
-- то вам, вероятно, нужно использовать $upstream_response_time
-- вместо ($request_time - ctx.limit_conn_delay) ниже.
local latency = tonumber(ngx.var.request_time) - ctx.limit_conn_delay
local key = ctx.limit_conn_key
assert(key)
local conn, err = lim:leaving(key, latency)
if not conn then
ngx.log(ngx.ERR,
"не удалось зафиксировать выход соединения ",
"запроса: ", err)
return
end
end
}
}
}
}
## демонстрация использования модуля resty.limit.traffic
http {
lua_shared_dict my_req_store 100m;
lua_shared_dict my_conn_store 100m;
server {
location / {
access_by_lua_block {
local limit_conn = require "resty.limit.conn"
local limit_req = require "resty.limit.req"
local limit_traffic = require "resty.limit.traffic"
local lim1, err = limit_req.new("my_req_store", 300, 200)
assert(lim1, err)
local lim2, err = limit_req.new("my_req_store", 200, 100)
assert(lim2, err)
local lim3, err = limit_conn.new("my_conn_store", 1000, 1000, 0.5)
assert(lim3, err)
local limiters = {lim1, lim2, lim3}
local host = ngx.var.host
local client = ngx.var.binary_remote_addr
local keys = {host, client, client}
local states = {}
local delay, err = limit_traffic.combine(limiters, keys, states)
if not delay then
if err == "rejected" then
return ngx.exit(503)
end
ngx.log(ngx.ERR, "не удалось ограничить трафик: ", err)
return ngx.exit(500)
end
if lim3:is_committed() then
local ctx = ngx.ctx
ctx.limit_conn = lim3
ctx.limit_conn_key = keys[3]
end
print("задержка ", delay, " сек, состояния: ",
table.concat(states, ", "))
if delay >= 0.001 then
ngx.sleep(delay)
end
}
# обработчик контента идет сюда. если это content_by_lua, то вы можете
# объединить Lua код выше в access_by_lua в ваш
# обработчик Lua content_by_lua, чтобы сэкономить немного времени ЦП.
log_by_lua_block {
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
-- если вы используете модуль upstream в фазе контента,
-- то вам, вероятно, нужно использовать $upstream_response_time
-- вместо $request_time ниже.
local latency = tonumber(ngx.var.request_time)
local key = ctx.limit_conn_key
assert(key)
local conn, err = lim:leaving(key, latency)
if not conn then
ngx.log(ngx.ERR,
"не удалось зафиксировать выход соединения ",
"запроса: ", err)
return
end
end
}
}
}
}
Описание
Эта библиотека предоставляет несколько Lua модулей, чтобы помочь пользователям OpenResty/ngx_lua контролировать и ограничивать трафик, как скорость запросов, так и одновременность запросов (или то и другое).
- resty.limit.req предоставляет ограничение скорости запросов и корректировку на основе метода "протекающего ведра".
- resty.limit.count предоставляет ограничение скорости на основе реализации "фиксированного окна" с версии OpenResty 1.13.6.1+.
- resty.limit.conn предоставляет ограничение уровня одновременности запросов и корректировку на основе дополнительных задержек.
- resty.limit.traffic предоставляет агрегатор для объединения нескольких экземпляров классов resty.limit.req, resty.limit.count или resty.limit.conn (или всех).
Пожалуйста, ознакомьтесь с документацией этих Lua модулей для получения более подробной информации.
Эта библиотека предоставляет более гибкие альтернативы стандартным модулям NGINX
ngx_limit_req
и ngx_limit_conn.
Например, ограничители на основе Lua, предоставленные этой библиотекой, могут использоваться в любых контекстах,
например, прямо перед процедурой SSL-рукопожатия (как с ssl_certificate_by_lua)
или прямо перед выдачей запросов к бэкенду.
nginx.conf
http { ... }
и затем загрузите один из модулей, предоставляемых этой библиотекой, в Lua. Например,
```lua
local limit_req = require "resty.limit.req"
См. также
- модуль resty.limit.req
- модуль resty.limit.count
- модуль resty.limit.conn
- модуль resty.limit.traffic
- модуль ngx_lua: https://github.com/openresty/lua-nginx-module
- OpenResty: https://openresty.org/
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-limit-traffic.