Transactions sur les microservices REST?

195

Disons que nous avons un utilisateur, des microservices Wallet REST et une passerelle API qui rassemble les choses. Lorsque Bob s'inscrit sur notre site Web, notre passerelle API doit créer un utilisateur via le microservice Utilisateur et un portefeuille via le microservice Wallet.

Voici maintenant quelques scénarios où les choses pourraient mal tourner:

  • La création de l'utilisateur Bob échoue: c'est OK, nous renvoyons simplement un message d'erreur au Bob. Nous utilisons des transactions SQL, donc personne n'a jamais vu Bob dans le système. Tout est bien :)

  • L'utilisateur Bob est créé mais avant que notre portefeuille ne puisse être créé, notre passerelle API plante. Nous avons maintenant un utilisateur sans portefeuille (données incohérentes).

  • L'utilisateur Bob est créé et au fur et à mesure que nous créons le portefeuille, la connexion HTTP est interrompue. La création du portefeuille a peut-être réussi ou non.

Quelles solutions sont disponibles pour éviter ce type d'incohérence des données? Existe-t-il des modèles qui permettent aux transactions de couvrir plusieurs demandes REST? J'ai lu la page Wikipédia sur le commit en deux phases qui semble aborder ce problème, mais je ne sais pas comment l'appliquer dans la pratique. Ce document Atomic Distributed Transactions: un article de conception RESTful semble également intéressant même si je ne l'ai pas encore lu.

Sinon, je sais que REST pourrait ne pas convenir à ce cas d'utilisation. La manière correcte de gérer cette situation serait-elle peut-être d'abandonner complètement REST et d'utiliser un protocole de communication différent comme un système de file d'attente de messages? Ou devrais-je appliquer la cohérence dans le code de mon application (par exemple, en ayant un travail d'arrière-plan qui détecte les incohérences et les corrige ou en ayant un attribut «état» sur mon modèle utilisateur avec des valeurs «création», «créé», etc.)?

Olivier Lalonde
la source
3
Lien intéressant: news.ycombinator.com/item?id=7995130
Olivier Lalonde
3
Si un utilisateur n'a pas de sens sans portefeuille, pourquoi créer un microservice séparé pour lui? Peut-être que quelque chose ne va pas avec l'architecture en premier lieu? Pourquoi avez-vous besoin d'une passerelle API générique, btw? Y a-t-il une raison particulière à cela?
Vladislav Rastrusny
4
@VladislavRastrusny c'était un exemple fictif, mais vous pourriez penser que le service de portefeuille est géré par Stripe par exemple.
Olivier Lalonde
Vous pouvez utiliser un gestionnaire de processus pour suivre la transaction (modèle de gestionnaire de processus) ou faire en sorte que chaque microservice sache comment déclencher une restauration (modèle de gestionnaire de saga) ou faire une sorte de validation en deux phases ( blog.aspiresys.com/software-product-engineering / producteering /… )
andrew pate
@VladislavRastrusny "Si un utilisateur n'a pas de sens sans portefeuille, pourquoi créer un microservice séparé pour lui" - par exemple, mis à part le fait qu'un utilisateur ne peut pas exister sans portefeuille, ils n'ont aucun code en commun. Ainsi, deux équipes vont développer et déployer indépendamment les microservices utilisateur et portefeuille. N'est-ce pas tout l'intérêt de faire des microservices en premier lieu?
Nik

Réponses:

148

Ce qui n'a pas de sens:

  • transactions distribuées avec les services REST . Les services REST, par définition, sont sans état, ils ne doivent donc pas être des participants à une limite transactionnelle qui couvre plusieurs services. Votre scénario d'utilisation d'enregistrement d'utilisateur a du sens, mais la conception avec des microservices REST pour créer des données d'utilisateur et de portefeuille n'est pas bonne.

Qu'est-ce qui vous donnera des maux de tête:

  • EJB avec transactions distribuées . C'est l'une de ces choses qui fonctionnent en théorie mais pas en pratique. En ce moment, j'essaie de faire fonctionner une transaction distribuée pour les EJB distants sur les instances JBoss EAP 6.3. Nous discutons avec le support RedHat depuis des semaines, et cela n'a pas encore fonctionné.
  • Solutions d'engagement en deux phases en général . Je pense que le protocole 2PC est un excellent algorithme (il y a de nombreuses années, je l'ai implémenté en C avec RPC). Il nécessite des mécanismes complets de reprise après échec, avec des tentatives, un référentiel d'état, etc. Toute la complexité est cachée dans le cadre de la transaction (ex .: JBoss Arjuna). Cependant, 2PC n'est pas infaillible. Il y a des situations que la transaction ne peut tout simplement pas terminer. Ensuite, vous devez identifier et corriger manuellement les incohérences de la base de données. Cela peut arriver une fois sur un million de transactions si vous avez de la chance, mais cela peut arriver une fois sur 100 transactions en fonction de votre plate-forme et de votre scénario.
  • Sagas (transactions compensatoires) . Il y a les frais généraux de mise en œuvre pour créer les opérations de compensation et le mécanisme de coordination pour activer la compensation à la fin. Mais la compensation n'est pas non plus à l'épreuve des échecs. Vous pouvez toujours vous retrouver avec des incohérences (= quelques maux de tête).

