checkups: Gestionar upstreams de NGINX en Lua puro
Instalación
Si no has configurado la suscripción al repositorio RPM, regístrate. Luego puedes proceder con los siguientes pasos.
CentOS/RHEL 7 o 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-checkups
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-checkups
Para usar esta biblioteca Lua con NGINX, asegúrate de que nginx-module-lua esté instalado.
Este documento describe lua-resty-checkups v0.1 lanzado el 01 de febrero de 2019.
- Latido periódico a servidores upstream
- Verificación de salud proactiva y pasiva
- Actualización dinámica de upstream
- Balanceo por round-robin ponderado o hash consistente
- Sincronización con bloques upstream de Nginx
- Probar clústeres por niveles o por claves
Sinopsis
-- config.lua
_M = {}
_M.global = {
checkup_timer_interval = 15,
checkup_shd_sync_enable = true,
shd_config_timer_interval = 1,
}
_M.ups1 = {
cluster = {
{
servers = {
{ host = "127.0.0.1", port = 4444, weight=10, max_fails=3, fail_timeout=10 },
}
},
},
}
return _M
-- nginx.conf
lua_shared_dict state 10m;
lua_shared_dict mutex 1m;
lua_shared_dict locks 1m;
lua_shared_dict config 10m;
server {
listen 12350;
return 200 12350;
}
server {
listen 12351;
return 200 12351;
}
init_by_lua_block {
local config = require "config"
local checkups = require "resty.checkups.api"
checkups.init(config)
}
init_worker_by_lua_block {
local config = require "config"
local checkups = require "resty.checkups.api"
checkups.prepare_checker(config)
checkups.create_checker()
}
server {
location = /12350 {
proxy_pass http://127.0.0.1:12350/;
}
location = /12351 {
proxy_pass http://127.0.0.1:12351/;
}
location = /t {
content_by_lua_block {
local checkups = require "resty.checkups.api"
local callback = function(host, port)
local res = ngx.location.capture("/" .. port)
ngx.say(res.body)
return 1
end
local ok, err
-- conectar a un servidor muerto, no hay upstream disponible
ok, err = checkups.ready_ok("ups1", callback)
if err then ngx.say(err) end
-- agregar servidor a ups1
ok, err = checkups.update_upstream("ups1", {
{
servers = {
{ host = "127.0.0.1", port = 12350, weight=10, max_fails=3, fail_timeout=10 },
}
},
})
if err then ngx.say(err) end
ngx.sleep(1)
ok, err = checkups.ready_ok("ups1", callback)
if err then ngx.say(err) end
ok, err = checkups.ready_ok("ups1", callback)
if err then ngx.say(err) end
-- agregar servidor a nuevo upstream
ok, err = checkups.update_upstream("ups2", {
{
servers = {
{ host="127.0.0.1", port=12351 },
}
},
})
if err then ngx.say(err) end
ngx.sleep(1)
ok, err = checkups.ready_ok("ups2", callback)
if err then ngx.say(err) end
-- agregar servidor a ups2, restablecer estado rr
ok, err = checkups.update_upstream("ups2", {
{
servers = {
{ host = "127.0.0.1", port = 12350, weight=10, max_fails=3, fail_timeout=10 },
{ host = "127.0.0.1", port = 12351, weight=10, max_fails=3, fail_timeout=10 },
}
},
})
if err then ngx.say(err) end
ngx.sleep(1)
ok, err = checkups.ready_ok("ups2", callback)
if err then ngx.say(err) end
ok, err = checkups.ready_ok("ups2", callback)
if err then ngx.say(err) end
}
}
}
Una salida típica de la ubicación /t definida arriba es:
no hay servidores disponibles
12350
12350
12351
12350
12351
Configuración
Configuración de Lua
El archivo de configuración de checkups es un módulo lua que consta de dos partes, la parte global y la parte del clúster.
Un ejemplo de archivo de configuración de checkups se muestra a continuación,
-- config.lua
-- Aquí está la parte global
_M = {}
_M.global = {
checkup_timer_interval = 15,
checkup_timer_overtime = 60,
default_heartbeat_enable = true,
checkup_shd_sync_enable = true,
shd_config_timer_interval = 1,
}
-- Las partes restantes son configuraciones del clúster
_M.redis = {
enable = true,
typ = "redis",
timeout = 2,
read_timeout = 15,
send_timeout = 15,
protected = true,
cluster = {
{ -- nivel 1
try = 2,
servers = {
{ host = "192.168.0.1", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
{ host = "192.168.0.2", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
}
},
{ -- nivel 2
servers = {
{ host = "192.168.0.3", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
}
},
},
}
_M.api = {
enable = false,
typ = "http",
http_opts = {
query = "GET /status HTTP/1.1\r\nHost: localhost\r\n\r\n",
statuses = {
["500"] = false,
["502"] = false,
["503"] = false,
["504"] = false,
},
},
mode = "hash",
cluster = {
dc1 = {
servers = {
{ host = "192.168.1.1", port = 1234, weight=10, max_fails=3, fail_timeout=10 },
}
},
dc2 = {
servers = {
{ host = "192.168.1.2", port = 1234, weight=10, max_fails=3, fail_timeout=10 },
}
}
}
}
_M.ups_from_nginx = {
timeout = 2,
cluster = {
{ -- nivel 1
upstream = "api.com",
},
{ -- nivel 2
upstream = "api.com",
upstream_only_backup = true,
},
},
}
return _M
configuraciones globales
checkup_timer_interval: Intervalo de envío de latidos a los servidores backend. El valor predeterminado es5.checkup_timer_overtime: Intervalo de las verificaciones para expirar la clave del temporizador. En la mayoría de los casos, no necesitas cambiar este valor. El valor predeterminado es60.default_heartbeat_enable: Las verificaciones enviarán latidos a los servidores por defecto o no. El valor predeterminado estrue.checkup_shd_sync_enable: Crear sincronizador de upstream para cada trabajador. Si se establece enfalse, el upstream dinámico no funcionará correctamente. El valor predeterminado estrue.shd_config_timer_interval: Intervalo de sincronización de la lista de upstream desde la memoria compartida. El valor predeterminado es igual acheckup_timer_interval.ups_status_sync_enable: Si se establece entrue, las verificaciones sincronizarán el estado del upstream desde las verificaciones a los bloques upstream de Nginx. El valor predeterminado esfalse.ups_status_timer_interval: Intervalo de sincronización del estado del upstream desde las verificaciones a los bloques upstream de Nginx.
Configuraciones del clúster
skey:_M.xxxxx.xxxxxes laskey(clave de servicio) de este clúster.enable: Habilitar o deshabilitar latidos a los servidores. El valor predeterminado estrue.typ: Tipo de clúster, debe ser uno degeneral,redis,mysql,http. El valor predeterminado esgeneral.general: Latido por TCPsock:connect.redis: Latido por redisPING. Se requiere el módulo lua-resty-redis.mysql: Latido por mysqldb:connect. Se requiere el módulo lua-resty-mysql.http: Latido por solicitud HTTP. Puedes configurar una solicitud HTTP personalizada y códigos de respuesta enhttp_opts.
timeout: Tiempo de conexión a los servidores upstream. El valor predeterminado es5.read_timeout: Tiempo de lectura a los servidores upstream (no se utiliza durante el latido). El valor predeterminado es igual atimeout.send_timeout: Tiempo de escritura a los servidores upstream (no se utiliza durante el latido). El valor predeterminado es igual atimeout.-
http_opts: Configuraciones de latido HTTP. Solo funciona paratyp="http".query: Solicitud HTTP para el latido.statuses: Si el código devuelto por el servidor se establece enfalse, entonces el servidor se considera que está fallando.
-
mode: Modo de balanceo. Puede configurarse comohash,url_hashoip_hash. Las verificaciones balancearán los servidores porhash_key,ngx.var.uriongx.var.remote_addr. El valor predeterminado eswrr. protected: Si se establece entruey todos los servidores en el clúster están fallando, las verificaciones no marcarán el último servidor fallido como no disponible (err), en su lugar, se marcará comoinestable(aún disponible en el siguiente intento). El valor predeterminado estrue.-
cluster: Puedes configurar múltiples niveles según la prioridad del clúster, en cada nivel puedes configurar un clúster deservers. Las verificaciones intentarán el siguiente nivel solo cuando todos los servidores en el nivel anterior se consideren no disponibles.En lugar de intentar clústeres por niveles, puedes configurar las verificaciones para intentar clústeres por clave (ver el clúster
apiarriba). Recuerda que también debes pasar un argumento adicional comoopts.cluster_key={"dc1", "dc2"}oopts.cluster_key={3, 1, 2}a checkups.read_ok para que las verificaciones intenten en el orden dedc1,dc2onivel 3,nivel 1,nivel 2. Si no has pasadoopts.cluster_keya checkups.ready_ok, las verificaciones aún intentarán clústeres por niveles. En cuanto al clústerapianterior, las verificaciones eventualmente devolveránno servers available. *try: Conteo de reintentos. El valor predeterminado es el número de servidores. *try_timeout: Limita el tiempo durante el cual se puede responder a una solicitud, de manera similar aproxy_next_upstream_timeoutde nginx. *servers: La configuración paraserversse enumera a continuación, *weight: Establece el peso del servidor. El valor predeterminado es1. *max_fails: Establece el número de intentos fallidos para comunicarse con el servidor que deben ocurrir en la duración establecida por el parámetrofail_timeout. Por defecto, el número de intentos fallidos se establece en0, lo que desactiva el conteo de intentos. Lo que se considera un intento fallido se define porhttp_opts.statusessityp="http"o un valornil/falsedevuelto por checkups.ready_ok. Esta opción solo está disponible en round-robin. *fail_timeout: Establece el tiempo durante el cual el número especificado de intentos fallidos para comunicarse con el servidor debe ocurrir para considerar el servidor no disponible y el período de tiempo que el servidor será considerado no disponible. Por defecto, el parámetro se establece en10segundos. Esta opción solo está disponible en round-robin.upstream: Nombre de los bloques upstream de Nginx. Las verificaciones extraerán servidores de los bloques upstream de la configuración de Nginx en prepare_checker. Se requiere el módulo lua-upstream-nginx-module.upstream_only_backup: Si se establece entrue, las verificaciones solo extraerán servidores de respaldo de los bloques upstream de Nginx.
Configuración de Nginx
Agrega las rutas del archivo de configuración de lua y checkups a lua_package_path y crea diccionarios compartidos de lua utilizados por checkups. Debes poner estas líneas en el bloque http de tu archivo de configuración de Nginx.
lua_shared_dict state 10m;
lua_shared_dict mutex 1m;
lua_shared_dict locks 1m;
lua_shared_dict config 10m;
Si usas el subsistema de stream, debes poner estas líneas en el bloque stream de tu archivo de configuración de Nginx.
lua_shared_dict stream_state 10m;
lua_shared_dict stream_mutex 1m;
lua_shared_dict stream_locks 1m;
lua_shared_dict stream_config 10m;
API

init
sintaxis: init(config)
fase: init_by_lua
Copia los upstreams de config.lua a shdict, extrae servidores de los bloques upstream de Nginx y realiza algunas inicializaciones básicas.
prepare_checker
sintaxis: prepare_checker(config)
fase: init_worker_by_lua
Copia configuraciones de config.lua a los checkups del trabajador, extrae servidores de los bloques upstream de Nginx y realiza algunas inicializaciones básicas.
create_checker
sintaxis: create_checker()
fase: init_worker_by_lua
Crea un temporizador de latido y un temporizador de sincronización de upstream. Solo se creará un temporizador de latido entre todos los trabajadores. Se recomienda encarecidamente llamar a este método en la fase init_worker.
ready_ok
sintaxis: res, err = ready_ok(skey, callback, opts?)
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Selecciona un peer disponible del clúster skey y llama a callback(peer.host, peer.port, opts).
La tabla opts acepta los siguientes campos,
cluster_key: Intenta clústeres porcluster_key. Las verificaciones intentarán clústeres en el orden decluster_key.clusters_keypuede ser el nombre de los clústeres o el nivel de los clústeres. clústeres ej:{"cluster_name_A", "name_B", "name_C"}. niveles ej:{3, 2, 1}.hash_key: Clave utilizada en el modo de balanceohash. Si no se establece, se utilizarángx.var.uri.try: El reintento no será más detryveces.try_timeout: Limita el tiempo durante el cual se puede responder a una solicitud, de manera similar aproxy_next_upstream_timeoutde nginx.
Devuelve lo que callback devuelve en caso de éxito, o devuelve nil y una cadena que describe el error en caso contrario.
Si callback devuelve nil o false, las verificaciones lo considerarán un intento fallido y volverán a intentar callback con otro peer. Así que, recuerda siempre no devolver nil o false después de un callback exitoso.
select_peer
sintaxis: peer, err = select_peer(skey)
contexto: rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua
Selecciona un peer disponible del clúster skey.
Devuelve una tabla que contiene host y port de un peer disponible.
En caso de errores, devuelve nil con una cadena que describe el error.
get_status
sintaxis: status = get_status()
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Devuelve el estado de las verificaciones en formato json.
get_ups_timeout
sintaxis: connect_timeout, send_timeout, read_timeout = get_ups_timeout(skey)
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Devuelve el tiempo de espera del clúster skey.
feedback_status
sintaxis: ok, err = feedback_status(skey, host, port, failed)
contexto: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, balancer_by_lua.*
Marca el servidor host:port en el clúster skey como fallido (true) o disponible (false).
Devuelve 1 en caso de éxito, o devuelve nil y una cadena que describe el error en caso contrario.
update_upstream
sintaxis: ok, err = update_upstream(skey, upstream)
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Actualiza el clúster skey. upstream está en el mismo formato que cluster en config.lua.
Devuelve true en caso de éxito, o devuelve false y una cadena que describe el error en caso contrario.
delete_upstream
sintaxis: ok, err = delete_upstream(skey)
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Elimina el clúster skey de la lista de upstream.
Devuelve true en caso de éxito, o devuelve false y una cadena que describe el error en caso contrario.
Ver También
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-checkups.