web-dev-qa-db-fra.com

Cohérence des données entre microservices

Alors que chaque microservice aura généralement ses propres données, certaines entités doivent être cohérentes sur plusieurs services. 

Pour une telle exigence de cohérence des données dans un paysage hautement distribué tel que l’architecture de microservices, quels sont les choix en matière de conception? Bien sûr, je ne veux pas d'architecture de base de données partagée, dans laquelle une seule base de données gère l'état de tous les services. Cela viole les principes de l'isolement et du rien partagé. 

Je comprends qu'un microservice puisse publier un événement lorsqu'une entité est créée, mise à jour ou supprimée. Tous les autres microservices intéressés par cet événement peuvent donc mettre à jour les entités liées dans leurs bases de données respectives. 

C'est réalisable, mais cela demande beaucoup d'efforts de programmation soigneux et coordonnés dans tous les services.

Akka ou tout autre framework peut-il résoudre ce cas d'utilisation? Comment?

EDIT1:
Ajouter le diagramme ci-dessous pour plus de clarté.
En gros, j'essaie de comprendre s'il existe aujourd'hui des frameworks capables de résoudre ce problème de cohérence des données. 

Pour la file d’attente, je peux utiliser n’importe quel logiciel AMQP tel que RabbitMQ, Qpid, etc., pour le cadre de cohérence des données, je ne sais pas si Akka ou tout autre logiciel peut aider. Ou bien ce scénario est-il si peu commun, et un tel anti-modèle qu'aucun cadre ne devrait être nécessaire?
 enter image description here

17
Santanu Dey

Le style architectural Microservices essaie de permettre aux organisations de disposer de services indépendants, en développement et en exécution, pour les petites équipes. Voir ceci lire . Et le plus difficile est de définir les limites du service de manière utile. Lorsque vous découvrez que la manière dont vous divisez votre application entraîne des exigences qui ont souvent des incidences sur plusieurs services, ce qui vous obligerait à repenser les limites du service. Il en va de même lorsque vous ressentez un fort besoin de partager des entités entre les services. 

Le conseil général serait donc de faire de gros efforts pour éviter de tels scénarios. Cependant, il peut arriver que vous ne puissiez pas l'éviter. Puisqu'une bonne architecture consiste souvent à faire les bons compromis, voici quelques idées.

  1. Pensez à exprimer la dépendance à l'aide d'interfaces de service (API) au lieu d'une dépendance directe à la base de données. Cela permettrait à chaque équipe de service de modifier autant que nécessaire leur schéma de données interne et de ne se soucier que de la conception de l'interface en ce qui concerne les dépendances. Cela est utile car il est plus facile d'ajouter des API supplémentaires et de déprécier lentement les API anciennes au lieu de modifier une conception de base de données avec tous les Microservices dépendants (potentiellement en même temps). En d'autres termes, vous pouvez toujours déployer de nouvelles versions de Microservice de manière indépendante, tant que les anciennes API sont toujours prises en charge. C’est l’approche recommandée par le CTO d’Amazon, qui a mis au point une grande partie de l’approche Microservices. Voici une lecture recommandée d’un entretien avec en 2006 avec lui.

  2. Lorsque vous ne pouvez vraiment pas éviter d'utiliser les mêmes bases de données et que vous divisez les limites de votre service de manière à ce que plusieurs équipes/services aient besoin des mêmes entités, vous introduisez deux dépendances entre l'équipe Microservice et l'équipe responsable du schéma de données: a ) Format des données, b) Données réelles. Ce n'est pas impossible à résoudre, mais seulement avec des frais généraux d'organisation. Et si vous introduisez trop de telles dépendances, votre organisation sera probablement paralysée et ralentie dans son développement.

a) Dépendance du schéma de données. Le format de données des entités ne peut pas être modifié sans nécessiter de modifications dans les Microservices. Pour le découpler, vous devrez mettre à jour le schéma de données des entités strictement et dans la base de données prendre en charge toutes les versions des données actuellement utilisées par Microservices. Cela permettrait aux équipes de Microservices de décider elles-mêmes quand mettre à jour leur service pour prendre en charge la nouvelle version du schéma de données. Ce n'est pas faisable avec tous les cas d'utilisation, mais cela fonctionne avec beaucoup.

b) Dépendance à l’égard des données effectivement collectées. Les données collectées et d’une version connue pour un microservice peuvent être utilisées, mais le problème se produit lorsque certains services produisent une version plus récente des données et qu’un autre service en dépend - Mais n’a pas encore été mis à niveau. être capable de lire la dernière version. Ce problème est difficile à résoudre et suggère dans de nombreux cas que vous n’avez pas choisi correctement les limites du service. En règle générale, vous n'avez pas d'autre choix que de déployer tous les services dépendant des données en même temps que la mise à niveau des données dans la base de données. Une approche plus farfelue consiste à écrire différentes versions des données simultanément (ce qui fonctionne généralement lorsque les données ne sont pas mutables).