Quelle est probablement la meilleure alternative:

  • Cohérence éventuelle . Ni les transactions distribuées de type ACID ni les transactions de compensation ne sont à l'épreuve des échecs, et les deux peuvent conduire à des incohérences. La cohérence finale est souvent meilleure qu'une «incohérence occasionnelle». Il existe différentes solutions de conception, telles que:
    • Vous pouvez créer une solution plus robuste en utilisant une communication asynchrone. Dans votre scénario, lorsque Bob s'inscrit, la passerelle API peut envoyer un message à une file d'attente NewUser et répondre immédiatement à l'utilisateur en disant «Vous recevrez un e-mail pour confirmer la création du compte». Un service consommateur de file d'attente peut traiter le message, effectuer les modifications de base de données en une seule transaction et envoyer l'e-mail à Bob pour notifier la création du compte.
    • Le microservice Utilisateur crée l'enregistrement utilisateur et un enregistrement de portefeuille dans la même base de données . Dans ce cas, le magasin de portefeuille dans le microservice utilisateur est une réplique du magasin de portefeuille principal uniquement visible par le microservice de portefeuille. Il existe un mécanisme de synchronisation des données basé sur des déclencheurs ou qui se déclenche périodiquement pour envoyer les modifications de données (par exemple, de nouveaux portefeuilles) de la réplique au maître, et vice-versa.

Mais que faire si vous avez besoin de réponses synchrones?

  • Remodeler les microservices . Si la solution avec la file d'attente ne fonctionne pas parce que le consommateur de service a besoin d'une réponse immédiate, alors je préfère remodeler la fonctionnalité utilisateur et portefeuille pour qu'elle soit colocalisée dans le même service (ou au moins dans la même machine virtuelle pour éviter les transactions distribuées. ). Oui, c'est un peu plus loin des microservices et plus proche d'un monolithe, mais cela vous évitera quelques maux de tête.
Paulo Merson
la source
4
La cohérence finale a fonctionné pour moi. Dans ce cas, la file d'attente "NewUser" doit être hautement disponible et résiliente.
Ram Bavireddi
@RamBavireddi est-ce que Kafka ou RabbitMQ prennent en charge les files d'attente résilientes?
v.oddou
@ v.oddou Oui, ils le font.
Ram Bavireddi
2
@PauloMerson Je ne sais pas comment vous différenciez les transactions de compensation de la cohérence éventuelle. Et si, dans votre cohérence éventuelle, la création du portefeuille échoue?
balsick
2
@balsick L'un des défis des éventuels paramètres de cohérence est l'augmentation de la complexité de la conception. Des contrôles de cohérence et des événements de correction sont souvent nécessaires. La conception de la solution varie. Dans la réponse, je suggère la situation où l'enregistrement Wallet est créé dans la base de données lors du traitement d'un message envoyé via un courtier de messages. Dans ce cas, nous pourrions définir un canal de lettre morte, c'est-à-dire que si le traitement de ce message génère une erreur, nous pouvons envoyer le message dans une file d'attente de lettres mortes et avertir l'équipe responsable du «portefeuille».
Paulo Merson
66

