checkups: Gerenciar upstreams do NGINX em Lua pura
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-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 com o NGINX, certifique-se de que o nginx-module-lua esteja instalado.
Este documento descreve lua-resty-checkups v0.1 lançado em 01 de fevereiro de 2019.
- Batimentos cardíacos periódicos para servidores upstream
- Verificação de saúde proativa e passiva
- Atualização dinâmica de upstream
- Balanceamento por round-robin ponderado ou hash consistente
- Sincronizar com blocos upstream do Nginx
- Tentar clusters por níveis ou por chaves
Sinopse
-- 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 um servidor inativo, nenhum upstream disponível
ok, err = checkups.ready_ok("ups1", callback)
if err then ngx.say(err) end
-- adicionar 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
-- adicionar servidor a novo 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
-- adicionar servidor a ups2, redefinir 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
}
}
}
Uma saída típica da localização /t definida acima é:
no servers available
12350
12350
12351
12350
12351
Configuração
Configuração Lua
O arquivo de configuração de checkups é um módulo lua que consiste em duas partes, a parte global e a parte do cluster.
Um exemplo de arquivo de configuração de checkups é mostrado abaixo,
-- config.lua
-- Aqui está a 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,
}
-- As partes restantes são configurações do cluster
_M.redis = {
enable = true,
typ = "redis",
timeout = 2,
read_timeout = 15,
send_timeout = 15,
protected = true,
cluster = {
{ -- nível 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 },
}
},
{ -- nível 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 = {
{ -- nível 1
upstream = "api.com",
},
{ -- nível 2
upstream = "api.com",
upstream_only_backup = true,
},
},
}
return _M
configurações globais
checkup_timer_interval: Intervalo de envio de batimentos cardíacos para servidores de backend. O padrão é5.checkup_timer_overtime: Intervalo de checkups para expirar a chave do timer. Na maioria dos casos, você não precisa alterar esse valor. O padrão é60.default_heartbeat_enable: Checkups enviarão batimentos cardíacos para servidores por padrão ou não. O padrão étrue.checkup_shd_sync_enable: Criar sincronizador de upstream para cada worker. Se definido comofalse, o upstream dinâmico não funcionará corretamente. O padrão étrue.shd_config_timer_interval: Intervalo de sincronização da lista de upstream da memória compartilhada. O padrão é igual acheckup_timer_interval.ups_status_sync_enable: Se definido comotrue, checkups sincronizarão o status do upstream de checkups para os blocos upstream do Nginx. O padrão éfalse.ups_status_timer_interval: Intervalo de sincronização do status do upstream de checkups para os blocos upstream do Nginx.
Configurações do Cluster
skey:_M.xxxxx.xxxxxé askey(chave de serviço) deste Cluster.enable: Habilitar ou desabilitar batimentos cardíacos para servidores. O padrão étrue.typ: Tipo de cluster, deve ser um dosgeneral,redis,mysql,http. O padrão égeneral.general: Batimento por TCPsock:connect.redis: Batimento por redisPING. O módulo lua-resty-redis é necessário.mysql: Batimento por mysqldb:connect. O módulo lua-resty-mysql é necessário.http: Batimento por requisição HTTP. Você pode configurar requisições HTTP personalizadas e códigos de resposta emhttp_opts.
timeout: Tempo limite de conexão com servidores upstream. O padrão é5.read_timeout: Tempo limite de leitura para servidores upstream (não utilizado durante o batimento). O padrão é igual atimeout.send_timeout: Tempo limite de escrita para servidores upstream (não utilizado durante o batimento). O padrão é igual atimeout.-
http_opts: Configurações de batimento HTTP. Funciona apenas paratyp="http".query: Requisição HTTP para batimento.statuses: Se o código retornado pelo servidor estiver definido comofalse, então o servidor é considerado como falhando.
-
mode: Modo de balanceamento. Pode ser definido comohash,url_hashouip_hash. Checkups irá balancear servidores porhash_key,ngx.var.urioungx.var.remote_addr. O padrão éwrr. protected: Se definido comotruee todos os servidores no cluster estiverem falhando, checkups não marcará o último servidor falhando como indisponível (err), em vez disso, será marcado comoinstável(ainda disponível na próxima tentativa). O padrão étrue.-
cluster: Você pode configurar múltiplos níveis de acordo com a prioridade do cluster, em cada nível você pode configurar um cluster deservers. Checkups tentará o próximo nível apenas quando todos os servidores no nível anterior forem considerados indisponíveis.Em vez de tentar clusters por níveis, você pode configurar checkups para tentar clusters por chave (veja o cluster
apiacima). Lembre-se de que você também deve passar um argumento extra comoopts.cluster_key={"dc1", "dc2"}ouopts.cluster_key={3, 1, 2}para checkups.read_ok para fazer checkups tentarem na ordem dedc1,dc2ounível 3,nível 1,nível 2. Se você não passaropts.cluster_keypara checkups.ready_ok, checkups ainda tentará clusters por níveis. Quanto ao clusterapiacima, checkups eventualmente retornaráno servers available. *try: Contagem de tentativas. O padrão é o número de servidores. *try_timeout: Limita o tempo durante o qual uma requisição pode ser respondida, assim comoproxy_next_upstream_timeoutdo nginx. *servers: A configuração paraserversé listada a seguir, *weight: Define o peso do servidor. O padrão é1. *max_fails: Define o número de tentativas malsucedidas de comunicação com o servidor que devem ocorrer durante o período definido pelo parâmetrofail_timeout. Por padrão, o número de tentativas malsucedidas é definido como0, o que desabilita a contagem de tentativas. O que é considerado uma tentativa malsucedida é definido porhttp_opts.statusessetyp="http"ou umnil/falseretornado por checkups.ready_ok. Esta opção está disponível apenas no round-robin. *fail_timeout: Define o tempo durante o qual o número especificado de tentativas malsucedidas de comunicação com o servidor deve ocorrer para considerar o servidor indisponível e o período de tempo que o servidor será considerado indisponível. Por padrão, o parâmetro é definido como10segundos. Esta opção está disponível apenas no round-robin.upstream: Nome dos blocos upstream do Nginx. Checkups irá extrair servidores dos blocos upstream da configuração do Nginx em prepare_checker. O módulo lua-upstream-nginx-module é necessário.upstream_only_backup: Se definido comotrue, checkups irá extrair apenas servidores de backup dos blocos upstream do Nginx.
Configuração do Nginx
Adicione os caminhos do arquivo de configuração lua e checkups ao lua_package_path e crie dicionários compartilhados lua usados por checkups. Você deve colocar essas linhas no bloco http do seu arquivo de configuração do Nginx.
lua_shared_dict state 10m;
lua_shared_dict mutex 1m;
lua_shared_dict locks 1m;
lua_shared_dict config 10m;
Se você usar o subsistema de stream, deve colocar essas linhas no bloco stream do seu arquivo de configuração do 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
sintaxe: init(config)
fase: init_by_lua
Copia upstreams de config.lua para shdict, extrai servidores dos blocos upstream do Nginx e faz algumas inicializações básicas.
prepare_checker
sintaxe: prepare_checker(config)
fase: init_worker_by_lua
Copia configurações de config.lua para os checkups do worker, extrai servidores dos blocos upstream do Nginx e faz algumas inicializações básicas.
create_checker
sintaxe: create_checker()
fase: init_worker_by_lua
Cria um timer de batimento e um timer de sincronização de upstream. Apenas um timer de batimento será criado entre todos os workers. É altamente recomendável chamar este método na fase init_worker.
ready_ok
sintaxe: res, err = ready_ok(skey, callback, opts?)
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Seleciona um peer disponível do cluster skey e chama callback(peer.host, peer.port, opts).
A tabela opts aceita os seguintes campos,
cluster_key: Tentar clusters porcluster_key. Checkups tentará clusters na ordem decluster_key.clusters_keypode ser o nome dos clusters ou o nível dos clusters. clusters ex:{"cluster_name_A", "name_B", "name_C"}. níveis ex:{3, 2, 1}.hash_key: Chave usada no modo de balanceamentohash. Se não definido,ngx.var.uriserá usado.try: A tentativa não será maior quetryvezes.try_timeout: Limita o tempo durante o qual uma requisição pode ser respondida, assim comoproxy_next_upstream_timeoutdo nginx.
Retorna o que callback retorna em caso de sucesso, ou retorna nil e uma string descrevendo o erro caso contrário.
Se callback retornar nil ou false, checkups considerará isso como uma tentativa falha e tentará novamente callback com outro peer. Portanto, sempre lembre-se de não retornar nil ou false após um callback bem-sucedido.
select_peer
sintaxe: peer, err = select_peer(skey)
contexto: rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua
Seleciona um peer disponível do cluster skey.
Retorna uma tabela contendo host e port de um peer disponível.
Em caso de erros, retorna nil com uma string descrevendo o erro.
get_status
sintaxe: status = get_status()
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Retorna o status dos checkups em formato json.
get_ups_timeout
sintaxe: connect_timeout, send_timeout, read_timeout = get_ups_timeout(skey)
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Retorna o tempo limite do cluster skey.
feedback_status
sintaxe: ok, err = feedback_status(skey, host, port, failed)
contexto: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, balancer_by_lua.*
Marca o servidor host:port no cluster skey como falhado (true) ou disponível (false).
Retorna 1 em caso de sucesso, ou retorna nil e uma string descrevendo o erro caso contrário.
update_upstream
sintaxe: ok, err = update_upstream(skey, upstream)
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Atualiza o cluster skey. upstream está no mesmo formato que cluster em config.lua.
Retorna true em caso de sucesso, ou retorna false e uma string descrevendo o erro caso contrário.
delete_upstream
sintaxe: ok, err = delete_upstream(skey)
fase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Deleta o cluster skey da lista de upstream.
Retorna true em caso de sucesso, ou retorna false e uma string descrevendo o erro caso contrário.
Veja Também
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório do GitHub para nginx-module-checkups.