1
MULTI marque le début d'un bloc de transaction. |
|
2
EXEC exécute toutes les commandes dans le bloc de transaction. |
|
3
DISCARD annule la transaction et abandonne l'exécution de toutes les commandes au sein du bloc de transaction. |
|
4
WATCH key [key ...] Surveille une (ou plusieurs) clés. Si cette (ou ces) clés sont modifiées par d'autres commandes avant l'exécution de la transaction, la transaction sera interrompue. |
|
5
UNWATCH annule la surveillance de toutes les touches par la commande WATCH. |
|
La transaction se compose de trois étapes :
- La transaction est ouverte, en utilisant MULTI, cette commande marque le client exécutant la commande passant de l'état non transactionnel à l'état transactionnel
- La commande est mise en file d'attente, une fois que MULTI a ouvert la transaction, la commande du client Il ; ne sera pas exécuté immédiatement, mais sera placé dans une file d'attente de transactions ;
- Exécutez la transaction ou supprimez-la. Si une commande EXEC est reçue, la commande dans la file d'attente des transactions sera exécutée. Si elle est DISCARD, la transaction sera rejetée.
Ce qui suit montre un exemple de transaction.
1
redis> MULTI
2
OK
3
redis> SET msg "hello world"
4
QUEUED
5
redis> GET msg
6
QUEUED
7
redis> EXEC
8
1) OK
9
1) hello world
Vous avez une question ici ? La clé Redis peut-elle être modifiée lors du démarrage d'une transaction ?
Avant que la transaction n'exécute la commande EXEC, la clé Redis peut toujours être modifiée.
Avant de démarrer la transaction, nous pouvons utiliser la commande watch pour surveiller la clé Redis. Avant que la transaction ne soit exécutée, nous modifions la valeur de la clé. Si la transaction échoue, nil est renvoyé.
Grâce à l'exemple ci-dessus, la commande watch peut obtenir un effet similaire au verrouillage optimiste.
2 ACIDE de transaction
2.1 Atomicité
Atomicité signifie : toutes les opérations d'une transaction sont soit entièrement terminées, soit non terminées, et ne se termineront pas par un lien intermédiaire. Si une erreur se produit lors de l'exécution de la transaction, elle sera restaurée à l'état avant le début de la transaction, comme si la transaction n'avait jamais été exécutée.
Premier exemple :
Avant d'exécuter la commande EXEC, la commande d'opération envoyée par le client est erronée, comme une erreur de syntaxe ou une commande inexistante.
1
redis> MULTI
2
OK
3
redis> SET msg "other msg"
4
QUEUED
5
redis> wrongcommand ### 故意写错误的命令
6
(error) ERR unknown command 'wrongcommand'
7
redis> EXEC
8
(error) EXECABORT Transaction discarded because of previous errors.
9
redis> GET msg
10
"hello world"
Dans cet exemple, nous avons utilisé une commande qui n'existe pas, provoquant l'échec de la mise en file d'attente et l'échec de l'exécution de la transaction entière.
Deuxième exemple :
Lorsque l'opération de transaction est mise en file d'attente, les types de données de la commande et de l'opération ne correspondent pas. La mise en file d'attente est normale, mais l'exécution de la commande EXEC est anormale.
1
redis> MULTI
2
OK
3
redis> SET msg "other msg"
4
QUEUED
5
redis> SET mystring "I am a string"
6
QUEUED
7
redis> HMSET mystring name "test"
8
QUEUED
9
redis> SET msg "after"
10
QUEUED
11
redis> EXEC
12
1) OK
13
2) OK
14
3) (error) WRONGTYPE Operation against a key holding the wrong kind of value
15
4) OK
16
redis> GET msg
17
"after"
Dans cet exemple, si une erreur se produit lorsque Redis exécute la commande EXEC, Redis ne mettra pas fin à l'exécution des autres commandes et la transaction ne sera pas annulée car une certaine commande ne parvient pas à s'exécuter.
Pour résumer, ma compréhension de l'atomicité des transactions Redis est la suivante :
- Si une erreur est signalée lorsque la commande est mise en file d'attente, l'exécution de la transaction sera abandonnée pour garantir l'atomicité ; mis en file d'attente, et une erreur sera signalée après l'exécution de la commande EXEC, ce qui ne garantit pas l'atomicité
- C'est-à-dire :
Les transactions Redis n'ont qu'une certaine atomicité sous certaines conditions.
2.2 Isolation L'isolation de la base de données fait référence à la capacité de la base de données à permettre à plusieurs transactions simultanées de lire, d'écrire et de modifier ses données en même temps. L'isolation peut empêcher l'exécution simultanée de plusieurs transactions en raison de croisements. exécution conduisant à une incohérence des données.
L'isolement des transactions est divisé en différents niveaux, qui sont :
lecture non validée
- lecture validée
- lecture répétable
- sérialisable
- Tout d'abord, il faut être clair : Redis n'a pas le concept de transaction niveau d'isolement. Nous discutons ici de l'isolement de Redis :
Dans un scénario simultané, si les transactions peuvent éviter d'interférer les unes avec les autres. Nous pouvons diviser l'exécution de la transaction en deux étapes :
avant l'exécution de la commande EXEC et commande EXEC après l'exécution, et en discuter séparément.
Avant d'exécuter la commande EXEC
- Dans la section sur les principes de transaction, nous avons constaté que la clé Redis peut toujours être modifiée avant l'exécution de la transaction. À ce stade, vous pouvez utiliser le
mécanisme WATCH pour obtenir l'effet de verrouillage optimiste.
Après l'exécution de la commande EXEC
- Étant donné que Redis est une commande d'exécution à thread unique, une fois la commande EXEC exécutée, Redis garantira que toutes les commandes de la file d'attente de commandes sont exécutées. Cela garantit l’isolement des transactions.
2.3 DurabilitéLa persistance de la base de données signifie : une fois la transaction terminée, la modification des données est permanente et ne sera pas perdue même en cas de panne du système.
La persistance des données Redis dépend du mode de configuration de persistance de Redis.
Sans RDB ou AOF configuré, la durabilité de la transaction ne peut pas être garantie
- En utilisant le mode RDB, après l'exécution d'une transaction et avant l'exécution du prochain instantané RDB, si un crash d'instance se produit, la durabilité de la transaction ; Il n'y a également aucune garantie ;
- utilise le mode AOF ; les trois options de configuration du mode AOF, no et everysec, entraîneront une perte de données. peut toujours garantir la durabilité des transactions, mais comme les performances sont trop médiocres, il n'est généralement pas recommandé de l'utiliser dans des environnements de production.
- En résumé, la pérennité des transactions
redis ne peut être garantie.
2.4 CohérenceLe concept de cohérence a toujours prêté à confusion. Dans les informations que j'ai recherchées, il existe deux définitions différentes.
- Wikipedia
Regardons d'abord la définition de la cohérence sur Wikipédia :
La cohérence garantit qu'une transaction ne peut que faire passer la base de données d'un état valide à un autre, en maintenant les invariants de la base de données : toutes les données écrites dans la base de données doivent être valides. selon toutes les règles définies, y compris les contraintes, les cascades, les déclencheurs et toute combinaison de celles-ci. Cela empêche la corruption de la base de données par une transaction illégale, mais ne garantit pas qu'une transaction est correcte.
Dans ce texte, le cœur de la cohérence est "
contraintes", "toute donnée écrite dans la base de données doit être valide selon toutes les règles définies". Comment comprendre les contraintes ? Voici une citation de la question Zhihu
Comment comprendre la cohérence interne et la cohérence externe de la base de données, et un passage auquel Han Fusheng, un expert R&D OceanBase chez Ant Financial a répondu :
Les "contraintes" sont indiquées par l'utilisateur de la base de données à la base de données, et l'utilisateur exige que les données soient sûres de respecter telle ou telle contrainte. Lorsque les données sont modifiées, la base de données vérifiera si les données répondent toujours aux contraintes. Si les contraintes ne sont plus satisfaites, l'opération de modification n'aura pas lieu.
Les deux types de contraintes les plus courants dans les bases de données relationnelles sont les « contraintes uniques » et les « contraintes d'intégrité ». La clé primaire et la clé unique définies dans la table garantissent que les éléments de données spécifiés ne seront jamais répétés. L'intégrité garantit également la cohérence du même attribut dans les différentes tables.
"Cohérence dans ACID" est si facile à utiliser qu'il a été fondu dans le sang de la plupart des utilisateurs. Les utilisateurs ajouteront consciemment les contraintes requises lors de la conception des tables, et la base de données les implémentera strictement.
Donc
la cohérence des transactions est liée à des contraintes prédéfinies. Assurer des contraintes, c'est assurer la cohérence. Regardons de plus près cette phrase :
Cela empêche la corruption de la base de données par une transaction illégale, mais ne garantit pas qu'une transaction est correcte. Vous êtes peut-être encore un peu confus après avoir écrit ceci. Prenons un cas classique de
transfert. Nous commençons une transaction. Les soldes initiaux sur les comptes de Zhang San et Li Si sont tous deux de 1 000 yuans, et il n'y a aucune contrainte sur le champ du solde. Zhang San a transféré 1 200 yuans à Li Si. Le solde de Zhang San est mis à jour à -200 et celui de Li Si est mis à jour à 2200.
Au niveau de l'application, cette transaction est évidemment illégale, car dans des scénarios réels, le solde utilisateur ne peut pas être inférieur à 0, mais elle suit complètement les contraintes de la base de données, donc au niveau de la base de données, cette transaction garantit toujours la cohérence.
La cohérence des transactions de Redis signifie que les transactions Redis sont conformes aux contraintes de la base de données lors de l'exécution et ne contiennent pas de données d'erreur illégales ou invalides.
Nous discutons respectivement de trois scénarios d'exception :
Avant d'exécuter la commande EXEC, la commande d'opération envoyée par le client est erronée, la transaction est terminée et les données restent cohérentes ; Après l'exécution de la commande EXEC, les données de commande et d'opération Si le type ne correspond pas, la mauvaise commande signalera une erreur, mais la transaction ne sera pas terminée en raison d'une mauvaise commande, mais continuera à s'exécuter. La bonne commande est exécutée normalement, et la mauvaise commande signale une erreur. De ce point de vue, les données peuvent également maintenir la cohérence Lors de l'exécution de la transaction, le service Redis tombe en panne. Ici, vous devez considérer le mode de persistance de la configuration du service. -
Mode mémoire sans persistance : Après le redémarrage du service, la base de données ne conserve pas les données, donc les données restent cohérentes ;
- Mode RDB/AOF : Après le redémarrage du service, Redis restaure les données via les fichiers RDB/AOF, et la base de données ; restaurera à un état cohérent.
-
Pour résumer,
Sous la sémantique selon laquelle le cœur de la cohérence est la contrainte, les transactions Redis peuvent garantir la cohérence.
"Concevoir des applications à forte intensité de données"
- Ce livre est un livre magique pour démarrer avec les systèmes distribués. Il y a une explication sur ACID dans le chapitre sur les transactions :
L'atomicité, l'isolation et la durabilité sont des propriétés de la base de données, tandis que la cohérence (au sens ACID) est une propriété de l'application. Les propriétés d'atomicité et d'isolation de la base de données afin d'obtenir une cohérence, mais cela ne dépend pas uniquement de la base de données. Ainsi, la lettre C n'appartient pas vraiment à ACID.
L'atomicité, l'isolation et la durabilité sont des propriétés de la base de données, alors que la cohérence ( au sens ACID) est une propriété de l'application. Les applications peuvent s'appuyer sur les propriétés d'atomicité et d'isolation de la base de données pour assurer la cohérence, mais cela ne dépend pas uniquement de la base de données. La lettre C n’appartient donc pas à ACID.
Souvent, la cohérence avec laquelle nous avons lutté fait en fait référence à
la cohérence en accord avec le monde réel. La cohérence dans le monde réel est le but ultime des affaires. Afin d'atteindre une cohérence dans le monde réel, les points suivants doivent être respectés :
- Garantir l'atomicité, la durabilité et l'isolement. Si ces caractéristiques ne peuvent pas être garanties, alors la cohérence de la transaction ne peut pas être garantie ;
- Les contraintes de la base de données elle-même, telles que la longueur des chaînes, ne peuvent pas dépasser les limites de colonnes ou les contraintes uniques ; Le niveau doit également être protégé.
-
2.5 Fonctionnalités de transactionNous appelons généralement Redis une base de données en mémoire Différente des bases de données relationnelles traditionnelles, afin de fournir des performances plus élevées et une vitesse d'écriture plus rapide, certaines choses ont été faites au niveau de la conception et de la mise en œuvre. Balanced ne prend pas entièrement en charge l’ACID transactionnel.
Les transactions Redis ont les caractéristiques suivantes :
garantit l'isolement ;
- ne peut pas garantir la durabilité ;
- a un certain degré d'atomicité, mais ne prend pas en charge le rollback ; La cohérence est que sous la sémantique des contraintes, les transactions Redis peuvent assurer la cohérence.
- D'un point de vue technique, en supposant que chaque étape d'une opération de transaction doit s'appuyer sur le résultat renvoyé par l'étape précédente, le verrouillage optimiste doit être implémenté via watch.
-
3 Script Lua
3.1 Introduction
Lua est écrit en standard C. Le code est simple et beau, et peut être compilé et exécuté sur presque tous les systèmes d'exploitation et plates-formes. Les scripts Lua peuvent être facilement appelés par du code C/C++, et peuvent également appeler des fonctions C/C++ à leur tour, ce qui rend Lua largement utilisé dans les applications. Les scripts Lua ont brillé dans le domaine du jeu. Les célèbres "Westward Journey II" et "World of Warcraft" utilisent tous deux largement les scripts Lua. Les scripts Lua peuvent être vus dans les passerelles API avec lesquelles les ingénieurs backend Java sont entrés en contact, telles que
Openresty et
Kong. À partir de la version 2.6.0 de Redis, l'interpréteur Lua intégré de Redis peut exécuter des scripts Lua dans Redis. Avantages de l'utilisation des scripts Lua :
Réduisez la surcharge du réseau. Envoyez plusieurs requêtes à la fois sous la forme d'un script pour réduire la latence du réseau. Opérations atomiques. Redis exécutera l'intégralité du script dans son ensemble et aucune autre commande ne sera insérée au milieu.
- Réutiliser. Le script envoyé par le client sera stocké de manière permanente dans Redis, et d'autres clients pourront réutiliser ce script sans utiliser de code pour compléter la même logique.
- Commandes communes pour les scripts Redis Lua :
-
numéro de série
Commande et description
|
|
1
EVAL script numkeys key [key ...] arg [arg ...] Exécuter Lua scénario.
|
2 |
EVALSHA sha1 numkeys key [key ...] arg [arg ...] Exécutez le script Lua.
|
3 |
SCRIPT EXISTS script [script ...] Vérifiez si le script spécifié a été enregistré dans le cache.
|
4 |
SCRIPT FLUSH Supprime tous les scripts du cache de scripts.
|
5 |
SCRIPT KILL Tue le script Lua en cours d'exécution.
|
6 |
Script SCRIPT LOAD Ajoute un script de script au cache de script, mais n'exécute pas le script immédiatement.
|
3.2 EVAL 命令
命令格式: 1
EVAL script numkeys key [key ...] arg [arg ...] 说明:
-
script 是第一个参数,为 Lua 5.1脚本;
- 第二个参数
numkeys 指定后续参数有几个 key;
-
key [key ...] ,是要操作的键,可以指定多个,在 Lua 脚本中通过KEYS[1] , KEYS[2] 获取;
-
arg [arg ...] ,参数,在 Lua 脚本中通过ARGV[1] , ARGV[2] 获取。
简单实例: 1
redis> eval "return ARGV[1]" 0 100
2
"100"
3
redis> eval "return {ARGV[1],ARGV[2]}" 0 100 101
4
1) "100"
5
2) "101"
6
redis> eval "return {KEYS[1],KEYS[2],ARGV[1]}" 2 key1 key2 first second
7
1) "key1"
8
2) "key2"
9
3) "first"
10
4) "second" 下面演示下 Lua 如何调用 Redis 命令 ,通过redis.call() 来执行了 Redis 命令 。 1
redis> set mystring 'hello world'
2
OK
3
redis> get mystring
4
"hello world"
5
redis> EVAL "return redis.call('GET',KEYS[1])" 1 mystring
6
"hello world"
7
redis> EVAL "return redis.call('GET','mystring')" 0
8
"hello world" 3.3 EVALSHA 命令
使用 EVAL 命令每次请求都需要传输 Lua 脚本 ,若 Lua 脚本过长,不仅会消耗网络带宽,而且也会对 Redis 的性能造成一定的影响。
思路是先将 Lua 脚本先缓存起来 , 返回给客户端 Lua 脚本的 sha1 摘要。 客户端存储脚本的 sha1 摘要 ,每次请求执行 EVALSHA 命令即可。
EVALSHA 命令基本语法如下: 1
redis> EVALSHA sha1 numkeys key [key ...] arg [arg ...] 实例如下: 1
redis> SCRIPT LOAD "return 'hello world'"
2
"5332031c6b470dc5a0dd9b4bf2030dea6d65de91"
3
redis> EVALSHA 5332031c6b470dc5a0dd9b4bf2030dea6d65de91 0
4
"hello world" 4 事务 VS Lua 脚本
从定义上来说, Redis 中的脚本本身就是一种事务, 所以任何在事务里可以完成的事, 在脚本里面也能完成。 并且一般来说, 使用脚本要来得更简单,并且速度更快。
因为脚本功能是 Redis 2.6 才引入的, 而事务功能则更早之前就存在了, 所以 Redis 才会同时存在两种处理事务的方法。
不过我们并不打算在短时间内就移除事务功能, 因为事务提供了一种即使不使用脚本, 也可以避免竞争条件的方法, 而且事务本身的实现并不复杂。
-- redis.io/
Lua 脚本是另一种形式的事务,他具备一定的原子性,但脚本报错的情况下,事务并不会回滚。Lua 脚本可以保证隔离性,而且可以完美的支持后面的步骤依赖前面步骤的结果。
Lua 脚本模式的身影几乎无处不在,比如分布式锁、延迟队列、抢红包等场景。
不过在编写 Lua 脚本时,要注意如下两点:
- 为了避免 Redis 阻塞,Lua 脚本业务逻辑不能过于复杂和耗时;
- 仔细检查和测试 Lua 脚本 ,因为执行 Lua 脚本具备一定的原子性,不支持回滚。
更多编程相关知识,请访问:编程视频!!
|