limit-traffic: bibliothèque Lua pour limiter et contrôler le trafic dans nginx-module-lua
Installation
Si vous n'avez pas encore configuré l'abonnement au dépôt RPM, inscrivez-vous. Ensuite, vous pouvez procéder avec les étapes suivantes.
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
Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que nginx-module-lua est installé.
Ce document décrit lua-resty-limit-traffic v0.9 publié le 08 août 2023.
## démontrer l'utilisation du module resty.limit.req (seul !)
http {
lua_shared_dict my_limit_req_store 100m;
server {
location / {
access_by_lua_block {
-- eh bien, nous pourrions mettre les appels require() et new() dans nos propres modules Lua
-- pour économiser des ressources. ici nous les mettons ci-dessous juste pour
-- commodité.
local limit_req = require "resty.limit.req"
-- limiter les requêtes à moins de 200 req/sec avec un pic de 100 req/sec,
-- c'est-à-dire que nous retardons les requêtes à moins de 300 req/sec et au-dessus de 200
-- req/sec, et rejetons toutes les requêtes dépassant 300 req/sec.
local lim, err = limit_req.new("my_limit_req_store", 200, 100)
if not lim then
ngx.log(ngx.ERR,
"échec de l'instanciation d'un objet resty.limit.req : ", err)
return ngx.exit(500)
end
-- l'appel suivant doit être par requête.
-- ici nous utilisons l'adresse (IP) distante comme clé de limitation
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, "échec de la limitation des requêtes : ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
-- la 2ème valeur de retour contient le nombre de requêtes excessives
-- par seconde pour la clé spécifiée. par exemple, le nombre 31
-- signifie que le taux de requêtes actuel est de 231 req/sec pour la
-- clé spécifiée.
local excess = err
-- la requête dépassant les 200 req/sec mais en dessous de 300 req/sec,
-- donc nous la retardons intentionnellement ici un peu pour respecter le
-- taux de 200 req/sec.
ngx.sleep(delay)
end
}
# le gestionnaire de contenu va ici. s'il s'agit de content_by_lua, alors vous pouvez
# fusionner le code Lua ci-dessus dans access_by_lua dans le gestionnaire Lua de votre content_by_lua
# pour économiser un peu de temps CPU.
}
}
}
## démontrer l'utilisation du module resty.limit.conn (seul !)
http {
lua_shared_dict my_limit_conn_store 100m;
server {
location / {
access_by_lua_block {
-- eh bien, nous pourrions mettre les appels require() et new() dans nos propres modules Lua
-- pour économiser des ressources. ici nous les mettons ci-dessous juste pour
-- commodité.
local limit_conn = require "resty.limit.conn"
-- limiter les requêtes à moins de 200 requêtes concurrentes (normalement juste
-- des connexions entrantes à moins que des protocoles comme SPDY ne soient utilisés) avec
-- un pic de 100 requêtes concurrentes supplémentaires, c'est-à-dire que nous retardons
-- les requêtes à moins de 300 connexions concurrentes et au-dessus de 200
-- connexions, et rejetons toute nouvelle requête dépassant 300
-- connexions.
-- de plus, nous supposons un temps de requête par défaut de 0,5 sec, qui peut être
-- ajusté dynamiquement par l'appel leaving() dans log_by_lua ci-dessous.
local lim, err = limit_conn.new("my_limit_conn_store", 200, 100, 0.5)
if not lim then
ngx.log(ngx.ERR,
"échec de l'instanciation d'un objet resty.limit.conn : ", err)
return ngx.exit(500)
end
-- l'appel suivant doit être par requête.
-- ici nous utilisons l'adresse (IP) distante comme clé de limitation
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, "échec de la limitation des requêtes : ", 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
-- la 2ème valeur de retour contient le niveau de concurrence actuel
-- pour la clé spécifiée.
local conn = err
if delay >= 0.001 then
-- la requête dépassant le ratio de 200 connexions mais en dessous
-- de 300 connexions, donc
-- nous la retardons intentionnellement ici un peu pour respecter le
-- limite de 200 connexions.
-- ngx.log(ngx.WARN, "retard")
ngx.sleep(delay)
end
}
# le gestionnaire de contenu va ici. s'il s'agit de content_by_lua, alors vous pouvez
# fusionner le code Lua ci-dessus dans access_by_lua dans le gestionnaire Lua de votre
# content_by_lua pour économiser un peu de temps CPU.
log_by_lua_block {
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
-- si vous utilisez un module en amont dans la phase de contenu,
-- alors vous voudrez probablement utiliser $upstream_response_time
-- au lieu de ($request_time - ctx.limit_conn_delay) ci-dessous.
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,
"échec de l'enregistrement de la connexion sortante ",
"requête : ", err)
return
end
end
}
}
}
}
## démontrer l'utilisation du module 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, "échec de la limitation du trafic : ", 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("dormir ", delay, " sec, états : ",
table.concat(states, ", "))
if delay >= 0.001 then
ngx.sleep(delay)
end
}
# le gestionnaire de contenu va ici. s'il s'agit de content_by_lua, alors vous pouvez
# fusionner le code Lua ci-dessus dans access_by_lua dans le gestionnaire Lua de votre
# content_by_lua pour économiser un peu de temps CPU.
log_by_lua_block {
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
-- si vous utilisez un module en amont dans la phase de contenu,
-- alors vous voudrez probablement utiliser $upstream_response_time
-- au lieu de $request_time ci-dessous.
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,
"échec de l'enregistrement de la connexion sortante ",
"requête : ", err)
return
end
end
}
}
}
}
Description
Cette bibliothèque fournit plusieurs modules Lua pour aider les utilisateurs d'OpenResty/ngx_lua à contrôler et limiter le trafic, soit le taux de requêtes soit la concurrence des requêtes (ou les deux).
- resty.limit.req fournit une limitation du taux de requêtes et un ajustement basé sur la méthode du "seau fuyant".
- resty.limit.count fournit une limitation de taux basée sur une implémentation de "fenêtre fixe" depuis OpenResty 1.13.6.1+.
- resty.limit.conn fournit une limitation du niveau de concurrence des requêtes et un ajustement basé sur des retards supplémentaires.
- resty.limit.traffic fournit un agrégateur pour combiner plusieurs instances des classes resty.limit.req, resty.limit.count ou resty.limit.conn (ou toutes).
Veuillez consulter la documentation de ces modules Lua pour plus de détails.
Cette bibliothèque fournit des alternatives plus flexibles aux modules standard de NGINX
ngx_limit_req
et ngx_limit_conn.
Par exemple, les limiteurs basés sur Lua fournis par cette bibliothèque peuvent être utilisés dans n'importe quel contexte
comme juste avant la procédure de négociation SSL en aval (comme avec ssl_certificate_by_lua)
ou juste avant d'émettre des requêtes en arrière-plan.
nginx.conf
http { ... }
et ensuite charger l'un des modules fournis par cette bibliothèque en Lua. Par exemple,
```lua
local limit_req = require "resty.limit.req"
Voir aussi
- module resty.limit.req
- module resty.limit.count
- module resty.limit.conn
- module resty.limit.traffic
- le module ngx_lua : https://github.com/openresty/lua-nginx-module
- OpenResty : https://openresty.org/
GitHub
Vous pouvez trouver des conseils de configuration supplémentaires et de la documentation pour ce module dans le dépôt GitHub pour nginx-module-limit-traffic.