C'est une question classique qui m'a été posée récemment lors d'une interview Comment appeler plusieurs services Web tout en conservant une sorte de gestion des erreurs au milieu de la tâche. Aujourd'hui, dans le calcul haute performance, on évite les engagements en deux phases. J'ai lu un article il y a de nombreuses années sur ce qu'on appelait le «modèle Starbuck» pour les transactions: Pensez au processus de commande, de paiement, de préparation et de réception du café que vous commandez chez Starbuck ... Je simplifie à l'extrême les choses, mais un modèle de validation en deux phases suggérez que l'ensemble du processus consisterait en une seule transaction d'emballage pour toutes les étapes impliquées jusqu'à ce que vous receviez votre café. Cependant, avec ce modèle, tous les employés attendraient et arrêtaient de travailler jusqu'à ce que vous ayez votre café. Vous voyez l'image?

Au lieu de cela, le «modèle Starbuck» est plus productif en suivant le modèle du «meilleur effort» et en compensant les erreurs dans le processus. Tout d'abord, ils s'assurent que vous payez! Ensuite, il y a des files d'attente de messages avec votre commande attachée à la tasse. Si quelque chose ne va pas dans le processus, comme si vous n'avez pas obtenu votre café, ce n'est pas ce que vous avez commandé, etc., nous entrons dans le processus de compensation et nous nous assurons que vous obtenez ce que vous voulez ou vous rembourser, c'est le modèle le plus efficace pour une productivité accrue.

