limit-traffic: biblioteca Lua para limitar e controlar o tráfego no nginx-module-lua
Instalação
Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Em seguida, você pode prosseguir com os seguintes passos.
CentOS/RHEL 7 ou 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
Para usar esta biblioteca Lua com NGINX, certifique-se de que o nginx-module-lua está instalado.
Este documento descreve lua-resty-limit-traffic v0.9 lançado em 08 de agosto de 2023.
## demonstrar o uso do módulo resty.limit.req (sozinho!)
http {
lua_shared_dict my_limit_req_store 100m;
server {
location / {
access_by_lua_block {
-- bem, poderíamos colocar as chamadas require() e new() em nossos próprios módulos Lua
-- para economizar sobrecarga. aqui as colocamos abaixo apenas por
-- conveniência.
local limit_req = require "resty.limit.req"
-- limitar as requisições a menos de 200 req/sec com um pico de 100 req/sec,
-- ou seja, atrasamos requisições abaixo de 300 req/sec e acima de 200
-- req/sec, e rejeitamos quaisquer requisições que excedam 300 req/sec.
local lim, err = limit_req.new("my_limit_req_store", 200, 100)
if not lim then
ngx.log(ngx.ERR,
"falha ao instanciar um objeto resty.limit.req: ", err)
return ngx.exit(500)
end
-- a seguinte chamada deve ser por requisição.
-- aqui usamos o endereço remoto (IP) como a chave de limitação
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, "falha ao limitar req: ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
-- o 2º valor de retorno contém o número de requisições excedentes
-- por segundo para a chave especificada. por exemplo, o número 31
-- significa que a taxa atual de requisições está em 231 req/sec para a
-- chave especificada.
local excess = err
-- a requisição excede as 200 req/sec, mas está abaixo de 300 req/sec,
-- então intencionalmente a atrasamos aqui um pouco para se conformar com a
-- taxa de 200 req/sec.
ngx.sleep(delay)
end
}
# manipulador de conteúdo vai aqui. se for content_by_lua, então você pode
# mesclar o código Lua acima em access_by_lua no manipulador Lua do seu
# content_by_lua para economizar um pouco de tempo de CPU.
}
}
}
## demonstrar o uso do módulo resty.limit.conn (sozinho!)
http {
lua_shared_dict my_limit_conn_store 100m;
server {
location / {
access_by_lua_block {
-- bem, poderíamos colocar as chamadas require() e new() em nossos próprios módulos Lua
-- para economizar sobrecarga. aqui as colocamos abaixo apenas por
-- conveniência.
local limit_conn = require "resty.limit.conn"
-- limitar as requisições a menos de 200 requisições concorrentes (normalmente apenas
-- conexões de entrada, a menos que protocolos como SPDY sejam usados) com
-- um pico de 100 requisições concorrentes extras, ou seja, atrasamos
-- requisições abaixo de 300 conexões concorrentes e acima de 200
-- conexões, e rejeitamos quaisquer novas requisições que excedam 300
-- conexões.
-- além disso, assumimos um tempo de requisição padrão de 0.5 seg, que pode ser
-- ajustado dinamicamente pela chamada leaving() no log_by_lua abaixo.
local lim, err = limit_conn.new("my_limit_conn_store", 200, 100, 0.5)
if not lim then
ngx.log(ngx.ERR,
"falha ao instanciar um objeto resty.limit.conn: ", err)
return ngx.exit(500)
end
-- a seguinte chamada deve ser por requisição.
-- aqui usamos o endereço remoto (IP) como a chave de limitação
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, "falha ao limitar req: ", 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
-- o 2º valor de retorno contém o nível atual de concorrência
-- para a chave especificada.
local conn = err
if delay >= 0.001 then
-- a requisição excede a proporção de 200 conexões, mas está abaixo
-- de 300 conexões, então
-- intencionalmente a atrasamos aqui um pouco para se conformar com a
-- limitação de 200 conexões.
-- ngx.log(ngx.WARN, "atrasando")
ngx.sleep(delay)
end
}
# manipulador de conteúdo vai aqui. se for content_by_lua, então você pode
# mesclar o código Lua acima em access_by_lua no manipulador Lua do seu
# content_by_lua para economizar um pouco de tempo de CPU.
log_by_lua_block {
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
-- se você estiver usando um módulo upstream na fase de conteúdo,
-- então você provavelmente quer usar $upstream_response_time
-- em vez de ($request_time - ctx.limit_conn_delay) abaixo.
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,
"falha ao registrar a conexão saindo ",
"requisição: ", err)
return
end
end
}
}
}
}
## demonstrar o uso do módulo 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, "falha ao limitar tráfego: ", 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("dormindo ", delay, " seg, estados: ",
table.concat(states, ", "))
if delay >= 0.001 then
ngx.sleep(delay)
end
}
# manipulador de conteúdo vai aqui. se for content_by_lua, então você pode
# mesclar o código Lua acima em access_by_lua no manipulador Lua do seu
# content_by_lua para economizar um pouco de tempo de CPU.
log_by_lua_block {
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
-- se você estiver usando um módulo upstream na fase de conteúdo,
-- então você provavelmente quer usar $upstream_response_time
-- em vez de $request_time abaixo.
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,
"falha ao registrar a conexão saindo ",
"requisição: ", err)
return
end
end
}
}
}
}
Descrição
Esta biblioteca fornece vários módulos Lua para ajudar os usuários do OpenResty/ngx_lua a controlar e limitar o tráfego, seja a taxa de requisições ou a concorrência de requisições (ou ambos).
- resty.limit.req fornece limitação de taxa de requisições e ajuste baseado no método "balde furado".
- resty.limit.count fornece limitação de taxa baseada em uma implementação de "janela fixa" desde OpenResty 1.13.6.1+.
- resty.limit.conn fornece limitação de nível de concorrência de requisições e ajuste baseado em atrasos extras.
- resty.limit.traffic fornece um agregador para combinar várias instâncias das classes resty.limit.req, resty.limit.count ou resty.limit.conn (ou todas).
Por favor, consulte a documentação própria desses módulos Lua para mais detalhes.
Esta biblioteca oferece alternativas mais flexíveis aos módulos padrão do NGINX
ngx_limit_req
e ngx_limit_conn.
Por exemplo, os limitadores baseados em Lua fornecidos por esta biblioteca podem ser usados em qualquer contexto
como logo antes do procedimento de handshake SSL downstream (como com ssl_certificate_by_lua)
ou logo antes de emitir requisições para o backend.
nginx.conf
http { ... }
e então carregue um dos módulos fornecidos por esta biblioteca em Lua. Por exemplo,
```lua
local limit_req = require "resty.limit.req"
Veja Também
- módulo resty.limit.req
- módulo resty.limit.count
- módulo resty.limit.conn
- módulo resty.limit.traffic
- o módulo ngx_lua: https://github.com/openresty/lua-nginx-module
- OpenResty: https://openresty.org/
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório GitHub para nginx-module-limit-traffic.