O Orca, protocolo compatível com Redis no PolarDB for MySQL, oferece suporte a scripts Lua para executar múltiplos comandos atomicamente em uma única interação com o banco de dados. Use scripts Lua para implementar bloqueios distribuídos, limitadores de taxa e atualizações condicionais, eliminando a latência e os riscos de condições de corrida associados a múltiplas viagens de ida e volta na rede.
Pré-requisitos
Antes de começar, verifique se você tem:
Um cluster PolarDB executando MySQL 8.0.2 com versão secundária do mecanismo 8.0.2.2.33 ou posterior
Um ORCA Endpoint configurado com Read/Write definido como Read/Write (Automatic Read/Write Splitting)
Conceitos principais
Atomicidade — Todos os comandos em um script Lua são executados como uma unidade única e indivisível. Nenhum outro comando ou script pode interromper a execução, o que evita gravações parciais e estados intermediários.
Cache de scripts — Carregue um script uma única vez com SCRIPT LOAD para obter sua soma de verificação SHA1 e invoque-o repetidamente com EVALSHA usando apenas o valor curto do SHA1. Essa abordagem reduz o tráfego de rede em comparação ao envio do script completo a cada chamada.
Volatilidade do cache de scripts — O cache de scripts não é persistente. Ele é limpo após a reinicialização do cluster, um failover de alta disponibilidade (HA) ou uma chamada explícita a SCRIPT FLUSH. Projete sua aplicação para capturar erros NOSCRIPT e recarregar os scripts automaticamente.
Comandos
Todos os comandos de script Lua seguem a mesma convenção de parâmetros: passe nomes de chaves por meio de KEYS[] e outros argumentos por meio de ARGV[]. Os índices dos arrays começam em 1.
Para a especificação completa do Redis, consulte Scripting with Lua e EVAL command reference no redis.io.
|
Comando |
Sintaxe |
Descrição |
|
|
|
|
Executa um script Lua diretamente. |
|
|
|
|
Executa um script Lua em modo somente leitura. Retorna um erro se o script contiver comandos de escrita. Ideal para cenários de divisão de leitura e escrita. |
|
|
|
|
Executa um script armazenado em cache usando sua soma de verificação SHA1. Retorna um erro |
|
|
|
|
Executa um script em cache no modo somente leitura. Possui o mesmo comportamento do |
|
|
|
|
Carrega um script no cache e retorna sua soma de verificação SHA1. Utilize essa soma de verificação com |
|
|
|
|
Verifica se os scripts estão em cache. Retorna |
|
|
|
|
Encerra o script em execução no momento. O Orca reverte automaticamente quaisquer alterações de dados feitas pelo script, incluindo scripts de escrita. |
|
|
|
|
SYNC]` |
Limpa todos os scripts Lua em cache do cluster. A opção |
Comandos não suportados
Os seguintes comandos não podem ser chamados dentro de um script Lua usando redis.call() ou redis.pcall():
Controle de transações:
WATCH,UNWATCH,MULTI,EXEC,DISCARDComandos de bloqueio:
BLPOP,BRPOPComandos de script Lua:
EVAL,EVAL_RO,EVALSHA,EVALSHA_RO,SCRIPTComandos Pub/Sub:
SUBSCRIBE,UNSUBSCRIBE,PSUBSCRIBE,PUNSUBSCRIBEGerenciamento de conexões:
AUTH,HELLO,CLIENT
Chamar qualquer um desses comandos retorna um erro imediatamente.
Início rápido
Os exemplos a seguir usam a chave de teste definida por SET polardb orca.
EVAL
EVAL — Execute um script diretamente:
EVAL "return redis.call('GET', KEYS[1])" 1 polardb
Saída:
"orca"
SCRIPT LOAD
SCRIPT LOAD — Armazene um script em cache e obtenha sua soma de verificação SHA1:
SCRIPT LOAD "return redis.call('GET', KEYS[1])"
Saída:
"d3c21d0c2b9ca22f82737626a27bcaf5d288f99f"
EVALSHA
EVALSHA — Execute o script em cache usando sua soma de verificação SHA1:
EVALSHA d3c21d0c2b9ca22f82737626a27bcaf5d288f99f 1 polardb
Saída:
"orca"
SCRIPT EXISTS
SCRIPT EXISTS — Verifique se os scripts estão no cache (o primeiro SHA1 existe, o segundo não):
SCRIPT EXISTS d3c21d0c2b9ca22f82737626a27bcaf5d288f99f ffffffffffffffffffffffffffffffffffffffff
Saída:
1) (integer) 1
2) (integer) 0
Cenários comuns
Implementar um contador atômico
Use scripts Lua para evitar condições de corrida causadas por operações INCR simultâneas. O padrão SCRIPT LOAD + EVALSHA evita o envio do conteúdo do script pela rede nas chamadas subsequentes, reduzindo o tráfego e melhorando o throughput.
1. Escreva o script e salve-o localmente:
-- counter.lua
-- Initialize the key to 0 if it does not exist, then increment by 1.
if redis.call('EXISTS', KEYS[1]) == 0 then
redis.call('SET', KEYS[1], 0)
end
return redis.call('INCR', KEYS[1])
2. Carregue o script para obter sua soma de verificação SHA1:
SCRIPT LOAD "if redis.call('EXISTS', KEYS[1]) == 0 then redis.call('SET', KEYS[1], 0) end return redis.call('INCR', KEYS[1])"
Saída:
"b547eabbcde73b25330442e4f4e4dc1783b91241"
3. Execute o script usando sua soma de verificação SHA1:
EVALSHA b547eabbcde73b25330442e4f4e4dc1783b91241 1 my_counter
Saída na primeira chamada:
(integer) 1
Saída na segunda chamada:
(integer) 2
Executar um script somente leitura
Use EVAL_RO ou EVALSHA_RO para garantir que um script não realize operações de escrita. Isso é útil em cenários de divisão de leitura e escrita, onde os scripts devem acessar apenas réplicas de leitura.
Antes de usar EVAL_RO, confirme se o seu script não chama comandos de escrita como SET, DEL, HSET ou LPUSH. Caso contrário, use EVAL.
EVAL_RO "return {redis.call('GET', KEYS[1]), redis.call('TTL', KEYS[1])}" 1 polardb
Saída:
1) "orca"
2) (integer) -1
Se o script contiver comandos de escrita, EVAL_RO retornará (error) ERR Write commands are not allowed from read-only scripts.
Interromper um script de longa duração
Se um script demorar mais do que o esperado e bloquear o cluster, encerre-o com SCRIPT KILL. O Orca reverte automaticamente todas as alterações feitas pelo script.
SCRIPT KILL
Saída:
OK
O comando SCRIPT KILL encerra apenas o script em execução no momento. Não é possível direcionar um script específico pelo SHA1.
Melhores práticas
Usar SCRIPT LOAD + EVALSHA para cargas de trabalho de produção
Todos os exemplos abaixo usam SCRIPT LOAD na inicialização para armazenar scripts em cache e, em seguida, EVALSHA para cada chamada subsequente. Esse padrão evita a retransmissão do script completo a cada solicitação.
1. Carregue o script durante a inicialização da aplicação:
# Cache a script that sets a key's value
SCRIPT LOAD "return redis.call('set', KEYS[1], ARGV[1])"
Saída:
"55b22c0d0cedf3866879ce7c854970626dcef0c3"
Armazene esse valor SHA1 em sua aplicação.
2. Execute o script usando o SHA1 em cache:
# Set k1 = v1
EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k1 v1
# Set k2 = v2 using the same cached script
EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k2 v2
3. Trate erros NOSCRIPT:
Se EVALSHA retornar um erro NOSCRIPT, significa que o script não está mais no cache. Mude para EVAL ou SCRIPT LOAD para executar e armazenar o script novamente no cache e, depois, retome o uso de EVALSHA.
Parametrizar scripts com KEYS[] e ARGV[]
Passe todos os dados variáveis por meio de KEYS[] e ARGV[] em vez de codificar valores fixos no corpo do script. Scripts com valores fixos são strings únicas — cada variação gera uma entrada de cache separada, o que aumenta o uso de memória e anula os benefícios do cache.
O exemplo a seguir mostra o antipadrão e a abordagem correta:
-- Anti-pattern: each hard-coded variant creates a separate cache entry
EVAL "return 'Hello'" 0
EVAL "return 'Scripting!'" 0
-- Correct: one parameterized script reuses the same cache entry for any value
EVAL "return ARGV[1]" 0 Hello
EVAL "return ARGV[1]" 0 Scripting!
Manter scripts curtos e rápidos
Scripts Lua são executados atomicamente e bloqueiam todos os outros comandos durante a execução. Scripts de longa duração ou com grandes lotes de processamento aumentam a latência do cluster para todos os outros clientes.
Evite loops complexos ou travessias de dados em grande escala dentro dos scripts.
O tempo limite padrão de execução é de 300 segundos. Um script que excede esse limite indica a necessidade de simplificar a lógica.
Divida operações complexas em vários scripts menores em vez de usar um único script grande.
Limpar o cache de scripts com segurança
Use SCRIPT FLUSH para remover todos os scripts em cache. Após a limpeza, qualquer chamada para EVALSHA ou EVALSHA_RO retornará um erro NOSCRIPT até que os scripts sejam recarregados.
Em clusters com muitos scripts em cache, SCRIPT FLUSH pode bloquear o cluster por um período prolongado. Execute este comando fora dos horários de pico.
SCRIPT FLUSH
Saída:
OK
Mantenha o source dos scripts em sua aplicação e implemente recuperação automática para erros NOSCRIPT. Em caso de erro, recarregue o script com SCRIPT LOAD ou registre-o novamente com EVAL.
Perguntas frequentes
Como corrigir NOSCRIPT No matching script. Please use EVAL.?
O script não está mais no cache do cluster. Isso ocorre após uma reinicialização do cluster, um failover de HA ou uma chamada a SCRIPT FLUSH. No seu cliente, capture erros NOSCRIPT e use EVAL ou SCRIPT LOAD como alternativa para registrar o script novamente. Após o novo registro, as chamadas EVALSHA voltarão a funcionar normalmente.
O que fazer quando um script atinge o tempo limite?
O tempo limite padrão é de 300 segundos. Geralmente, isso indica que a lógica do script é muito complexa ou processa dados demais. Para recuperar, execute SCRIPT KILL — o PolarDB reverterá todas as alterações feitas pelo script. Para evitar reincidência, otimize o script evitando loops ineficientes ou leituras massivas de dados, ou divida a lógica em vários scripts menores.
Por que EVAL_RO retorna ERR Write commands are not allowed from read-only scripts.?
EVAL_RO e EVALSHA_RO proíbem todas as operações de escrita. Verifique se o script contém comandos de escrita como SET, HSET ou DEL e remova-os. Se o script precisar gravar dados, use EVAL ou EVALSHA em vez disso.