Parfois, Starbuck gaspille un café, mais le processus global est efficace. Il y a d'autres astuces à penser lorsque vous créez vos services Web, comme les concevoir de manière à ce qu'ils puissent être appelés un nombre illimité de fois tout en fournissant le même résultat final. Donc, ma recommandation est:

  • Ne soyez pas trop fin dans la définition de vos services web (je ne suis pas convaincu du battage médiatique des micro-services ces jours-ci: trop de risques d'aller trop loin);

  • Async augmente les performances, alors préférez être asynchrone, envoyez des notifications par e-mail chaque fois que possible.

  • Construisez des services plus intelligents pour les rendre "rappelables" un nombre illimité de fois, en les traitant avec un uid ou un taskid qui suivra l'ordre de bas en haut jusqu'à la fin, en validant les règles métier à chaque étape;

  • Utilisez des files d'attente de messages (JMS ou autres) et détournez-les vers des processeurs de gestion des erreurs qui appliqueront des opérations à la «restauration» en appliquant des opérations opposées, d'ailleurs, travailler avec un ordre asynchrone nécessitera une sorte de file d'attente pour valider l'état actuel du processus, alors considérez cela;

  • En dernier recours, (car cela peut ne pas arriver souvent), mettez-le dans une file d'attente pour le traitement manuel des erreurs.

Revenons au problème initial qui a été signalé. Créez un compte et créez un portefeuille et assurez-vous que tout a été fait.

Disons qu'un service Web est appelé pour orchestrer l'ensemble de l'opération.

Le pseudo code du service Web ressemblerait à ceci:

  1. Appelez le microservice de création de compte, transmettez-lui des informations et un microservice de création de compte ID de tâche unique 1.1 vérifiera d'abord si ce compte a déjà été créé. Un identifiant de tâche est associé à l'enregistrement du compte. Le microservice détecte que le compte n'existe pas, il le crée et stocke l'ID de la tâche. REMARQUE: ce service peut être appelé 2000 fois, il effectuera toujours le même résultat. Le service répond par un "reçu contenant des informations minimales pour effectuer une opération d'annulation si nécessaire".

  2. Appelez la création du portefeuille, en lui donnant l'ID de compte et l'ID de tâche. Disons qu'une condition n'est pas valide et que la création du portefeuille ne peut pas être effectuée. L'appel retourne avec une erreur mais rien n'a été créé.

  3. L'orchestrateur est informé de l'erreur. Il sait qu'il doit abandonner la création du compte, mais il ne le fera pas lui-même. Il demandera au service de portefeuille de le faire en transmettant son «reçu d'annulation minimal» reçu à la fin de l'étape 1.

  4. Le service de compte lit le reçu d'annulation et sait comment annuler l'opération; le reçu d'annulation peut même inclure des informations sur un autre microservice qu'il aurait pu appeler lui-même pour faire une partie du travail. Dans cette situation, le reçu d'annulation peut contenir l'ID de compte et éventuellement des informations supplémentaires nécessaires pour effectuer l'opération inverse. Dans notre cas, pour simplifier les choses, disons que c'est simplement supprimer le compte en utilisant son identifiant de compte.

  5. Maintenant, disons que le service Web n'a jamais reçu le succès ou l'échec (dans ce cas) que l'annulation de la création du compte a été effectuée. Il appellera simplement à nouveau le service d'annulation du compte. Et ce service ne devrait normalement jamais échouer car son objectif est que le compte n'existe plus. Il vérifie donc s'il existe et voit que rien ne peut être fait pour l'annuler. Il revient donc que l'opération est un succès.

  6. Le service Web renvoie à l'utilisateur que le compte n'a pas pu être créé.

Ceci est un exemple synchrone. Nous aurions pu le gérer d'une manière différente et placer le cas dans une file d'attente de messages destinée au service d'assistance si nous ne voulions pas que le système récupère complètement l'erreur ". J'ai vu cela se faire dans une entreprise où ce n'est pas assez des hooks pouvaient être fournis au système dorsal pour corriger les situations. Le service d'assistance recevait des messages contenant ce qui avait été effectué avec succès et disposait de suffisamment d'informations pour corriger les choses, tout comme notre reçu d'annulation pouvait être utilisé de manière entièrement automatisée.

J'ai effectué une recherche et le site Web de Microsoft a une description de modèle pour cette approche. C'est ce qu'on appelle le modèle de transaction de compensation:

Modèle de transaction compensatoire

user8098437
la source
2
Pensez-vous que vous pourriez développer cette réponse pour fournir des conseils plus spécifiques au PO. En l'état, cette réponse est quelque peu vague et difficile à comprendre. Bien que je comprenne comment le café est servi chez Starbucks, je ne sais pas quels aspects de ce système devraient être émulés dans les services REST.
jwg
J'ai ajouté un exemple lié au cas initialement fourni dans le message d'origine.
user8098437
2
Je viens d'ajouter un lien vers le modèle de transaction de compensation tel que décrit par Microsoft.
user8098437
3
Pour moi, c'est la meilleure réponse. Si simple
Oscar Nevarez
1
Notez que la compensation des transactions peut être carrément impossible dans certains scénarios complexes (comme cela est brillamment souligné dans la documentation Microsoft). Dans cet exemple, imaginez avant que la création du portefeuille n'échoue, quelqu'un pourrait lire les détails du compte associé en effectuant un appel GET sur le service Compte, qui idéalement ne devrait pas exister en premier lieu car la création du compte a échoué. Cela peut entraîner une incohérence des données. Ce problème d'isolement est bien connu dans le modèle SAGAS.
Anmol Singh Jaggi le
32

Tous les systèmes distribués ont des problèmes de cohérence transactionnelle. La meilleure façon de faire est, comme vous l'avez dit, d'avoir un commit en deux phases. Faites en sorte que le portefeuille et l'utilisateur soient créés dans un état en attente. Après sa création, effectuez un appel séparé pour activer l'utilisateur.

Ce dernier appel doit être répétable en toute sécurité (au cas où votre connexion serait interrompue).

Cela nécessitera que le dernier appel connaisse les deux tables (afin que cela puisse être fait en une seule transaction JDBC).

Sinon, vous voudrez peut-être réfléchir aux raisons pour lesquelles vous êtes si inquiet pour un utilisateur sans portefeuille. Pensez-vous que cela posera un problème? Si c'est le cas, peut-être que les avoir comme appels de repos séparés est une mauvaise idée. Si un utilisateur ne devrait pas exister sans portefeuille, vous devriez probablement ajouter le portefeuille à l'utilisateur (dans l'appel POST d'origine pour créer l'utilisateur).

Rob Conklin
la source
Merci pour la suggestion. Les services User / Wallet étaient fictifs, juste pour illustrer ce point. Mais je conviens que je devrais concevoir le système de manière à éviter autant que possible le besoin de transactions.
Olivier Lalonde
7
Je suis d'accord avec le deuxième point de vue. Il semble, ce que votre microservice, qui crée l'utilisateur, devrait également créer un portefeuille, car cette opération représente une unité de travail atomique. Aussi, vous pouvez lire ce eaipatterns.com/docs/IEEE_Software_Design_2PC.pdf
Sattar Imamov
2
C'est en fait une excellente idée. Les undos sont un casse-tête. Mais créer quelque chose dans un état d'attente est beaucoup moins invasif. Tous les contrôles ont été effectués, mais rien de définitif n'est encore créé. Il ne nous reste plus qu'à activer les composants créés. Nous pouvons probablement même le faire de manière non transactionnelle.
Timo
10

À mon humble avis, l'un des aspects clés de l'architecture des microservices est que la transaction est limitée au microservice individuel (principe de responsabilité unique).

Dans l'exemple actuel, la création de l'utilisateur serait une propre transaction. La création d'un utilisateur pousserait un événement USER_CREATED dans une file d'attente d'événements. Le service Wallet s'abonnerait à l'événement USER_CREATED et effectuerait la création du portefeuille.

mithrandir
la source
1
En supposant que nous voulons éviter tout 2PC, et en supposant que le service utilisateur écrit dans une base de données, nous ne pouvons pas faire pousser le message dans une file d'attente d'événements par l'utilisateur pour être transactionnel, ce qui signifie qu'il ne peut jamais le faire. le service Wallet.
Roman Kharkovski
@RomanKharkovski Un point important en effet. Une façon de résoudre ce problème peut être de démarrer une transaction, d'enregistrer l'utilisateur, de publier l'événement (ne faisant pas partie de la transaction), puis de valider la transaction. (Dans le pire des cas, hautement improbable, la validation échoue et ceux qui répondent à l'événement ne pourront pas trouver l'utilisateur.)
Timo
1
Ensuite, stockez l'événement dans la base de données ainsi que dans l'entité. Avoir un travail planifié pour traiter les événements stockés et les envoyer au courtier de messages. stackoverflow.com/a/52216427/4587961
Yan Khonski
7

Si mon portefeuille n'était qu'un autre groupe d'enregistrements dans la même base de données SQL que l'utilisateur, je placerais probablement le code de création de l'utilisateur et du portefeuille dans le même service et le gérerais en utilisant les fonctions de transaction normales de la base de données.

Il me semble que vous vous demandez ce qui se passe lorsque le code de création de portefeuille vous oblige à toucher un autre ou plusieurs autres systèmes? Je dirais que tout dépend de la complexité et / ou du risque du processus de création.

S'il s'agit simplement de toucher un autre magasin de données fiable (par exemple, celui qui ne peut pas participer à vos transactions SQL), alors en fonction des paramètres globaux du système, je serais peut-être prêt à risquer la très petite chance que la deuxième écriture ne se produise pas. Je pourrais ne rien faire, mais soulever une exception et traiter les données incohérentes via une transaction de compensation ou même une méthode ad hoc. Comme je le dis toujours à mes développeurs: "si ce genre de choses se passe dans l'application, cela ne passera pas inaperçu".

À mesure que la complexité et le risque de création de portefeuille augmentent, vous devez prendre des mesures pour atténuer les risques encourus. Supposons que certaines étapes nécessitent l'appel de plusieurs API partenaires.

À ce stade, vous pouvez introduire une file d'attente de messages avec la notion d'utilisateurs et / ou de portefeuilles partiellement construits.

Une stratégie simple et efficace pour vous assurer que vos entités seront finalement correctement construites consiste à réessayer les tâches jusqu'à ce qu'elles réussissent, mais cela dépend en grande partie des cas d'utilisation de votre application.

Je réfléchirais également longuement et sérieusement à la raison pour laquelle j'ai eu une étape sujette à l'échec dans mon processus d'approvisionnement.

Robert Moskal
la source
4

Une solution simple consiste à créer un utilisateur à l'aide du service utilisateur et à utiliser un bus de messagerie où le service utilisateur émet ses événements, et le service portefeuille s'inscrit sur le bus de messagerie, écoute l'événement créé par l'utilisateur et crée un portefeuille pour l'utilisateur. En attendant, si l'utilisateur accède à l'interface utilisateur de Wallet pour voir son portefeuille, vérifiez si l'utilisateur vient d'être créé et montrez que la création de votre portefeuille est en cours, veuillez vérifier un certain temps.

techagrammer
la source
3

Quelles solutions sont disponibles pour empêcher ce type d'incohérence des données?

Traditionnellement, des gestionnaires de transactions distribués sont utilisés. Il y a quelques années, dans le monde Java EE, vous avez peut-être créé ces services en tant que qu'EJB qui ont été déployés sur différents nœuds et votre passerelle API aurait effectué des appels à distance vers ces EJB. Le serveur d'applications (s'il est correctement configuré) garantit automatiquement, à l'aide de la validation en deux phases, que la transaction est soit validée, soit annulée sur chaque nœud, de sorte que la cohérence est garantie. Mais cela nécessite que tous les services soient déployés sur le même type de serveur d'application (afin qu'ils soient compatibles) et en réalité ne fonctionnent qu'avec des services déployés par une seule entreprise.

Existe-t-il des modèles qui permettent aux transactions de couvrir plusieurs demandes REST?

Pour SOAP (ok, pas REST), il y a la spécification WS-AT mais aucun service que j'ai jamais eu à intégrer ne prend en charge cela. Pour REST, JBoss a quelque chose dans le pipeline . Sinon, le «modèle» est soit de trouver un produit que vous pouvez brancher dans votre architecture, soit de construire votre propre solution (non recommandé).

J'ai publié un tel produit pour Java EE: https://github.com/maxant/genericconnector

Selon l'article auquel vous faites référence, il existe également le modèle Try-Cancel / Confirm et le produit associé d'Atomikos.

Les moteurs BPEL gèrent la cohérence entre les services déployés à distance à l'aide de la compensation.

Sinon, je sais que REST pourrait ne pas convenir à ce cas d'utilisation. La manière correcte de gérer cette situation serait-elle peut-être d'abandonner complètement REST et d'utiliser un protocole de communication différent comme un système de file d'attente de messages?

Il existe de nombreuses façons de «lier» des ressources non transactionnelles dans une transaction:

  • Comme vous le suggérez, vous pouvez utiliser une file d'attente de messages transactionnels, mais elle sera asynchrone, donc si vous dépendez de la réponse, cela devient compliqué.
  • Vous pouvez écrire le fait que vous devez appeler les services back-end dans votre base de données, puis appeler les services back-end à l'aide d'un batch. Encore une fois, asynchrone, peut donc devenir compliqué.
  • Vous pouvez utiliser un moteur de processus métier comme passerelle API pour orchestrer les microservices principaux.
  • Vous pouvez utiliser un EJB distant, comme mentionné au début, car il prend en charge les transactions distribuées hors de la boîte.

Ou devrais-je appliquer la cohérence dans le code de mon application (par exemple, en ayant un travail d'arrière-plan qui détecte les incohérences et les corrige ou en ayant un attribut «état» sur mon modèle utilisateur avec des valeurs «création», «créé», etc.)?

Prôner le jeu des démons: pourquoi construire quelque chose comme ça, quand il y a des produits qui font ça pour vous (voir ci-dessus), et le font probablement mieux que vous ne le pouvez, car ils sont essayés et testés?

Fourmi Kutschera
la source
2

Personnellement j'aime l'idée des Micro Services, des modules définis par les cas d'utilisation, mais comme votre question le mentionne, ils ont des problèmes d'adaptation pour les entreprises classiques comme les banques, l'assurance, les télécoms, etc ...

Les transactions distribuées, comme beaucoup l'ont mentionné, ne sont pas un bon choix, les gens optent désormais davantage pour des systèmes finalement cohérents, mais je ne suis pas sûr que cela fonctionnera pour les banques, les assurances, etc.

J'ai écrit un blog sur ma solution proposée, peut-être que cela peut vous aider ...

https://mehmetsalgar.wordpress.com/2016/11/05/micro-services-fan-out-transaction-problems-and-solutions-with-spring-bootjboss-and-netflix-eureka/

posthume
la source
0

La cohérence éventuelle est la clé ici.

  • L'un des services est choisi pour devenir le gestionnaire principal de l'événement.
  • Ce service gérera l'événement d'origine avec une seule validation.
  • Le gestionnaire principal se chargera de la communication asynchrone des effets secondaires à d'autres services.
  • Le gestionnaire principal effectuera l'orchestration des autres appels de services.

Le commandant est en charge de la transaction distribuée et prend le contrôle. Il connaît l'instruction à exécuter et coordonnera leur exécution. Dans la plupart des scénarios, il n'y aura que deux instructions, mais il peut gérer plusieurs instructions.

Le commandant assume la responsabilité de garantir l'exécution de toutes les instructions, ce qui signifie qu'il se retire. Lorsque le commandant tente d'effectuer la mise à jour à distance et n'obtient pas de réponse, il n'a pas de nouvelle tentative. De cette façon, le système peut être configuré pour être moins sujet aux pannes et il se guérit tout seul.

Comme nous avons des tentatives, nous avons l'idempotence. L'idempotence est la propriété de pouvoir faire quelque chose deux fois de manière à ce que les résultats finaux soient les mêmes que si cela avait été fait une seule fois. Nous avons besoin d'une idempotence au niveau du service distant ou de la source de données afin que, dans le cas où il reçoit l'instruction plus d'une fois, il ne la traite qu'une seule fois.

Cohérence à terme Cela résout la plupart des problèmes de transaction distribuée, mais nous devons considérer quelques points ici. Chaque transaction échouée sera suivie d'une nouvelle tentative, le nombre de tentatives dépend du contexte.

La cohérence est éventuelle, c'est-à-dire pendant que le système n'est pas dans un état cohérent lors d'une nouvelle tentative, par exemple si un client a commandé un livre et effectué un paiement, puis met à jour la quantité en stock. Si les opérations de mise à jour du stock échouent et en supposant qu'il s'agissait du dernier stock disponible, le livre sera toujours disponible jusqu'à ce que l'opération de nouvelle tentative de mise à jour du stock ait réussi. Une fois la nouvelle tentative réussie, votre système sera cohérent.

Viyaan Jhiingade
la source
-2

Pourquoi ne pas utiliser la plate-forme de gestion des API (APIM) qui prend en charge les scripts / la programmation? Ainsi, vous pourrez créer un service composite dans l'APIM sans déranger les micro-services. J'ai conçu en utilisant APIGEE à cet effet.

sra
la source