Pour résoudre les problèmes a) et b) dans certains autres cas, la dépendance peut être réduite de hidden data duplication et eventual consistency. Ce qui signifie que chaque service stocke sa propre version des données et ne la modifie que lorsque les exigences de ce service changent. Les services peuvent le faire en écoutant un flux de données public. Dans de tels scénarios, vous utiliseriez une architecture basée sur des événements dans laquelle vous définissez un ensemble d’événements publics pouvant être mis en file d’attente et utilisés par des écouteurs des différents services qui traiteront l’événement et stockeront toutes les données pertinentes pour cet événement ( créant potentiellement une duplication des données). À présent, d'autres événements peuvent indiquer que les données stockées en interne doivent être mises à jour et il incombe à chaque service de le faire avec sa propre copie des données. Une technologie permettant de gérer une telle file d’événements publique est Kafka .

7

Limites théoriques

Une mise en garde importante à retenir est le théorème CAP :

En présence d'une partition, il reste alors deux options: cohérence ou disponibilité. Lorsque vous choisissez la consistance avant disponibilité, le système renverra une erreur ou un délai d’expiration si Des informations particulières ne peuvent pas être garanties comme étant à jour en raison de partitionnement du réseau.

Ainsi, en "exigeant" que certaines entités soient cohérentes dans plusieurs services, vous augmentez la probabilité que vous ayez à traiter des problèmes de délai d'attente.

Akka Distributed Data

Akka dispose d'un module de données distribuées pour partager des informations au sein d'un cluster:

Toutes les entrées de données sont propagées à tous les nœuds ou aux nœuds avec un certain rôle, dans le cluster via la réplication directe et basée sur les commérages dissémination. Vous avez un contrôle fin du niveau de consistance pour lit et écrit.

Je pense qu'il y a 2 forces principales en jeu ici:

  • le découplage - c'est pourquoi vous disposez en premier lieu de microservices et souhaitez une approche sans partage de la persistance des données
  • exigence de cohérence - si j'ai bien compris, vous êtes déjà satisfait de la cohérence éventuelle

Le diagramme me semble tout à fait logique, mais je ne connais pas de cadre permettant de le faire directement, probablement en raison des nombreux arbitrages liés aux cas d'utilisation. J'aborderais le problème comme suit:

Le service en amont émet des événements sur le bus de messages, comme vous l'avez montré. Aux fins de la sérialisation, je choisis avec soin le format de câble qui ne couple pas trop le producteur et le consommateur. Ceux que je connais sont protobuf et avro. Vous pouvez faire évoluer votre modèle d'événement en amont sans avoir à modifier l'aval s'il ne se soucie pas des nouveaux champs ajoutés et peut effectuer une mise à niveau propagée si c'est le cas.

Les services en aval souscrivent aux événements - le bus de messages doit offrir une tolérance aux pannes. Nous utilisons kafka pour cela, mais depuis que vous avez choisi AMQP, je suppose que cela vous donne ce dont vous avez besoin.

En cas de défaillance du réseau (par exemple, le consommateur en aval ne peut pas se connecter au courtier), si vous préférez la cohérence (éventuelle) à la disponibilité, vous pouvez choisir de refuser de traiter les demandes qui reposent sur des données dont vous savez qu'elles peuvent être plus anciennes que certains seuils préconfigurés.

1
Michal Borowiecki

Je pense que vous pouvez aborder ce problème sous deux angles, la collaboration de service et la modélisation de données:

Collaboration de service

Ici, vous pouvez choisir entre l'orchestration de services et la chorégraphie de services. Vous avez déjà mentionné l'échange de messages ou d'événements entre services. Ce serait la chorégraphie qui, comme vous l'avez dit, pourrait fonctionner, mais implique l'écriture de code dans chaque service qui traite de la partie messagerie. Je suis sûr qu'il existe des bibliothèques pour cela cependant. Vous pouvez également choisir une orchestration de services dans laquelle vous introduisez un nouveau service composite: l'orchestrateur, qui peut être responsable de la gestion des mises à jour des données entre les services. Étant donné que la gestion de la cohérence des données est maintenant extraite dans un composant séparé, cela vous permettrait de basculer entre une cohérence éventuelle et une cohérence forte sans toucher aux services en aval.

Modélisation de données

Vous pouvez également choisir de redéfinir les modèles de données derrière les microservices participants et d'extraire les entités devant être cohérentes entre plusieurs services dans des relations gérées par un microservice de relation dédié. Un tel microservice serait un peu similaire à l'orchestrateur, mais le couplage serait réduit car les relations peuvent être modélisées de manière générique.

0
clonq