Gli script Lua di Redis eseguono in modo isolato sul server una serie di comandi Redis, comprese le condizioni. In questo modo si evita che altri client causino stati intermedi contraddittori tra la lettura, la verifica e la scrittura. In questo contesto, “atomico” non significa “rollback automatico”: Gli input e i percorsi di errore devono essere progettati con attenzione, soprattutto prima delle operazioni di scrittura. Sono fondamentali chiavi dichiarate in modo chiaro, valori di ritorno stabili, tempi di esecuzione brevi e un modello adeguato – dal comando nativo alla funzione Redis.
Classificare gli script Lua di Redis atomici
Gli script Lua di Redis eseguono la logica di elaborazione dei dati direttamente nel server Redis. Mentre uno script è in esecuzione, Redis non elabora altre attività del server; i comandi in esso contenuti sono quindi isolati rispetto agli altri client. Ciò consente di combinare più comandi semplici in un unico operazione atomica collegare, ad esempio, una verifica dei limiti seguita dall’aggiornamento del contatore o un addebito solo in presenza di credito sufficiente.
Senza uno script, un client può inizialmente leggere un contatore con un GET, verificare il limite nel codice dell’applicazione e quindi inviare un INCR. Tra questi passaggi, tuttavia, un altro client potrebbe modificare lo stesso contatore. Uno script, invece, legge, verifica e incrementa senza questo stato intermedio osservabile. Ciò risolve la condizione di competizione della regola composta, ma non risolve automaticamente questioni quali i valori limite appropriati, i tempi di esecuzione o i formati di restituzione.
"Radicale e isolato" non significa che Script Lua di Redis Le transazioni del database prevedono il rollback automatico. Se, dopo che un’operazione di scrittura è già stata eseguita, si verifica un errore di esecuzione, le modifiche precedenti non vengono annullate in blocco. Per questo motivo, gli script dovrebbero verificare gli input, i tipi di dati e i prerequisiti funzionali prima della prima scrittura; i percorsi di errore successivi alle modifiche richiedono una gestione appositamente progettata.
Le regole tipiche sono: consentire un accesso solo entro un determinato limite o ridurre una quantità solo se disponibile in misura sufficiente. Verifica innanzitutto se un singolo comando Redis esistente esprima già l'intera regola. Uno script è utile quando diverse operazioni Redis, comprese le relative condizioni, devono interagire in modo atomico.
Un modello Lua per l'operazione "confronta e cancella" confronta il valore memorizzato con un token di proprietà fornito e cancella solo in caso di corrispondenza. In questo modo, un processo in ritardo non può cancellare una chiave che nel frattempo è stata riassegnata solo perché possiede un token obsoleto.
Questo modello di riferimento descrive esclusivamente la sequenza sicura per una singola chiave Redis. Non risolve le questioni più ampie relative ai blocchi distribuiti, quali le durate appropriate dei lease, le pause dei processi, i guasti o il coordinamento di più istanze Redis. L’atomicità di un comando o di uno script riguarda inoltre solo i dati Redis coinvolti, non il pagamento, il database, l’e-mail o le API esterne.
Lua Sandbox e limiti ben definiti
Redis Open Source integra Lua 5.1 per gli script. Questo runtime non è equiparabile a una versione principale di Lua installata localmente o aggiornata: sono Redis a determinare le funzionalità linguistiche disponibili e le regole di sicurezza. Chi sviluppa script Lua per Redis dovrebbe quindi verificarli rispetto alla versione di Redis effettivamente in uso e non dare per scontate le caratteristiche di un ambiente Lua esterno qualsiasi.
La realizzazione avviene in una Sandbox con limiti volutamente ristretti. Uno script deve elaborare i dati Redis e gli argomenti passati, ma non deve utilizzare né il file system, né la rete, né i servizi del sistema operativo. Le chiamate HTTP esterne, l’invio di messaggi o l’accesso ai file locali devono quindi essere gestiti nel codice dell’applicazione o in un servizio dedicato, non tramite lo scripting della cache.
Redis offre KEYS e ARGV come variabili di ambito globale. Per i valori intermedi e le funzioni ausiliarie personalizzate, invece, utilizza variabili locali con local. In questo modo è possibile distinguere quali valori si applicano solo a questa chiamata e la logica dello script non genera dipendenze evitabili. I comandi Redis vanno chiamati in modo mirato tramite redis.call oppure redis.pcall su.
La sandbox non sostituisce la pianificazione delle capacità. Durante l’esecuzione regolare, uno script blocca gli altri client sul server; pertanto, i cicli lunghi, i volumi di dati illimitati e le elaborazioni ad alta intensità di calcolo non sono adatti. Limita il lavoro a poche chiavi note in anticipo e a calcoli di piccola entità. Analisi approfondite, inventari completi basati su SCAN o la comunicazione con sistemi esterni aumenterebbero i rischi operativi senza ampliare in modo significativo l'atomicità.
Comprendere EVAL, KEYS e ARGV
Per eseguire direttamente uno script si utilizza il formato EVAL script numkeys [key …] [arg …]. Secondo il codice sorgente, `numkeys` determina quanti dei parametri successivi sono chiavi. Lo script li raggiunge tramite KEYS con indicizzazione a partire da 1; tutti gli altri valori si trovano in ARGV. Questa distinzione è fondamentale: le chiavi descrivono i dati Redis, mentre gli argomenti descrivono gli input specifici come il valore limite, l’importo o il token previsto.
Uno script di limite, ad esempio, riceve il contatore come KEYS[1] e il valore massimo come ARGV[1]. Legge il valore attuale, converte il valore limite con tonumber(ARGV[1]) lo converte in un numero e confronta entrambi i valori prima di aumentarlo. La conversione rende esplicita la regola numerica prevista, invece di affidarsi a un trattamento implicito dei valori degli argomenti. Se manca un contatore, lo script può trattare in modo mirato il valore letto come zero.
Ogni chiave che lo script legge o scrive deve essere specificata in anticipo come argomento della chiave. Comporre i nomi delle chiavi nello script utilizzando prefissi o ricavandoli da dati memorizzati non è una pratica affidabile. Redis, in particolare nella versione open source con il cluster attivato, non è in grado di determinare prima dell’esecuzione di quali dati abbia bisogno lo script. Pertanto, si raccomanda di passare le chiavi note per esteso tramite KEYS e i valori variabili esclusivamente tramite ARGV.
In Redis Open Source con il cluster abilitato, le chiavi passate a uno script devono inoltre trovarsi nello stesso hash slot. La dichiarazione precedente consente di effettuare questa verifica, ma non la sostituisce. Per i dati correlati, può essere utile un hash tag scelto appositamente, ad esempio account:{4711}:balance e account:{4711}:reservations. La parte tra parentesi graffe determina in questo caso l'assegnazione degli slot; le chiavi determinate dinamicamente vanificherebbero questa pianificazione.
Aggiornamento atomico dei contatori a finestra fissa
L'esempio seguente è un Contatore a finestra fissa per un'istanza di test locale. Verifica il valore del contatore e il limite in un'unica esecuzione sul server e imposta il tempo di scadenza solo al primo accesso riuscito all'interno della finestra temporale. In questo modo si elimina la finestra temporale tra un comando GET nel codice dell'applicazione e un successivo comando INCR, durante la quale un altro client potrebbe modificare il contatore.
La chiamata passa la chiave del contatore, il limite e la durata della finestra in secondi. Lo stato 1 indica che l'operazione è stata approvata, lo stato 0 indica che il limite è stato raggiunto. Lo stato 2 segnala un input non valido rilevato dai controlli preliminari, un valore del contatore stringa rifiutato in tale fase o un contatore stringa esistente senza TTL. Se la chiave contiene un altro tipo di dati Redis, il comando GET fallisce già con un errore tecnico di tipo; lo script non restituisce quindi lo stato 2. Anche altri errori di runtime di Redis devono essere distinti dallo stato di ritorno funzionale. L’esempio non costituisce un modello per dati di accesso, limiti di produzione o test di carico.
Prima di ogni operazione di scrittura, lo script verifica che tutti i numeri siano interi positivi finiti entro un limite massimo volutamente basso. Si tratta di qualcosa di più di una semplice verifica con tonumber: Valori come 1.5 oppure 1e3 vengono rifiutati. Il limite di un milione impedisce inoltre che la precisione numerica di Lua o quella di INCR la stringa intera prevista diventa rilevante al di fuori dell'ambito dell'esempio. La durata massima della finestra, pari a 86.400 secondi, limita anche il EXPIRE numero di secondi trasmesso.
L'espressione regolare accetta solo cifre decimali; successivamente, la funzione ausiliaria verifica il valore numerico, la natura intera e il limite massimo. Un contatore già esistente deve essere un numero intero non negativo compreso nello stesso intervallo limitato. In questo modo, un valore negativo, frazionario o eccessivamente grande non può alterare la semantica dei limiti senza che ciò venga rilevato. Solo dopo queste verifiche segue INCR.
Se la chiave non è presente, lo script parte da 0. Se esiste già un contatore di stringhe valido senza scadenza, restituisce lo stato 2 e non scrive nulla. Dopo il primo INCR set EXPIRE il TTL, precedentemente verificato integralmente. In caso di riscontri successivi, esso rimane invariato, in modo che la finestra non venga estesa continuamente.
Il sito Contratto di restituzione fa parte dell'interfaccia: il primo elemento dell'array descrive lo stato, il secondo fornisce, a seconda dello stato, il valore del contatore o un codice di errore. Il codice chiamante dovrebbe trattare un rifiuto tecnico con stato 0 in modo diverso rispetto allo stato 2, che indica una condizione preliminare non soddisfatta. Per ulteriori informazioni sulla scelta e il monitoraggio dei tempi di esecuzione, si veda l’articolo Analisi e ottimizzazione della scadenza delle chiavi Redis una base integrativa.
Il TTL viene impostato qui intenzionalmente solo al primo accesso. Un modello che lo aggiornasse ad ogni accesso avrebbe una semantica temporale diversa e non sarebbe più una "fixed window". Atomicità di Lua Elimina solo la race condition. Che sia il Fixed Window, lo Sliding Window o il Token Bucket a garantire l'equità e la distribuzione del carico desiderate, dipende dall'algoritmo scelto, non dal linguaggio di scripting.
Selezionare il modello di atomicità appropriato
Non tutti i requisiti composti richiedono uno script. Se esiste un singolo comando Redis che esprime già completamente la regola di business, di solito è più semplice da gestire e da verificare. Per le regole a più livelli, invece, è necessario considerare congiuntamente condizioni, tipi di dati e contratto di restituzione.
A partire dalla versione 8.4 di Redis Open Source sono disponibili operazioni native "Compare-and-Set" e "Compare-and-Delete" per singole chiavi di tipo stringa: SET supporta le opzioni di confronto IFEQ/IFNE/IFDEQ/IFDNE; DELEX gestisce la cancellazione condizionata. Per i casi specifici relativi a singole chiavi, non è quindi necessario uno script di confronto dedicato. In Redis 8.2, 8.0 e 7.x queste nuove opzioni SET e DELEX non sono disponibili; in tali versioni rimangono rilevanti i modelli WATCH o Lua appropriati.
Per un "Compare-and-Set" ottimistico, WATCH può essere appropriato prima di MULTI ed EXEC: se una chiave monitorata viene modificata prima di EXEC, la transazione viene interrotta e il client decide se effettuare un nuovo tentativo. Inoltre, in caso di errori durante l’esecuzione di EXEC, le transazioni non prevedono un rollback generale. WATCH rimane quindi un’opzione valida quando la condizione richiesta non può essere soddisfatta da un singolo comando nativo.
| Modello | Caso d'uso appropriato | Codice e chiamata | Dopo il riavvio o il failover | Comportamento del client e limiti |
|---|---|---|---|---|
| Comando nativo | Un'operazione singola esistente rappresenta la regola | Nessun codice di programma; comando diretto | Nessuna cache degli script è interessata | Nessun ricaricamento dello script; limitato alla semantica esistente |
| CAS/CAD nativo a partire da Redis Open Source 8.4 | Impostazione o cancellazione di una singola chiave stringa in base al valore | SET con IFEQ/IFNE/IFDEQ/IFDNE; DELEX con condizione di confronto | Nessuna cache degli script è interessata | Verificare il limite di versione e la condizione di confronto; nessuna regola composta con più chiavi |
| MULTI/EXEC con WATCH | Lettura, verifica e scrittura ottimistiche | WATCH, MULTI, EXEC | Nessuna memoria di programma | In caso di modifiche prima di EXEC, rileggere e decidere nuovamente; nessun rollback in caso di errori EXEC |
| EVAL | Piccolo script eseguito direttamente | Codice sorgente per ogni EVAL | La cache degli script non è permanente | Nessun ricaricamento del digest; il codice sorgente viene ritrasmesso |
| SCRIPT LOAD più EVALSHA | Script riutilizzato con digest noto | Caricamento, seguito da richiamo tramite digest SHA1 | La cache potrebbe mancare | Gestire NOSCRIPT e ricaricare la pagina; pianificare con particolare attenzione il fallback della pipeline |
| Funzioni Redis a partire dalla versione 7.0 | Logica dei dati denominata e riutilizzabile | FUNCTION LOAD, seguito da FCALL | Le librerie vengono replicate e salvate in modo permanente | È necessario un processo di versione e distribuzione; non confondere con EVAL |
Gli script EVAL sono associati alla cache degli script e ricevono i propri input tramite KEYS e ARGV. Funzioni Redis A partire da Redis 7.0 sono disponibili come librerie denominate: vengono registrate con FUNCTION LOAD, richiamate con FCALL e, insieme al database, salvate in modo persistente e replicate. Le loro chiavi e i loro argomenti vengono passati alla funzione come parametri; ne consegue un modello di distribuzione e di chiamata diverso rispetto a quello di EVAL.
Per la logica di piccole dimensioni orientata alle applicazioni, EVAL rappresenta quindi un punto di partenza immediato. La presenza di più client e una logica dei dati gestita a lungo termine spesso giustificano l’uso delle funzioni, a condizione che la versione open source di Redis utilizzata le supporti. La decisione dovrebbe inoltre tenere conto del deployment, delle autorizzazioni, della gestione degli errori e di un ritorno chiaramente documentato, non solo del numero di comandi Redis.
Cluster, errori e contratti di restituzione
In Redis Open Source con il cluster attivato, le chiavi passate in uno script a più chiavi devono trovarsi nello stesso slot di hash. Gli hash tag consentono di controllare questo aspetto: in account:{4711}:balance e account:{4711}:reservations Il contenuto tra parentesi graffe determina lo slot. Entrambe le chiavi possono quindi essere indirizzate contemporaneamente. Il requisito dello stesso slot si applica anche alle operazioni con più chiavi e alle transazioni MULTI/EXEC qui considerate. Altre configurazioni di prodotto e di cluster possono differire per singoli comandi. Da ciò non deriva alcuna autorizzazione generale cross-slot per Lua: la documentazione relativa alle chiavi multiple classifica EVAL/EVALSHA come operazioni a slot singolo anche nel caso di Redis Software con cluster attivato e con o senza OSS Cluster API.
Tutte le chiavi utilizzate devono essere dichiarate come argomenti “key” prima della chiamata. Uno script non deve ricavare i nomi delle chiavi da valori memorizzati né comporli dinamicamente. Questa regola consente a Redis di eseguire una corretta verifica degli slot prima dell'esecuzione e impedisce dipendenze nascoste che, pur passando inosservate in un'istanza standalone, causerebbero un errore in Redis Open Source con il cluster attivato.
Con redis.call() un errore del comando Redis eseguito viene segnalato al client come errore di script. redis.pcall() Lo restituisce invece a Lua, in modo che lo script possa gestirlo in modo mirato. pcall ha senso solo se è definita una reazione specifica, ad esempio una risposta di errore ben strutturata o un flusso alternativo ammissibile. Ignorare silenziosamente gli errori nasconde problemi relativi ai dati e all'integrità.
A Contratto viziato distingue gli errori tecnici dai risultati funzionali. WRONGTYPE significa, ad esempio, che il tipo di dati Redis memorizzato non corrisponde al comando previsto e deve essere verificato. Una prenotazione rifiutata a causa della mancanza di disponibilità, invece, è un risultato atteso e può restituire, ad esempio, lo stato e la disponibilità residua. Le applicazioni non dovrebbero trattare queste categorie allo stesso modo né ripeterle entrambe in modo indiscriminato.
Gestire in modo affidabile la distribuzione degli script
EVAL è adatto per le chiamate dirette: il client trasmette il codice sorgente Lua completo insieme ai valori delle chiavi e degli argomenti. Per uno script utilizzato frequentemente e immutato, l’applicazione può invece utilizzarlo con SCRIPT LOAD caricare nella cache degli script. Redis restituisce un digest SHA1 a tale scopo; EVALSHA Esegue quindi esattamente il codice sorgente corrispondente. Ciò evita la trasmissione ripetuta, ma non modifica né l'atomicità né la responsabilità tecnica dello script.
Il sito Cache degli script non è permanente. Dopo un riavvio, un failover o SCRIPT FLUSH è possibile effettuare una chiamata tramite digest con NOSCRIPT fallire. L'applicazione dovrebbe gestire regolarmente questo caso: ricaricare lo script e ripetere la chiamata correttamente eseguita, purché la propria logica di riprova lo consenta. Un digest non deve quindi essere interpretato come una garanzia che lo script sia già presente su ogni server di destinazione.
Nel caso delle pipeline, questa opzione di ripiego è limitata. Se sono già stati inviati più comandi insieme, l'applicazione può riscontrare un NOSCRIPT- Non sostituire gli errori in modo retroattivo caricando e rieseguendo il codice nello stesso punto. Redis raccomanda, in questi casi, di utilizzare EVAL come strategia alternativa. Chi pianifica la replica e il failover dovrebbe inoltre comprendere quale ruolo svolga il buffer di replica nel ricollegamento di una replica: Comprendere il backlog di replica di Redis.
I valori variabili non devono essere inseriti nel codice sorgente Lua, ma in ARGV. Altrimenti, ogni valore limite genererebbe uno script diverso, aumentando inutilmente la cache. A partire da Redis 7.4 è possibile, tramite EVAL oppure EVAL_RO gli script caricati vengano rimossi al raggiungimento del limite della cache secondo l'algoritmo LRU; ciò non sostituisce né la parametrizzazione né la gestione di NOSCRIPT.
Padroneggiare script lunghi ed errori di ortografia
Uno script Lua blocca altre attività del server durante la sua esecuzione normale. Ciò garantisce l'isolamento, ma in caso di tempi di esecuzione prolungati diventa un Rischio operativo. Se uno script supera il limite configurato busy-reply-threshold, Redis risponde ai comandi normali con BUSY; non termina automaticamente lo script. Limita quindi gli script a poche chiavi note e a calcoli semplici e limitati.
Le operazioni di scrittura che precedono un errore o un ciclo infinito sono particolarmente critiche. Se uno script ha già modificato i dati, è possibile che SCRIPT KILL non terminare in modo sicuro. Controlla quindi i dati inseriti prima della prima scrittura ed evita i cicli illimitati, nonché SCAN sulle scorte complessive. I test dovrebbero riprodurre i volumi di dati e i percorsi di errore previsti per l'implementazione.
| Caso | Risposta evidente | Causa tipica | Coerenza sicura |
|---|---|---|---|
| NOSCRIPT | Messaggio di errore NOSCRIPT | Il digest non è presente nella cache temporanea degli script | Caricare lo script oppure utilizzare EVAL con parametri; ripetere solo in base alla propria regola di riprova. |
| CROSSSLOT | CROSSSLOT su Redis Open Source con il cluster attivato | Le chiavi passate allo script si trovano in diversi slot di hash | Modificare il design delle chiavi e dichiarare tutte le chiavi necessarie. |
| WRONGTYPE | Errore Redis WRONGTYPE | Key ha un tipo di dati inaspettato | Correggere il modello di dati o i prerequisiti dello script; non considerarlo un rifiuto di natura tecnica. |
| Pressione di memoria tramite maxmemory | L'operazione di scrittura può interrompere lo script | All'avvio, Redis supera già il limite di memoria | Non limitarsi a ripetere ciecamente; per redis.pcall prevedere un percorso di gestione degli errori sicuro e documentato. |
| OCCUPATO | Risposta di errore “BUSY” per altri comandi | Lo script supera la soglia di risposta di occupato (busy-reply-threshold) | Ridurre il carico e alleggerire lo script; non fare affidamento su "kill" dopo le operazioni di scrittura. |
| Rifiuto tecnico | Valore di stato documentato | Ad esempio: limite raggiunto o saldo insufficiente | Valutare lo stato e rifiutare l'operazione in modo ordinato. |
All'indirizzo maxmemory il processo dipende dalla prima operazione di scrittura. Se Redis ha già superato il limite, un comando che richiede molta memoria può, in caso di redis.call interrompere lo script; redis.pcall restituisce l'errore a Lua e richiede un percorso di gestione degli errori appositamente progettato. Le modifiche già apportate non vengono quindi ripristinate.
Un'operazione iniziale che non richiede memoria aggiuntiva, ad esempio DEL oppure LREM, lo script può invece continuare a funzionare; le operazioni di scrittura successive possono aumentare il consumo tramite maxmemory aumentare. Errori tecnici quali WRONGTYPE oppure CROSSSLOT In Redis Open Source con il cluster attivato, le correzioni al modello di dati o alla struttura delle chiavi richiedono un'approvazione, mentre solo lo script stesso può definire un rifiuto tecnico come stato stabile.
Scegliere consapevolmente i casi d'uso appropriati
Per una prenotazione condizionata, uno script può verificare la disponibilità, rifiutare un valore troppo basso e, in caso di esito positivo, restituire la disponibilità residua. La Prenotazione atomica comprende tuttavia solo Redis. Il pagamento, il database relazionale, la posta elettronica e le API esterne richiedono un coordinamento specifico e, se necessario, una logica di compensazione.
La scelta dipende dalla versione di Redis e dal modello di dati. A partire da Redis Open Source 8.4, le opzioni di confronto di SET un'impostazione condizionata e DELEX eseguire il confronto e l’eliminazione di una singola chiave di tipo stringa. Prima di Redis 8.4 o in caso di condizioni più complesse, è necessario WATCH con MULTI/EXEC Un'alternativa: se una chiave monitorata cambia prima di EXEC, la transazione viene interrotta e il client decide se rileggere e ripetere l'operazione. Uno script Lua breve è sufficiente quando più comandi o strutture di dati, comprese le relative regole di business, devono interagire lato server.
Per i blocchi distribuiti, né il singolo comando né il modello Lua sono sufficienti come approccio globale. La durata del lease, le pause di processo, i guasti, le ripetizioni, il failover e gli scenari multi-istanza devono essere valutati separatamente. È preferibile utilizzare un comando nativo se la versione in uso e la sua semantica coprono l'intera regola. In caso contrario, sono WATCH e valutare l'utilizzo di uno script breve a seconda del contratto di errore e della posizione della logica di business. Per la logica lato server riutilizzabile, una funzione Redis potrebbe essere la soluzione adatta. Script di sola lettura A partire da Redis 7.0 è possibile utilizzare EVAL_RO oppure EVALSHA_RO funzionano, ma solo se la logica è garantita come priva di operazioni di scrittura.
Fonti e stato dell'arte
Stato della ricerca:
Data di ricerca e versione: 23 settembre 2026. L'articolo tratta di Redis Open Source e distingue gli script EVAL dalle funzioni Redis a partire dalla versione 7.0 di Redis. Prima dell'utilizzo, verificare i limiti di versione e i comandi disponibili rispetto alla versione di Redis effettivamente in uso.
https://redis.io/docs/latest/develop/programmability/eval-intro/
https://redis.io/docs/latest/develop/programmability/
https://redis.io/docs/latest/commands/eval/
https://redis.io/docs/latest/develop/using-commands/multi-key-operations/
https://redis.io/docs/latest/develop/using-commands/transactions/
https://redis.io/docs/latest/develop/programmability/functions-intro/
https://redis.io/docs/latest/commands/evalsha_ro/




