upstream: Module d'équilibrage de charge et de basculement de connexion en amont pour 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-upstream
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-upstream
Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que nginx-module-lua est installé.
Ce document décrit lua-resty-upstream v0.10 publié le 19 décembre 2019.
Module d'équilibrage de charge et de basculement de connexion en amont
Vue d'ensemble
Créez un dictionnaire partagé Lua. Définissez vos pools et hôtes en amont dans init_by_lua, cela sera enregistré dans le dictionnaire partagé.
Utilisez la méthode connect pour retourner un socket TCP connecté.
Vous pouvez également passer un module resty (par exemple lua-resty-redis ou lua-resty-http) qui implémente connect() et set_timeout().
Appelez process_failed_hosts pour gérer les hôtes échoués sans bloquer la requête actuelle.
Utilisez resty.upstream.api pour modifier la configuration en amont pendant l'initialisation ou à l'exécution, c'est recommandé !
resty.upstream.http enveloppe le lua-resty-http de @pintsized.
Il permet le basculement basé sur les codes d'état HTTP ainsi que sur l'état de connexion du socket.
lua_shared_dict my_upstream_dict 1m;
init_by_lua '
upstream_socket = require("resty.upstream.socket")
upstream_api = require("resty.upstream.api")
upstream, configured = upstream_socket:new("my_upstream_dict")
if not upstream then
error(configured)
end
api = upstream_api:new(upstream)
if not configured then -- Reconfigurer uniquement au démarrage, la mémoire partagée persiste à travers un HUP
api:create_pool({id = "primary", timeout = 100})
api:set_priority("primary", 0)
api:set_method("primary", "round_robin")
api:add_host("primary", { id="a", host = "127.0.0.1", port = "80", weight = 10 })
api:add_host("primary", { id="b", host = "127.0.0.1", port = "81", weight = 10 })
api:create_pool({id = "dr"})
api:set_priority("dr", 10)
api:add_host("dr", { host = "127.0.0.1", port = "82", weight = 5 })
api:add_host("dr", { host = "127.0.0.1", port = "83", weight = 10 })
api:create_pool({id = "test", priority = 5})
api:add_host("primary", { id="c", host = "127.0.0.1", port = "82", weight = 10 })
api:add_host("primary", { id="d", host = "127.0.0.1", port = "83", weight = 10 })
end
';
init_worker_by_lua 'upstream:init_background_thread()';
server {
location / {
content_by_lua '
local sock, err = upstream:connect()
upstream:process_failed_hosts()
';
}
}
upstream.socket
new
syntax: upstream, configured = upstream_socket:new(dictionary, id?)
Retourne un nouvel objet en amont en utilisant le nom du dictionnaire fourni. Lorsqu'il est appelé dans init_by_lua, il retourne une variable supplémentaire si le dictionnaire contient déjà une configuration. Prend un paramètre id optionnel, celui-ci doit être unique si plusieurs instances de upstream.socket utilisent le même dictionnaire.
init_background_thread
syntax: ok, err = upstream:init_background_thread()
Initialise le thread d'arrière-plan, doit être appelé dans init_worker_by_lua.
connect
syntax: ok, err = upstream:connect(client?, key?)
Tente de se connecter à un hôte dans les pools définis dans l'ordre de priorité en utilisant la méthode d'équilibrage de charge sélectionnée. Retourne un socket connecté et une table contenant l'hôte, poolid et pool ou nil et un message d'erreur.
Lorsqu'un socket ou un module resty est passé, il retournera le même objet après une connexion réussie ou nil.
De plus, les méthodes de hachage peuvent prendre une key optionnelle pour définir comment hacher la connexion afin de déterminer l'hôte. Par défaut, ngx.var.remote_addr est utilisé. Cette valeur est ignorée lorsque la méthode du pool est round robin.
resty_redis = require('resty.redis')
local redis = resty_redis.new()
local key = ngx.req.get_headers()["X-Forwarded-For"]
local redis, err = upstream:connect(redis, key)
if not redis then
ngx.log(ngx.ERR, err)
ngx.status = 500
return ngx.exit(ngx.status)
end
ngx.log(ngx.info, 'Connected to ' .. err.host.host .. ':' .. err.host.port)
local ok, err = redis:get('key')
process_failed_hosts
syntax: ok, err = upstream:process_failed_hosts()
Traite tous les hôtes échoués ou récupérés de la requête actuelle. Lance un rappel immédiat via ngx.timer.at, ne bloque pas la requête actuelle.
get_pools
syntax: pools = usptream:get_pools()
Retourne une table contenant la configuration actuelle des pools et des hôtes. Par exemple :
{
primary = {
up = true,
method = 'round_robin',
timeout = 100,
priority = 0,
hosts = {
web01 = {
host = "127.0.0.1",
weight = 10,
port = "80",
lastfail = 0,
failcount = 0,
up = true,
healthcheck = true
},
web02 = {
host = "127.0.0.1",
weight = 10,
port = "80",
lastfail = 0,
failcount = 0,
up = true,
healthcheck = { interval = 30, path = '/check' }
}
}
},
secondary = {
up = true,
method = 'round_robin',
timeout = 2000,
priority = 10,
hosts = {
dr01 = {
host = "10.10.10.1",
weight = 10,
port = "80",
lastfail = 0,
failcount = 0,
up = true
}
}
},
}
save_pools
syntax: ok, err = upstream:save_pools(pools)
Sauvegarde une table de pools dans le dictionnaire partagé, pools doit être au même format que celui retourné par get_pools.
sort_pools
syntax: ok, err = upstream:sort_pools(pools)
Génère un ordre de priorité dans le dictionnaire partagé basé sur la table de pools fournie.
bind
syntax: ok, err = upstream:bind(event, func)
Liaison d'une fonction à appeler lorsque des événements se produisent. func doit s'attendre à 1 argument contenant les données de l'événement.
Retourne true en cas de liaison réussie ou nil et un message d'erreur en cas d'échec.
local function host_down_handler(event)
ngx.log(ngx.ERR, "Host: ", event.host.host, ":", event.host.port, " dans le pool '", event.pool.id,'" est hors service!')
end
local ok, err = upstream:bind('host_down', host_down_handler)
Événement : host_up
Déclenché lorsqu'un hôte change de statut de hors service à en service. Les données de l'événement sont une table contenant l'hôte et le pool affectés.
Événement : host_down
Déclenché lorsqu'un hôte change de statut de en service à hors service. Les données de l'événement sont une table contenant l'hôte et le pool affectés.
upstream.api
Ces fonctions vous permettent de reconfigurer dynamiquement les pools et les hôtes en amont.
new
syntax: api, err = upstream_api:new(upstream)
Retourne un nouvel objet api en utilisant l'objet en amont fourni.
set_method
syntax: ok, err = api:set_method(poolid, method)
Définit la méthode d'équilibrage de charge pour le pool spécifié. Actuellement, les méthodes de round robin randomisées et de hachage sont prises en charge.
create_pool
syntax: ok, err = api:create_pool(pool)
Crée un nouveau pool à partir d'une table d'options, pool doit contenir au moins 1 clé id qui doit être unique dans l'objet en amont actuel.
D'autres options valides sont :
methodMéthode d'équilibragetimeoutDélai d'attente de connexion en mspriorityLes pools de priorité plus élevée sont utilisés plus tardread_timeoutkeepalive_timeoutkeepalive_poolstatus_codesVoir status_codes
Les hôtes ne peuvent pas être définis à ce stade.
Remarque : Les ID sont convertis en chaîne par cette fonction.
Valeurs par défaut du pool :
{ method = 'round_robin', timeout = 2000, priority = 0 }
set_priority
syntax: ok, err = api:set_priority(poolid, priority)
La priorité doit être un nombre, retourne nil en cas d'erreur.
add_host
syntax: ok, err = api:add_host(poolid, host)
Prend un ID de pool et une table d'options, host doit contenir au moins host. Si l'ID de l'hôte n'est pas spécifié, il sera un index numérique basé sur le nombre d'hôtes dans le pool.
Remarque : Les ID sont convertis en chaîne par cette fonction.
Valeurs par défaut :
{ host = '', port = 80, weight = 0}
remove_host
syntax: ok, err = api:remove_host(poolid, host)
Prend un poolid et un hostid à supprimer du pool.
down_host
syntax: ok,err = api:down_host(poolid, host)
Marque manuellement un hôte comme hors service, cet hôte ne sera pas réactivé automatiquement.
up_host
syntax: ok,err = api:up_host(poolid, host)
Restaure manuellement un hôte mort dans le pool.
upstream.http
Fonctions pour effectuer des requêtes HTTP vers des hôtes en amont.
new
syntax: httpc, err = upstream_http:new(upstream, ssl_opts?)
Retourne un nouvel objet HTTP en amont en utilisant l'objet en amont fourni.
ssl_opts est une table optionnelle pour configurer le support SSL.
* ssl défini sur true pour activer le handshake SSL, par défaut false
* ssl_verify défini sur false pour désactiver la vérification du certificat SSL, par défaut true
* sni_host une chaîne à utiliser comme nom d'hôte SNI, par défaut l'en-tête Host de la requête
lua
https_upstream = Upstream_HTTP:new(upstream_ssl, {
ssl = true,
ssl_verify = true,
sni_host = "foo.example.com"
})
init_background_thread
syntax: ok, err = upstream_http:init_background_thread()
Initialise le thread d'arrière-plan, doit être appelé dans init_worker_by_lua.
Ne pas appeler la méthode init_background_thread dans upstream.socket si vous utilisez le thread d'arrière-plan upstream.http.
request
syntax: res, err_or_conn_info, status? = upstream_api:request(params)
Prend les mêmes paramètres que la méthode request de lua-resty-http.
Lors d'une requête réussie, retourne l'objet lua-resty-http et une table contenant l'hôte et le pool connectés.
Si la requête échoue, retourne nil, l'erreur et un code d'état HTTP suggéré.
local ok, err, status = upstream_http:request({
path = "/helloworld",
headers = {
["Host"] = "example.com",
}
})
if not ok then
ngx.status = status
ngx.say(err)
ngx.exit(status)
else
local host = err.host
local pool = err.pool
end
set_keepalive
syntax: ok, err = upstream_http:set_keepalive()
Transmet le délai d'attente de keepalive / pool à la méthode set_keepalive de lua-resty-http.
get_reused_times
syntax: ok, err = upstream_http:get_reused_times()
Transmet à la méthode get_reused_times de lua-resty-http.
close
syntax: ok, err = upstream_http:close()
Transmet à la méthode close de lua-resty-http.
Vérifications de santé HTTP
Des vérifications de santé actives en arrière-plan peuvent être activées en ajoutant le paramètre healthcheck à un hôte.
Une valeur de true activera la vérification par défaut, une requête GET pour /.
Le paramètre healthcheck peut également être une table de paramètres valides pour la méthode request de lua-resty-http.
Avec quelques paramètres supplémentaires :
intervalpour définir le temps entre les vérifications de santé, en secondes. Doit être >= 10s. Par défaut 60s.timeoutdéfinit le délai d'attente de connexion pour les vérifications de santé. Par défaut, réglage du pool.read_timeoutdéfinit le délai d'attente de lecture pour les vérifications de santé. Par défaut, réglage du pool.status_codesune table de codes d'état de réponse invalides. Par défaut, réglage du pool.
L'échec de la vérification en arrière-plan est selon les mêmes paramètres que pour une requête frontend, sauf si explicitement remplacé.
-- Paramètres de vérification personnalisés
api:add_host("primary", {
host = 123.123.123.123,
port = 80,
healthcheck = {
interval = 30, -- vérification toutes les 30s
timeout = (5*1000), -- délai d'attente de connexion de 5s
read_timeout = (15*1000), -- délai d'attente de lecture de 15s
status_codes = {["5xx"] = true, ["403"] = true}, -- les réponses 5xx et 403 sont un échec
-- paramètres resty-http
path = "/check",
headers = {
["Host"] = "domain.com",
["Accept-Encoding"] = "gzip"
}
}
})
-- Paramètres de vérification par défaut
api:add_host("primary", {host = 123.123.123.123, port = 80, healthcheck = true})
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-upstream.