Redis propose deux mécanismes de gestion des transactions :les transactions basées sur MULTI/EXEC et l'évaluation des scripts Lua. Le script Redis Lua est l'approche recommandée et son utilisation est assez populaire.
Nos clients Redis™ qui ont déployé des scripts Lua signalent souvent cette erreur :"BUSY Redis est occupé à exécuter un script. Vous ne pouvez appeler SCRIPT KILL ou SHUTDOWN NOSAVE ”. Dans cet article, nous expliquerons la propriété transactionnelle Redis des scripts, en quoi consiste cette erreur et pourquoi nous devons y faire très attention sur les systèmes gérés par Sentinel qui peuvent basculer.
Nature transactionnelle des scripts Redis Lua
Les « transactions » Redis ne sont pas vraiment des transactions au sens conventionnel ; en cas d'erreurs, il n'y a pas d'annulation des écritures effectuées par le script.
"l'atomicité" des scripts Redis est garantie de la manière suivante :
- Une fois qu'un script commence à s'exécuter, toutes les autres commandes/scripts sont bloqués jusqu'à ce que le script se termine. Ainsi, les autres clients voient ou non les modifications apportées par le script. En effet, ils ne peuvent s'exécuter qu'avant ou après le script.
- Cependant, Redis n'effectue pas de restauration, donc en cas d'erreur dans un script, toutes les modifications déjà apportées par le script seront conservées et les futures commandes/scripts verront ces modifications partielles.
- Étant donné que tous les autres clients sont bloqués pendant l'exécution du script, il est essentiel que le script se comporte bien et se termine à temps.
La valeur "lua-time-limit"
Il est fortement recommandé que le script soit terminé dans un délai imparti. Redis applique cela de manière faible avec la valeur "lua-time-limit". Il s'agit de la durée maximale autorisée (en ms) pendant laquelle le script est autorisé à s'exécuter. La valeur par défaut est de 5 secondes. C'est un temps très long pour l'activité liée au processeur (les scripts ont un accès limité et ne peuvent pas exécuter de commandes qui accèdent au disque).
Cependant, le script n'est pas tué lorsqu'il s'exécute au-delà de ce délai. Redis recommence à accepter les commandes client, mais y répond par une erreur BUSY.
Si vous devez tuer le script à ce stade, deux options s'offrent à vous :
- SCRIPT KILL La commande peut être utilisée pour arrêter un script qui n'a pas encore effectué d'écriture.
- Si le script a déjà effectué des écritures sur le serveur et doit encore être tué, utilisez le SHUTDOWN NOSAVE pour arrêter complètement le serveur.
Il est généralement préférable d'attendre que le script termine son opération. Les informations complètes sur les méthodes pour tuer l'exécution du script et le comportement associé sont disponibles dans la documentation.
Transactions Redis et scripts Lua de longue duréeCliquez pour tweeterComportement sur les systèmes haute disponibilité surveillés par Sentinel
Les systèmes de haute disponibilité gérés par Sentinel ajoutent une nouvelle dimension à cela. En fait, cette discussion s'applique à tout système à haute disponibilité qui dépend de l'interrogation des serveurs Redis :
- Les scripts de longue durée bloqueront initialement les commandes client. Plus tard, lorsque le "lua-time-limit" est passé, le serveur commencera à répondre avec des erreurs BUSY.
- Les Sentinelles considéreront un tel nœud comme indisponible, et si cela persiste au-delà de la valeur d'arrêt après millisecondes configurée sur les Sentinelles, elles détermineront que le nœud est en panne.
- Si un tel nœud est le maître, un basculement sera lancé. Un nœud de réplique peut être promu et commencer à accepter de nouvelles connexions de clients.
- Pendant ce temps, l'ancien maître finira par terminer l'exécution du script et reviendra en ligne. Cependant, Sentinel finira par le reconfigurer en tant que réplique et il commencera à se synchroniser avec le nouveau maître. Toutes les données écrites par le script seront perdues.
|
Démonstration
Nous avons configuré un système de haute disponibilité sensible pour démontrer ce comportement de basculement. La configuration comporte 2 serveurs Redis exécutés dans une configuration maître/réplica surveillée par un quorum de 3 sentinelles.
La valeur lua-time-limit a été définie sur 500 ms afin qu'il commence à répondre aux clients avec des erreurs si un script s'exécute pendant plus de 500 ms. La valeur down-after-milliseconds sur les Sentinels est définie sur 5 secondes afin qu'un nœud qui signale des erreurs soit marqué DOWN après 5 secondes.
Nous exécutons le script Lua suivant sur le maître :
local i = 0 while (true) do local key = "Key-" .. i local value = "Value-" .. i redis.call('set', key, value) i = i + 1 redis.call('time') end
Cela continue d'écrire des entrées dans le maître Redis. Nous nous inscrivons aux événements sur l'une des sentinelles pour observer le comportement.
Le script est lancé sur le maître :
$ redis-cli -a --eval test.lua Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Voici une séquence tronquée d'activités comme on le voit sur Sentinel :
3) "+vote-for-leader" 4) "9096772621089bb885eaf7304a011d9f46c5689f 1" 1) "pmessage" 2) "*" 3) "+sdown" <<< master marked DOWN 4) "master test 172.31.2.48 6379" 1) "pmessage" 2) "*" 3) "+odown" 4) "master test 172.31.2.48 6379 #quorum 3/2" 1) "pmessage" 2) "*" 3) "-role-change" << role change initiated 4) "slave 172.31.28.197:6379 172.31.28.197 6379 @ test 172.31.2.48 6379 new reported role is master" 1) "pmessage" 2) "*" 3) "+config-update-from" 4) "sentinel 9096772621089bb885eaf7304a011d9f46c5689f 172.31.2.48 26379 @ test 172.31.2.48 6379" 1) "pmessage" 2) "*" 3) "+switch-master" 4) "test 172.31.2.48 6379 172.31.28.197 6379"
Plus tard, lorsque l'ancien maître est mis en ligne, il est remplacé par un réplica :
3) "-role-change" 4) "slave 172.31.2.48:6379 172.31.2.48 6379 @ test 172.31.28.197 6379 new reported role is master" 1) "pmessage" 2) "*" 3) "-sdown" 4) "slave 172.31.2.48:6379 172.31.2.48 6379 @ test 172.31.28.197 6379" 1) "pmessage" 2) "*" 3) "+role-change" 4) "slave 172.31.2.48:6379 172.31.2.48 6379 @ test 172.31.28.197 6379 new reported role is slave"
Toutes les données écrites sur l'ancien maître via le script sont perdues.
Recommandations
- Vous devez connaître à l'avance les caractéristiques de vos scripts de longue durée avant de les déployer en production.
- Si votre script dépasse régulièrement la limite de temps lua, vous devez examiner attentivement le script pour d'éventuelles optimisations. Vous pouvez également le décomposer en éléments qui se terminent dans des durées acceptables.
- Si vous devez exécuter des scripts qui ne respectent pas la limite de temps lua, envisagez de planifier ces scripts pendant les périodes où l'activité des autres clients sera faible.
- La valeur de lua-time-limit peut également être augmentée. Ce serait une solution acceptable si d'autres applications clientes qui s'exécutent en parallèle avec le script peuvent tolérer de recevoir des réponses extrêmement retardées plutôt qu'une erreur BUSY et de réessayer plus tard.
Considérations supplémentaires sur les systèmes haute disponibilité surveillés par Sentinel :
- Si les scripts n'effectuent que des opérations de lecture et que vous avez des répliques disponibles, vous pouvez déplacer ces scripts vers les répliques.
Modifiez le paramètre Sentinel down-after-milliseconds sur une valeur qui garantira que les basculements ne sont pas lancés. Vous ne devez le faire qu'après mûre réflexion, car une augmentation drastique de la valeur compromettra les caractéristiques de haute disponibilité de votre système. Cela pourrait également entraîner l'ignorance des véritables pannes de serveur.
|