Avec le développement rapide des affaires et la complexité croissante des affaires, le système de presque toutes les entreprises passera du monolithique au distribué, en particulier à l'architecture de microservices. Vous rencontrerez alors inévitablement le problème des transactions distribuées.
Cet article présente d'abord les théories de base pertinentes, puis résume les solutions de transaction les plus classiques, et enfin fournit des solutions à l'exécution dans le désordre des sous-transactions (idempotence, compensation nulle et problèmes de blocage), qui sont partagées par tout le monde. .
Théorie de base
Avant d'expliquer la solution spécifique, comprenons d'abord les connaissances théoriques de base impliquées dans les transactions distribuées.
Prenons l'exemple du transfert. A doit transférer 100 yuans vers B, puis le solde vers A doit être de -100 yuans et le solde vers B +100 yuans. L'ensemble du transfert doit garantir que A-100 et B. +100 réussissent en même temps, ou les deux échouent. Voyons comment ce problème est résolu dans différents scénarios.
Transaction
La fonction d'exploitation de plusieurs instructions dans leur ensemble est appelée une transaction de base de données. Les transactions de base de données garantissent que toutes les opérations dans le cadre de la transaction peuvent réussir ou échouer.
Les transactions ont 4 propriétés : atomicité, cohérence, isolation et durabilité. Ces quatre propriétés sont souvent appelées propriétés ACIDE.
- Atomicité (atomicité) : Toutes les opérations d'une transaction sont soit complètement terminées, soit non terminées, et ne se termineront par aucun lien intermédiaire. Si une erreur survient 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.
- Cohérence : l'intégrité de la base de données n'est pas compromise avant le début et après la fin de la transaction. L'intégrité, y compris les contraintes de clé étrangère, les contraintes définies par l'application, etc. ne sera pas détruite.
- Isolement : la base de données permet à plusieurs transactions simultanées de lire, d'écrire et de modifier ses données en même temps. L'isolement peut empêcher l'incohérence des données due à l'exécution croisée lorsque plusieurs transactions sont exécutées simultanément.
- Durabilité : 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.
Si notre système commercial n'est pas compliqué et que nous pouvons modifier les données et effectuer le transfert dans une seule base de données et un seul service, nous pouvons alors utiliser les transactions de base de données pour garantir la bonne exécution de l'activité de transfert.
Transactions distribuées
Les opérations de transfert interbancaire sont un scénario de transaction distribué typique. Supposons que A doive transférer de l'argent à B entre les banques, ce qui implique les données de deux banques. L'ACID du transfert ne peut pas être garanti par une transaction locale. une base de données. Résolu via des transactions distribuées.
Une transaction distribuée signifie que l'initiateur de la transaction, la ressource et le gestionnaire de ressources ainsi que le coordinateur de transaction sont situés sur différents nœuds du système distribué. Dans l'activité de transfert ci-dessus, l'opération de l'utilisateur A-100 et l'opération de l'utilisateur B+100 ne sont pas situées sur le même nœud. Essentiellement, les transactions distribuées visent à garantir la bonne exécution des opérations de données dans des scénarios distribués.
Les transactions distribuées dans un environnement distribué, afin de répondre aux besoins de disponibilité, de performances et de services de rétrogradation, et de réduire les exigences de cohérence et d'isolement, d'une part, suivent la théorie BASE (théorie liée à BASE, impliquant beaucoup de contenu, étudiants intéressés, vous pouvez vous référer à la théorie BASE) :
- Disponibilité métier de base (Basic Availability)
- Soft state (Soft state)
- Cohérence éventuelle (Cohérence éventuelle)
De même, les transactions distribuées suivent également partiellement le Spécification ACID :
- Atomicité : strictement suivie
- Cohérence : la cohérence une fois la transaction terminée est strictement respectée ; la cohérence au sein de la transaction peut être assouplie de manière appropriée
- Isolement : les transactions parallèles ne peuvent pas être affectées ; la visibilité des résultats des transactions intermédiaires permet une relaxation en toute sécurité ; Durabilité : suivez strictement la
Deuxième phase (commit/rollback) : Lorsque le gestionnaire de transactions (TM) confirme que tous les participants (RM) sont prêts, il envoie une commande de validation à tous les participants.
Les bases de données actuellement grand public prennent essentiellement en charge les transactions XA, y compris mysql, oracle, sqlserver et postgre
Les trois rôles de RM, TM et AP ici sont des divisions de rôles classiques, qui seront utilisées tout au long des modes de transaction Saga, Tcc et autres suivants.
Prenons le transfert ci-dessus comme exemple. Un diagramme de séquence de transactions XA terminé avec succès est le suivant :
Si un participant ne parvient pas à se préparer, alors TM informera tous les participants qui ont terminé la préparation d'annuler.
Les caractéristiques des transactions XA sont :
- Simple et facile à comprendre, plus facile à développer
- Verrouillage à long terme des ressources, faible concurrence
Si les lecteurs souhaitent approfondir leurs études sur XA, optez pour le langage, PHP, Python, Java, C#, Node, etc. peuvent faire référence à DTM
SAGA
Saga est une solution mentionnée par les sagas dans cet article de base de données. L'idée principale est de diviser une transaction longue en plusieurs transactions courtes locales, coordonnées par le coordinateur des transactions Saga. Si elle se termine normalement, elle se terminera normalement. Si une étape échoue, l'opération de compensation sera appelée une fois dans l'ordre inverse.
En prenant le transfert ci-dessus comme exemple, un diagramme de séquence de transactions SAGA terminé avec succès est le suivant :
Une fois que Saga atteint l'étape d'annulation, Cancel n'est pas autorisé à échouer dans la logique métier. Si le succès n'est pas renvoyé en raison d'une défaillance du réseau ou d'autres échecs temporaires, TM continuera à réessayer jusqu'à ce que Cancel renvoie le succès.
Caractéristiques des transactions Saga :
- Concurrence élevée, pas besoin de verrouiller les ressources pendant une longue période comme les transactions XA
- Besoin de définir les opérations normales et les opérations de compensation, le volume de développement est plus grand que XA
- La cohérence est faible, pour transferts, A peut se produire L'utilisateur a déduit l'argent et le transfert final a de nouveau échoué
Il y a beaucoup de contenu SAGA dans le document, y compris deux stratégies de récupération, y compris l'exécution simultanée des transactions de succursale. Notre discussion ici ne comprend que les plus simples. SAGA
SAGA est applicable Il existe de nombreux scénarios, il convient aux transactions longues et il convient aux scénarios commerciaux qui ne sont pas sensibles aux résultats intermédiaires
Si les lecteurs souhaitent approfondir SAGA, ils peuvent se référer au DTM, qui comprend des exemples de réussite et d'échec de restauration de SAGA, ainsi que diverses anomalies du réseau.
TCC
Le concept de TCC (Try-Confirm-Cancel) a été proposé pour la première fois par Pat Helland dans un article intitulé « La vie au-delà des transactions distribuées : l'opinion d'un apostat » publié en 2007.
TCC est divisé en 3 étapes
- Étape d'essai : essayer d'exécuter, effectuer tous les contrôles commerciaux (cohérence), réserver les ressources commerciales nécessaires (quasi-isolement)
- Étape de confirmation : confirmer que l'exécution exécute réellement l'entreprise, et aucune opération n'est effectuée. Vérifiez que seules les ressources métier réservées lors de la phase d'essai sont utilisées. L'opération de confirmation nécessite une conception idempotente. Vous devez réessayer après l'échec de la confirmation.
- Phase d'annulation : annulez l'exécution et libérez les ressources métier réservées dans la phase d'essai. Le schéma de gestion des exceptions dans la phase Cancel est fondamentalement le même que celui de la phase Confirm et nécessite une conception idempotente.
Prenons le transfert ci-dessus comme exemple. Habituellement, le montant est gelé dans Try mais pas déduit. Le montant est déduit dans Confirm et le montant est dégelé dans Cancel. Un diagramme de séquence de transaction TCC terminé avec succès est le suivant :
.
TCC La logique métier de la phase de confirmation/annulation ne permet pas de renvoyer un échec. Si le succès ne peut pas être renvoyé en raison d'un réseau ou d'autres échecs temporaires, TM continuera à réessayer jusqu'à ce que Confirm/Annuler renvoie le succès.
Les fonctionnalités TCC sont les suivantes :
- Concurrence élevée et pas de verrouillage des ressources à long terme.
- Le volume de développement est important et l'interface Try/Confirm/Cancel doit être fournie.
- La cohérence est meilleure, et il n'y aura aucune situation où SAGA a déduit l'argent puis n'a pas réussi à transférer l'argent
- TCC convient aux entreprises de type commande, aux entreprises avec des contraintes sur les états intermédiaires
Si les lecteurs. Si vous souhaitez étudier plus en détail TCC, vous pouvez vous référer au DTM
Local Message Table
Cette solution était à l'origine un article publié par l'architecte eBay Dan Pritchett à ACM en 2008. Le cœur de la conception est d'assurer de manière asynchrone l'exécution de tâches nécessitant un traitement distribué via des messages.
Le processus général est le suivant :
Le regroupement des messages locaux et des opérations commerciales en une seule transaction garantit l'atomicité des affaires et de l'envoi des messages. Soit ils réussissent tous, soit ils échouent tous.
Mécanisme de tolérance aux pannes :
- Lorsque la transaction de déduction du solde échoue, la transaction est annulée directement sans étapes ultérieures
- Si le message de production de la séquence de roues échoue, si la transaction d'augmentation du solde échoue, elle sera réessayée
Caractéristiques de la table de messages locale :
- Les transactions longues doivent uniquement être divisées en plusieurs tâches, faciles à utiliser
- Le producteur doit créer une table de messages supplémentaire
- Chaque table de messages locale doit être interrogée
- Si le consommateur la logique échoue après une nouvelle tentative, alors davantage de mécanismes sont nécessaires pour annuler les opérations
Applicable aux entreprises qui peuvent être exécutées de manière asynchrone et les opérations ultérieures ne nécessitent pas d'annulation
Message de transaction
Dans la solution de table de messages locaux ci-dessus, le producteur doit créer une table de messages supplémentaire et interroger la table de messages locale, ce qui impose une lourde charge commerciale. L'open source RocketMQ 4.3 et versions ultérieures d'Alibaba prennent officiellement en charge les messages de transaction. Ce message de transaction place essentiellement la table de messages locaux sur RocketMQ pour résoudre le problème d'atomicité de l'envoi de messages et de l'exécution de transactions locales du côté de la production.
Envoi et soumission du message de transaction :
- Envoyer un message (demi-message)
- Le serveur stocke le message et répond au résultat de l'écriture du message
- Exécuter des transactions locales en fonction du résultat de l'envoi (si l'écriture échoue, le demi-message est L'entreprise n'est pas visible et la logique locale n'est pas exécutée)
- Exécutez Commit ou Rollback en fonction de l'état de la transaction locale (l'opération Commit publie le message, le message est visible pour les consommateurs)
L'organigramme de l'envoi normal est le suivant :
Processus de compensation :
Pour les messages de transaction sans Commit/Rollback (messages en attente), lancez une "révision" depuis le serveur
Le producteur reçoit le message de révision et renvoie l'état du transaction locale correspondant au message, qui est Commit ou Rollback
Solution de message de transaction Il est très similaire au mécanisme de table de message local. La principale différence est que les opérations de table locale associées d'origine sont remplacées par une interface de requête inversée
Les caractéristiques. des messages de transaction sont les suivants :
- Les transactions longues doivent uniquement être divisées en plusieurs tâches et une requête inverse est fournie.Interface simple à utiliser
- Si la logique du consommateur ne parvient pas à réussir une nouvelle tentative, davantage de mécanismes sont nécessaires pour revenir en arrière. l'opération
Applicable aux entreprises qui peuvent être exécutées de manière asynchrone, et les opérations ultérieures ne nécessitent pas de restauration
Si les lecteurs qui souhaitent approfondir l'étude des messages de transaction peuvent se référer au DTM ou à Rocketmq
Notification de meilleur effort
La partie de notification initiatrice utilise un certain mécanisme pour faire de son mieux pour informer le destinataire des résultats du traitement commercial. Incluez spécifiquement :
Il existe un certain mécanisme de notification de répétition de message. Étant donné que la partie qui reçoit la notification peut ne pas recevoir la notification, un certain mécanisme doit être en place pour notifier le message à plusieurs reprises.
Mécanisme de relecture des messages. Si le destinataire n'est pas averti malgré tous ses efforts, ou s'il souhaite consommer à nouveau le message après l'avoir consommé, le destinataire peut activement interroger le notificateur pour obtenir des informations sur le message afin de répondre à la demande.
Le tableau des messages locaux et les messages de transaction introduits précédemment sont tous deux des messages fiables. En quoi sont-ils différents de la notification au mieux présentée ici ?
Cohérence fiable du message. La partie de notification initiatrice doit s'assurer que le message est envoyé et envoyé à la partie de notification réceptrice. La clé de la fiabilité du message est garantie par la partie de notification initiatrice.
Notification au mieux, la partie qui initie la notification fait de son mieux pour informer la partie destinataire des résultats du traitement commercial, mais le message peut ne pas être reçu à ce moment, la partie réceptrice doit appeler activement l'interface de la partie initiatrice. pour interroger les résultats du traitement commercial et la notification. La clé de la fiabilité est la partie qui reçoit la notification.
En termes de solution, la notification au mieux nécessite :
- Fournir une interface afin que le destinataire de la notification puisse interroger les résultats du traitement commercial via l'interface
- Mécanisme ACK de file d'attente de messages, la file d'attente de messages est basée sur l'intervalle de 1 min, 5 min, 10 min, 30 min, 1 h, 2 h, 5 h et 10 h, et augmentez progressivement l'intervalle de notification jusqu'à ce que la limite supérieure de la fenêtre de temps requise pour la notification soit atteinte. Plus de notifications par la suite
Les notifications de meilleur effort conviennent aux types de notifications commerciales. Par exemple, les résultats des transactions WeChat sont notifiés à chaque commerçant via des notifications de meilleur effort. Il existe à la fois des notifications de rappel et des interfaces de requête de transaction
Mode de transaction AT
.Il s'agit d'un modèle de transaction dans le projet open source d'Alibaba Seata est également appelé FMT dans Ant Financial. L'avantage est que le mode transaction est utilisé d'une manière similaire au mode XA. L'entreprise n'a pas besoin d'écrire diverses opérations de compensation et le rollback est automatiquement effectué par le framework. L'inconvénient est également similaire à XA. -verrouillages à terme, qui ne répondent pas aux scénarios de concurrence élevée. Du point de vue des performances, le mode AT est supérieur au mode XA, mais il entraîne également de nouveaux problèmes tels qu'une restauration sale. Les étudiants intéressés peuvent se référer à Seata-AT
Gestion des exceptions
Dans tous les aspects des transactions distribuées, des problèmes tels que des pannes de réseau et d'entreprise peuvent survenir. Ces problèmes nécessitent que le côté commercial des transactions distribuées soit anti-rollback et idempotent. -suspendre trois caractéristiques.
Exceptions
Ce qui suit utilise des transactions TCC pour illustrer ces exceptions :
Annulation vide :
La méthode Cancel de deuxième étape est appelée sans appeler la méthode Try de la ressource TCC. La méthode Cancel doit identifier ceci. rollback vide puis revient directement au succès.
La raison en est que lorsqu'une transaction de branche présente un temps d'arrêt du service ou une anomalie du réseau, l'appel de transaction de branche est enregistré comme un échec. À ce stade, la phase d'essai n'est pas réellement exécutée. Lorsque l'erreur est restaurée, la transaction distribuée est enregistrée. sera annulé et la deuxième phase sera appelée la méthode Cancel, formant ainsi un rollback vide.
Idempotence :
Étant donné que toute demande peut présenter des anomalies de réseau et des demandes répétées, toutes les branches de transactions distribuées doivent garantir l'idempotence
Suspension :
La suspension est destinée à une distribution. Dans cette transaction, l'interface d'annulation de la deuxième étape est exécuté avant l'interface Try.
La raison est que lorsque RPC appelle branch transaction try, la transaction de branche est enregistrée en premier, puis l'appel RPC est exécuté si le réseau appelé par RPC est encombré à ce moment-là, après l'expiration du délai RPC, TM informera RM. annuler la transaction distribuée, ce qui peut se produire. Une fois le basculement terminé, la requête Try RPC parvient au participant et est réellement exécutée.
Regardons le chronogramme d'une exception réseau pour mieux comprendre les problèmes ci-dessus
- Lors du traitement de la demande 4, Cancel est exécuté avant Try, et une restauration vide doit être traitée
- Lors du traitement de la demande 6 , Cancel est exécuté à plusieurs reprises et doit être idempotent
- Lorsque la demande de traitement métier 8 est exécutée, Try est exécuté après Cancel et la suspension doit être gérée
Face aux anomalies de réseau complexes ci-dessus, les solutions actuellement recommandé par diverses entreprises sont côté entreprise Utilisez la clé unique pour demander si l'opération associée a été terminée. Si elle est terminée, le succès sera renvoyé directement. La logique de jugement pertinente est complexe, sujette aux erreurs et représente une lourde charge commerciale.
Barrière de sous-transaction
Dans le projet https://github.com/yedf/dtm, une technologie de barrière de sous-transaction est apparue En utilisant cette technologie, cet effet peut être obtenu Voir le schéma :
Tous. ces demandes, Après avoir atteint la barrière de sous-transaction : les demandes anormales seront filtrées ; les demandes normales franchiront la barrière. Une fois que les développeurs ont utilisé les barrières de sous-transaction, toutes les exceptions mentionnées ci-dessus sont correctement gérées et les développeurs commerciaux n'ont qu'à se concentrer sur la logique métier réelle, et le fardeau est considérablement réduit.
La barrière de sous-transaction fournit la méthode ThroughBarrierCall. Le prototype de la méthode est :
func ThroughBarrierCall(db *sql.DB, transInfo *TransInfo, busiCall BusiFunc)
Les développeurs commerciaux peuvent écrire leur propre logique associée dans busiCall et appeler cette fonction. ThroughBarrierCall garantit que busiCall ne sera pas appelé dans des scénarios tels qu'une restauration à vide et une suspension lorsque l'entreprise est appelée à plusieurs reprises, il existe un contrôle idempotent pour garantir qu'il n'est soumis qu'une seule fois ;
La barrière de sous-transaction gérera TCC, SAGA, les messages de transaction, etc., et peut également être étendue à d'autres domaines
Principe de la barrière de sous-transaction
Le principe de la technologie de barrière de sous-transaction est d'établir une transaction de succursale table d'état sub_trans_barrier dans la base de données locale, avec une clé unique Ouvrir une transaction pour la transaction globale id-sub-transaction id-sub-transaction branch name (try|confirm|cancel)
- S'il s'agit d'une branche Try, puis insérez ignore insert gid-branchid-try, si l'insertion est réussie, appelez la barrière Logique interne
- S'il s'agit de la branche Confirm, alors insérez ignore insère gid-branchid-confirm Si l'insertion est réussie, appelez la barrière interne. logique
- S'il s'agit de la branche Cancel, alors insert ignore insère gid-branchid-try, puis insère gid-branchid -cancel, si try n'est pas inséré et que Cancel est inséré avec succès, appelez la logique dans la barrière
- La logique à l'intérieur de la barrière renvoie le succès, valide la transaction, renvoie le succès
- La logique à l'intérieur de la barrière renvoie une erreur, annule la transaction, renvoie une erreur
Dans ce mécanisme Ensuite, les problèmes liés aux anomalies du réseau sont résolus
- Vide contrôle de compensation - si Try n'est pas exécuté et Cancel est exécuté directement, alors Cancel sera inséré avec succès dans gid-branchid-try sans utiliser la logique à l'intérieur de la barrière, garantissant un contrôle de compensation vide
- Contrôle impuissant - Aucune clé unique ne peut être inséré à plusieurs reprises dans n'importe quelle branche, garantissant qu'il ne sera pas exécuté à plusieurs reprises
- Contrôle anti-suspension - Try est exécuté après l'annulation, et si le gid-branchid-try inséré échoue, il ne sera pas exécuté, garantissant l'anti-. contrôle suspendu
Il existe un mécanisme similaire pour SAGA, les messages de transaction, etc.
Résumé de la barrière de sous-transaction
La technologie de barrière de sous-transaction est la première du genre sur https://github.com/yedf/dtm. Son importance réside dans la conception d'algorithmes simples et faciles à mettre en œuvre et dans la fourniture d'un. interface simple et facile à utiliser. En premier lieu, l'importance est de concevoir des algorithmes simples et faciles à mettre en œuvre et de fournir des interfaces simples et faciles à utiliser. Avec l'aide de ces deux éléments, les développeurs sont complètement. libéré du traitement des exceptions réseau.
Cette technologie doit actuellement être associée au gestionnaire de transactions yedf/dtm. Actuellement, le SDK a été fourni aux développeurs des langages Go et Python. Des SDK dans d'autres langues sont en préparation. Pour d'autres cadres de transactions distribuées, tant que les informations appropriées sur les transactions distribuées sont fournies, la technologie peut être rapidement mise en œuvre selon les principes ci-dessus.
Résumé
Cet article présente quelques théories de base des transactions distribuées et explique les solutions de transactions distribuées couramment utilisées. Dans la seconde moitié de l'article, les raisons, les classifications et les solutions élégantes pour les exceptions de transaction sont également données.
yedf/dtm prend en charge TCC, XA, SAGA, les messages de transaction, les notifications de meilleur effort (implémentées à l'aide de messages de transaction), fournit la prise en charge des protocoles HTTP et gRPC et est très facile d'accès.
yedf/dtm a pris en charge des clients en Python, Java, PHP, C#, Node et d'autres langages, voir : SDK pour chaque langage.
Bienvenue à tous pour visiter le projet https://github.com/yedf/dtm et donner une étoile pour le soutenir !