Les scripts Lua Redis exécutent plusieurs commandes Redis, y compris des conditions, de manière isolée sur le serveur. Cela permet d'éviter toute incohérence dans l'état intermédiaire entre la lecture, la vérification et l'écriture, due à d'autres clients. Dans ce contexte, « atomique » ne signifie pas « restauration automatique ».: Les entrées et les chemins d'erreur doivent avant tout être conçus de manière réfléchie avant toute opération d'écriture. Il est essentiel de disposer de clés clairement déclarées, de valeurs de retour stables, de durées d'exécution courtes et d'un modèle adapté – de la commande native à la fonction Redis.
Classer les scripts Lua Redis de manière atomique
Les scripts Lua de Redis exécutent la logique métier directement sur le serveur Redis. Pendant l'exécution d'un script, Redis ne traite aucune autre activité du serveur ; les commandes qu'il contient sont donc isolées des autres clients. Cela permet de regrouper plusieurs commandes simples en une seule opération atomique combiner, par exemple, une vérification de limite suivie d'une mise à jour du compteur ou un prélèvement uniquement si le solde est suffisant.
Sans script, un client peut d'abord lire un compteur à l'aide d'une requête GET, vérifier la limite dans le code de l'application, puis envoyer une requête INCR. Entre ces étapes, un autre client peut toutefois modifier ce même compteur. Un script, en revanche, lit, vérifie et incrémente le compteur sans passer par cet état intermédiaire observable. Cela résout la condition de concurrence de la règle composite, mais ne résout pas automatiquement les questions relatives aux limites appropriées, aux délais d'exécution ou aux formats de retour.
« Atomique » et « isolé » ne signifient pas que Scripts Lua Redis Les transactions de base de données comportent un rollback automatique. Si une erreur d'exécution survient après qu'une opération d'écriture a déjà été effectuée, les modifications précédentes ne sont pas systématiquement annulées. C'est pourquoi les scripts doivent vérifier les entrées, les types de données et les contraintes métier avant la première écriture ; les scénarios d'erreur survenant après des modifications nécessitent une gestion soigneusement conçue.
Voici quelques règles typiques : n'autoriser un accès que dans une certaine limite ou ne réduire un stock que si la quantité disponible est suffisante. Vérifie d'abord si une commande Redis existante exprime déjà l'intégralité de la règle. Un script est utile lorsque plusieurs opérations Redis, y compris leurs conditions, doivent fonctionner de manière atomique.
Un modèle Lua de type « comparaison et suppression » compare la valeur stockée à un jeton de propriété transmis et ne procède à la suppression qu'en cas de correspondance. Cela empêche un processus en retard de supprimer une clé qui a entre-temps été réattribuée, uniquement en raison de son ancien jeton.
Ce modèle de comparaison décrit exclusivement l'ordre d'exécution garanti pour une seule clé Redis. Il ne résout pas les questions plus larges liées aux verrous distribués, telles que les durées de lease appropriées, les pauses de processus, les pannes ou la coordination de plusieurs instances Redis. De plus, l’atomicité d’une commande ou d’un script ne concerne que les données Redis impliquées, et non les paiements, la base de données, les e-mails ou les API externes.
Lua Sandbox et des limites claires
Redis Open Source intègre Lua 5.1 pour les scripts. Ce moteur d'exécution ne doit pas être assimilé à une version principale de Lua installée localement ou à la version actuelle : c'est Redis qui détermine les fonctionnalités linguistiques disponibles et les règles de sécurité. Les développeurs de scripts Lua pour Redis doivent donc les tester par rapport à la version de Redis effectivement utilisée et ne pas supposer les caractéristiques d’un environnement Lua externe quelconque.
La réalisation s'effectue dans une Sandbox avec des limites délibérément strictes. Un script doit traiter les données Redis et les arguments qui lui sont transmis, mais ne doit utiliser ni le système de fichiers, ni le réseau, ni les services du système d'exploitation. Les appels HTTP externes, l'envoi de messages ou l'accès aux fichiers locaux doivent donc être intégrés au code de l'application ou à un service prévu à cet effet, et non dans le « cache scripting ».
Redis propose KEYS et ARGV sont disponibles en tant que variables de portée globale. En revanche, pour tes propres valeurs intermédiaires et fonctions auxiliaires, tu utilises des variables locales avec local. Cela permet de distinguer les valeurs qui ne s'appliquent qu'à cet appel, et la logique du script ne crée pas de dépendances inutiles. Tu peux appeler les commandes Redis de manière ciblée via redis.call ou redis.pcall sur.
Le bac à sable ne remplace pas la planification des capacités. Lors d’une exécution normale, un script bloque les autres clients au niveau du serveur ; par conséquent, les boucles longues, les volumes de données illimités et les calculs gourmands en ressources ne sont pas adaptés. Limitez le travail à quelques clés connues à l’avance et à des calculs simples. Des analyses approfondies, des inventaires globaux basés sur SCAN ou la communication avec des systèmes tiers augmenteraient les risques opérationnels sans pour autant étendre l’atomicité de manière pertinente.
Comprendre EVAL, KEYS et ARGV
L'appel direct d'un script s'effectue sous la forme suivante EVAL script numkeys [key …] [arg …]. D'après le code source, numkeys détermine combien de paramètres suivants sont des clés. Le script y accède via KEYS avec une indexation à partir de 1 ; toutes les autres valeurs se trouvent dans ARGV. Cette distinction est essentielle : les clés décrivent les données Redis, tandis que les arguments correspondent aux entrées métier telles que la valeur limite, le montant ou le jeton attendu.
Un script de limite reçoit, par exemple, le compteur sous la forme KEYS[1] et la valeur maximale sous la forme ARGV[1]. Il lit la valeur actuelle, convertit la valeur limite à l'aide de tonumber(ARGV[1]) en un nombre et compare les deux valeurs avant de l'incrémenter. Cette conversion rend explicite la règle arithmétique prévue, au lieu de s'appuyer sur un traitement implicite des valeurs des arguments. En l'absence de compteur, le script peut traiter de manière ciblée la valeur lue comme étant nulle.
Chaque clé que le script lit ou écrit doit être préalablement spécifiée en tant qu'argument de clé. La composition de noms de clés dans le script à partir de préfixes ou leur dérivation à partir de données enregistrées ne constitue pas une pratique recommandée. Redis, en particulier dans le cas de Redis Open Source avec le cluster activé, ne peut alors pas déterminer avant l'exécution quelles données le script nécessite. Transmettez donc les clés connues dans leur intégralité via KEYS et les valeurs variables exclusivement via ARGV.
Dans Redis Open Source, lorsque le cluster est activé, les clés transmises à un script doivent en outre se trouver dans le même slot de hachage. La déclaration précédente permet de vérifier cela, mais ne remplace pas cette vérification. Pour les données associées, un tag de hachage choisi à dessein peut s'avérer utile, par exemple account:{4711}:balance et account:{4711}:reservations. La partie entre accolades détermine ici l'affectation des emplacements ; des clés déterminées de manière dynamique compromettraient cette planification.
Mise à jour atomique des compteurs à fenêtre fixe
L'exemple suivant est un élément atomique Compteur à fenêtre fixe pour une instance de test locale. Il vérifie la valeur du compteur et la limite lors d'une exécution sur le serveur et ne définit la durée d'expiration qu'au premier accès réussi pendant la fenêtre temporelle. Cela permet d'éviter que, pendant l'intervalle entre une requête GET dans le code de l'application et un INCR ultérieur, un autre client ne puisse modifier le compteur.
L'appel transmet la clé du compteur, la limite et la durée de la fenêtre en secondes. Le statut 1 signifie « autorisé », le statut 0 signifie « limite atteinte ». Le statut 2 signale une entrée non valide détectée lors des vérifications préliminaires, une valeur de compteur de type chaîne rejetée à ce stade ou l'existence d'un compteur de type chaîne sans TTL. Si la clé contient un autre type de données Redis, la commande GET échoue d’emblée en raison d’une erreur technique de type ; le script ne renvoie alors pas le statut 2. Il convient également de distinguer les autres erreurs d’exécution Redis du statut de retour fonctionnel. Cet exemple ne constitue pas un modèle pour les données d’accès, les limites en production ou les tests de charge.
Avant chaque opération d'écriture, le script vérifie que tous les nombres sont bien des entiers positifs finis, dont la valeur ne dépasse pas une limite supérieure délibérément basse. Il ne s'agit pas simplement d'une vérification avec tonumber: Des valeurs telles que 1.5 ou 1e3 sont rejetées. La limite d'un million empêche en outre la précision numérique de Lua ou celle de INCR chaîne de caractères entière attendue en dehors de la plage de l'exemple devient pertinente. La durée maximale de la fenêtre, fixée à 86 400 secondes, limite également la EXPIRE nombre de secondes transmis.
L'expression régulière n'accepte que des chiffres décimaux ; la fonction auxiliaire vérifie ensuite la valeur numérique, le caractère entier et la limite supérieure. Un compteur déjà existant ne peut être qu’un nombre entier non négatif appartenant à ce même intervalle limité. Ainsi, une valeur négative, fractionnaire ou trop grande ne peut pas modifier la sémantique des limites sans être détectée. Ce n’est qu’après ces vérifications que suit INCR.
Si la clé n'existe pas, le script commence à 0. S'il existe déjà un compteur de chaînes valide sans date d'expiration, il renvoie le statut 2 et n'écrit rien. Après le premier INCR met EXPIRE la TTL, qui a été préalablement vérifiée dans son intégralité. En cas de correspondances ultérieures, elle reste inchangée, de sorte que la fenêtre n'est pas prolongée en continu.
Le Contrat de restitution fait partie de l'interface : le premier élément du tableau décrit l'état, le second fournit, en fonction de l'état, la valeur du compteur ou un code d'erreur. Le code appelant doit traiter différemment un rejet technique avec l’état 0 et l’état 2, qui indique une condition préalable non respectée. Pour plus d’informations sur le choix et la surveillance des délais d’exécution, consultez l’article Analyser et optimiser l'expiration des clés Redis une base complémentaire.
Le TTL n'est ici délibérément défini qu'à la première requête. Un modèle qui le réinitialiserait à chaque accès aurait une sémantique temporelle différente et ne serait plus une « fenêtre fixe ». Atomicité en Lua Cela ne fait que résoudre la condition de concurrence. C'est l'algorithme choisi, et non le langage de script, qui détermine si la méthode « Fixed Window », « Sliding Window » ou « Token Bucket » est la plus adaptée pour obtenir l'équité et la répartition de charge souhaitées.
Sélectionner le modèle d'atomisation approprié
Toutes les exigences composées ne nécessitent pas forcément un script. S'il existe une commande Redis unique qui exprime déjà pleinement la règle métier, celle-ci est généralement plus simple à mettre en œuvre et à tester. En revanche, pour les règles à plusieurs niveaux, il faut prendre en compte conjointement les conditions, les types de données et le contrat de retour.
À partir de Redis Open Source 8.4, des opérations natives « Compare-and-Set » et « Compare-and-Delete » sont disponibles pour les clés de type chaîne de caractères : SET prend en charge les options de comparaison IFEQ/IFNE/IFDEQ/IFDNE; DELEX prend en charge la suppression conditionnelle. Pour les cas spécifiques impliquant une seule clé, aucun script de comparaison distinct n'est donc nécessaire. Dans Redis 8.2, 8.0 et 7.x, ces nouvelles options SET et DELEX ne sont pas disponibles ; dans ces versions, les modèles WATCH ou Lua adaptés restent d'actualité.
Pour une stratégie « Compare-and-Set » optimiste, l'utilisation de WATCH avant MULTI et EXEC peut s'avérer appropriée : si une clé surveillée change avant EXEC, la transaction est interrompue et le client décide de réessayer. De même, les transactions ne proposent pas de rollback général en cas d'erreurs survenant pendant EXEC. WATCH reste donc une option lorsque la condition requise ne peut être satisfaite par une seule commande native.
| Modèle | Cas d'utilisation approprié | Code et appel | Après un redémarrage ou un basculement | Comportement du client et limites |
|---|---|---|---|---|
| Commande native | Une opération individuelle existante met en œuvre la règle | Pas de code de programme ; commande directe | Aucun cache de script n'est concerné | Pas de rechargement de script ; limité à la sémantique existante |
| CAS/CAD natifs à partir de Redis Open Source 8.4 | Définition ou suppression d'une clé de type chaîne de caractères en fonction d'une valeur | SET avec IFEQ/IFNE/IFDEQ/IFDNE ; DELEX avec condition de comparaison | Aucun cache de script n'est concerné | Vérifier la limite de version et la condition de comparaison ; pas de règle composite à plusieurs clés |
| MULTI/EXEC avec WATCH | Lecture, révision et rédaction optimistes | WATCH, MULTI, EXEC | Pas de mémoire programme | En cas de modification avant EXEC, relire et prendre une décision ; pas de rollback en cas d'erreurs EXEC |
| EVAL | Petit script exécuté directement | Code source pour chaque EVAL | Le cache de scripts n'est pas permanent | Pas de rechargement du résumé ; le code source est retransmis |
| SCRIPT LOAD et EVALSHA | Script réutilisé avec un digest connu | Chargement, puis vérification à l'aide du condensé SHA1 | Le cache peut être manquant | Gérer NOSCRIPT et recharger la page ; prévoir tout particulièrement la solution de secours pour le pipeline |
| Fonctions Redis à partir de la version 7.0 | Logique de données nommée et réutilisable | FUNCTION LOAD, puis FCALL | Les bibliothèques sont répliquées et persistées | Processus de gestion des versions et de mise à disposition requis ; ne pas confondre avec EVAL |
Les scripts EVAL sont liés au cache de scripts et reçoivent leurs entrées via KEYS et ARGV. Fonctions Redis À partir de Redis 7.0, elles sont disponibles sous forme de bibliothèques nommées : elles sont enregistrées à l'aide de la commande FUNCTION LOAD, appelées via FCALL, puis persistées et répliquées avec la base de données. Leurs clés et leurs arguments sont transmis à la fonction sous forme de paramètres ; il en résulte un modèle de mise à disposition et d'appel différent de celui d'EVAL.
Pour les petites logiques orientées application, EVAL constitue donc un point d'entrée direct. La présence de plusieurs clients et une logique de données gérée sur le long terme plaident souvent en faveur des fonctions, à condition que la version open source de Redis utilisée les prenne en charge. La décision doit également tenir compte du déploiement, des autorisations, de la gestion des erreurs et d’un retour de résultat clairement documenté, et pas seulement du nombre de commandes Redis.
Clusters, erreurs et contrats de retour
Dans Redis Open Source, lorsque le cluster est activé, les clés transmises par un script à clés multiples doivent se trouver dans le même emplacement de hachage. Les balises de hachage permettent de contrôler cela : dans le cas de account:{4711}:balance et account:{4711}:reservations le contenu entre accolades détermine le slot. Les deux clés peuvent donc être adressées conjointement. La condition du « même slot » s'applique également aux opérations à clés multiples et aux transactions MULTI/EXEC considérées ici. D'autres configurations de produit et de cluster peuvent présenter des différences pour certaines commandes. Il n’en résulte toutefois pas d’autorisation générale de « cross-slot » pour Lua : la documentation relative aux clés multiples classe EVAL/EVALSHA comme une opération à slot unique, même avec Redis Software, que le cluster soit activé ou non et que l’API cluster OSS soit utilisée ou non.
Toutes les clés utilisées doivent être déclarées en tant qu'arguments de clé avant l'appel. Un script ne doit pas dériver les noms de clés à partir de valeurs enregistrées ni les composer de manière dynamique. Cette règle permet à Redis de vérifier correctement les slots avant l'exécution et évite les dépendances cachées qui passent inaperçues dans une instance autonome, mais qui entraînent des échecs dans Redis Open Source lorsque le cluster est activé.
Avec redis.call() une erreur de la commande Redis appelée est transmise au client sous forme d'erreur de script. redis.pcall() En revanche, elle le renvoie à Lua afin que le script puisse le traiter de manière ciblée. pcall n'a de sens que si une réaction spécifique est définie, par exemple une réponse d'erreur clairement structurée ou un déroulement alternatif autorisé. Ignorer les erreurs en silence masque les problèmes liés aux données et à leur intégrité.
A contrat vicié distingue les erreurs techniques des résultats fonctionnels. WRONGTYPE signifie par exemple que le type de données Redis enregistré ne correspond pas à la commande attendue et doit être examiné. En revanche, une réservation refusée en raison d’un stock insuffisant est un résultat attendu et peut, par exemple, renvoyer le statut et le stock restant. Les applications ne doivent pas traiter ces catégories de la même manière ni les répéter toutes les deux de manière systématique.
Assurer une exploitation robuste de la distribution des scripts
EVAL convient aux appels directs : le client transmet le code source Lua complet, accompagné des valeurs des clés et des arguments. Pour un script fréquemment utilisé et inchangé, l'application peut plutôt l'appeler avec SCRIPT LOAD le charger dans le cache des scripts. Redis renvoie pour cela un hachage SHA1 ; EVALSHA exécute ensuite précisément le code source correspondant. Cela évite les transferts répétés, mais ne modifie ni l'atomicité ni la responsabilité technique du script.
Le Cache de scripts n'est pas permanent. Après un redémarrage, un basculement ou SCRIPT FLUSH un appel via Digest peut être effectué avec NOSCRIPT échouer. L'application doit gérer ce cas de manière standard : recharger le script et répéter l'appel valide, dans la mesure où sa propre logique de nouvelle tentative le permet. Un « digest » ne doit donc pas être interprété comme une garantie que le script existe déjà sur chaque serveur de destination.
Dans le cas des pipelines, cette solution de secours est limitée. Si plusieurs commandes ont déjà été envoyées ensemble, l'application peut rencontrer un NOSCRIPT- Ne pas remplacer rétroactivement les erreurs en chargeant et en réexécutant à partir du même point. Redis recommande, dans de tels cas, d'utiliser des EVAL comme stratégie de secours. Quiconque prévoit de mettre en place la réplication et le basculement doit également comprendre le rôle que joue le tampon de réplication lors de la reconnexion d'une réplique : Comprendre le backlog de réplication Redis.
Les valeurs variables ne doivent pas figurer dans le code source Lua, mais dans ARGV. Sinon, chaque valeur limite génère un script différent, ce qui alourdit inutilement le cache. Depuis Redis 7.4, il est possible, via EVAL ou EVAL_RO les scripts chargés sont supprimés lorsqu'une limite de cache est atteinte selon le principe LRU ; cela ne remplace ni la paramétrisation ni le traitement de NOSCRIPT.
Maîtriser les scripts longs et les fautes d'orthographe
Un script Lua bloque les autres activités du serveur pendant son exécution normale. Cela permet d'assurer l'isolation, mais devient un problème lorsque l'exécution dure longtemps. Risque opérationnel. Si un script dépasse la limite configurée busy-reply-threshold, Redis répond aux commandes normales par BUSY; cela ne met pas automatiquement fin au script. Limitez donc les scripts à quelques clés connues et à des calculs simples et limités.
Les opérations d'écriture précédant une erreur ou une boucle infinie sont particulièrement critiques. Si un script a déjà modifié des données, il peut SCRIPT KILL ne pas le terminer correctement. Vérifie donc les données d'entrée avant la première écriture et évite les boucles sans limite ainsi que SCAN sur l'ensemble des stocks. Les tests doivent refléter le volume de données et les chemins d'erreur du déploiement prévu.
| Cas | Réponse identifiable | Cause typique | Une cohérence sans faille |
|---|---|---|---|
| NOSCRIPT | Message d'erreur NOSCRIPT | Le « digest » est absent du cache temporaire des scripts | Charger le script ou utiliser la fonction EVAL paramétrée ; ne réessayer qu'en respectant votre propre règle de réessai. |
| CROSSSLOT | CROSSSLOT dans Redis Open Source avec le cluster activé | Les clés transmises au script se trouvent dans différents emplacements de hachage | Modifier la structure des clés et déclarer toutes les clés nécessaires. |
| WRONGTYPE | Erreur Redis WRONGTYPE | La clé possède un type de données inattendu | Corriger le modèle de données ou les conditions préalables du script ; ne pas considérer cela comme un rejet technique. |
| Pression de mémoire via maxmemory | Une opération d'écriture peut interrompre le script | Au démarrage, Redis dépasse déjà la limite de mémoire | Ne pas reproduire aveuglément ; prévoir une gestion des erreurs sûre et documentée pour redis.pcall. |
| BUSY | Réponse d'erreur « BUSY » pour d'autres commandes | Le script dépasse le seuil « busy-reply-threshold » | Réduire la charge et alléger le script ; ne pas compter sur la fonction « kill » après les opérations d'écriture. |
| Rejet pour des raisons techniques | Valeur d'état documentée | Par exemple : limite atteinte ou solde trop faible | Évaluer le statut et rejeter la transaction de manière ordonnée. |
À l'adresse suivante : maxmemory le déroulement dépend de la première opération d'écriture. Si Redis a déjà dépassé la limite, une commande gourmande en mémoire peut, lors de redis.call interrompre le script ; redis.pcall renvoie l'erreur à Lua et nécessite une gestion des erreurs spécialement conçue. Les modifications déjà effectuées ne sont pas restaurées.
Une première opération ne nécessitant pas de mémoire supplémentaire, par exemple DEL ou LREM, le script peut en revanche continuer à s'exécuter ; les opérations d'écriture ultérieures peuvent augmenter la consommation via maxmemory augmenter. Les erreurs techniques telles que WRONGTYPE ou CROSSSLOT Dans Redis Open Source, lorsque le cluster est activé, les corrections apportées au modèle de données ou à la conception des clés sont obligatoires, alors que seul le script lui-même peut définir un rejet technique comme état stable.
Choisir délibérément les cas d'utilisation appropriés
Dans le cadre d'une réservation conditionnelle, un script peut vérifier le stock, refuser une valeur trop faible et, en cas de succès, renvoyer le stock restant. Le réservation atomique ne concerne toutefois que Redis. Le paiement, la base de données relationnelle, la messagerie électronique et les API externes nécessitent une coordination spécifique et, le cas échéant, une logique de compensation.
Le choix dépend de la version de Redis et du modèle de données. À partir de Redis Open Source 8.4, les options de comparaison de SET une mise conditionnelle et DELEX se charger de la comparaison et de la suppression d'une clé de type chaîne de caractères unique. Avant Redis 8.4 ou dans le cas d'une condition plus complexe, WATCH avec MULTI/EXEC Une alternative : si une clé surveillée change avant l'instruction EXEC, la transaction est interrompue et le client décide de relire les données et de répéter l'opération. Un petit script Lua convient lorsque plusieurs commandes ou structures de données, y compris leurs règles métier, doivent interagir côté serveur.
Pour les verrous distribués, ni la commande unique ni le modèle Lua ne suffisent en tant que concept global. La durée du bail, les pauses de processus, les pannes, les répétitions, le basculement et les scénarios multi-instances doivent être évalués séparément. Privilégiez une commande native si la version utilisée et sa sémantique couvrent l'intégralité de la règle. Sinon, il faut WATCH et évaluer un petit script en fonction du contrat d'erreur et de l'emplacement de la logique métier. Pour une logique côté serveur réutilisable, une fonction Redis peut convenir. Scripts en lecture seule sont autorisées à partir de Redis 7.0 via EVAL_RO ou EVALSHA_RO fonctionnent, mais uniquement si la logique est garantie sans écriture.
Sources et état des connaissances
État de la recherche :
Date de recherche et version : 23 septembre 2026. Cet article traite de Redis Open Source et fait la distinction entre les scripts EVAL et les fonctions Redis à partir de la version 7.0 de Redis. Vérifiez les limites de version et les commandes disponibles avant toute utilisation, en fonction de la version de Redis effectivement utilisée.
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/




