Pourquoi est-il si mauvais de lire les données d'une base de données «appartenant» à un autre microservice?

64

J'ai récemment lu cet excellent article sur l'architecture de microservice: http://www.infoq.com/articles/microservices-intro

Il indique que lorsque vous chargez une page Web sur Amazon, plus de 100 microservices coopèrent pour servir cette page.

Cet article explique que toutes les communications entre microservices ne peuvent passer que par une API. Ma question est la suivante: pourquoi est-il si grave de dire que toutes les écritures de base de données ne peuvent passer que par une API, mais que vous êtes libre de lire directement à partir des bases de données des différents micro-services. On pourrait par exemple dire que seules quelques vues de base de données sont accessibles en dehors du micro service afin que l'équipe de maintenance du micro service sache que, tant qu'elles conservent ces vues intactes, elles peuvent modifier autant que possible la structure de la base de données de leur micro service. vouloir.

Est-ce que j'ai râté quelque chose? Existe-t-il une autre raison pour laquelle les données ne devraient être lues que via une API?

Inutile de dire que mon entreprise est nettement plus petite qu'Amazon (et le sera toujours) et que nous pouvons avoir un nombre maximal d'utilisateurs de 5 millions.

David
la source
Un autre facteur général non mentionné dans les réponses est que, lorsqu'elles sont écrites dans la base de données, la mise en cache locale, même un simple mappage O / R, peut générer des données obsolètes lors de l'accès immédiat à la base de données. Si vous envisagez de contourner l'API µservice pour des raisons de rapidité, il se peut que vous ayez poussé trop loin l'architecture µservice.
Joop Eggen
Lorsque vous autorisez la lecture de la base de données, chaque détail de la base de données devient une partie de l'API publique. Je ne voudrais pas maintenir la compatibilité sur une API aussi complexe.
Patrick
Mais dans ce cas, la vue ne fait-elle pas simplement partie de l'API, du moins à des fins sémantiques? C'est juste une question de ce que vous appelez l'API et de ce qui vous oblige à maintenir. (Habituellement, une couche au-dessus de la base de données est plus facile à maintenir cohérente.)
lc.
Je suis d'accord que la vue serait simplement une forme d'une API. Je pense que la plupart des personnes répondant à cette question ne lisent pas mon idée d'utiliser les vues comme un niveau d'abstraction. Je comprends, bien que garder la vue intacte si on changeait la technologie de base de données serait un défi majeur, mais je suis prêt à parier que nous n’aurons pas besoin de changer notre technologie de base de données pour les 5 prochaines années. En outre, les performances ne seront pas un problème avec seulement 5 utilisateurs de la filière. Donc, étant donné notre taille, je tiens à remercier cette solution, même si les réponses semblent indiquer que je me dirige directement vers un monde de douleur.
David

Réponses:

69

Les bases de données ne sont pas très douées pour cacher des informations, ce qui est tout à fait plausible, car leur travail consiste à exposer des informations. Mais cela les rend un outil moche en matière d'encapsulation. Pourquoi voulez-vous une encapsulation?

Scénario: vous liez directement quelques composants à un SGBDR et vous voyez un composant en particulier devenir un goulot de performance pour lequel vous souhaiterez peut-être dénormaliser la base de données, mais vous ne pourrez pas, car tous les autres composants seraient affectés. Vous pouvez même réaliser que vous seriez mieux avec un magasin de documents ou une base de données de graphes qu'avec un SGBDR. Si les données sont encapsulées par une petite API, vous avez une chance réaliste de réimplémenter ladite API comme vous le souhaitez. Vous pouvez insérer des couches de cache de manière transparente et non.

La couche de stockage directement à partir de la couche d’application est l’opposé diamétralement opposé de ce que suggère le principe d’inversion de dépendance .

back2dos
la source
1
Ceci est un excellent point! Une chose qui me rend moins inquiet est que Postgres prend désormais en charge le magasin de documents et le SGBDR ( sanstheloop.com/articles/2014-09-30-postgresql-nosql ). Votre point est toujours valable, cependant, et je vais l'examiner attentivement.
David
3
Cela ne devrait pas vous rendre moins inquiet @David simplement parce qu'un outil peut faire quelque chose ne veut pas dire que le changer ne changera pas beaucoup de choses. C’est le point d’avoir un degré de séparation: vous pouvez complètement modifier les données derrière une API sans changer ce que l’utilisateur voit. Je parle ici comme un gabarit de données ... tant que le client voit la même chose, vous pouvez modifier le backend autant que vous le souhaitez.
Ben
1
@ David Bien qu'il s'agisse d'une nouvelle intéressante, cela n'a aucune importance pour le scénario que j'ai décrit. Si vous changez votre schéma de base de données d’un modèle relationnel à un autre basé sur le document, cela aura le même impact sur tous ceux qui en dépendent: vous devrez réécrire toutes les requêtes. Il y a aussi le cauchemar de devoir déployer toutes ces modifications en même temps, afin que la compatibilité entre les composants soit maintenue à travers le système.
back2dos
1
@ David: Restreindre l'accès à quelques vues bien définies revient à construire une autre API, avec certains des avantages qui vont avec. Tant qu'il ne s'agit que de vues, vous êtes toutefois limité à un accès en lecture seule. Et si un composant dépend à la fois de l'API de service et de l'API de vue, il est très fragile. Ainsi, si vous faites dépendre un composant des vues, vous avez prédéfini qu'il est en lecture seule ou à maintenance élevée. Je sens une dette technique ici. En outre, vous souhaiterez peut-être ajouter un partitionnement horizontal d’une manière que votre base de données ne vous permettra pas.
back2dos
2
@ David: À long terme, il est plus important de changer de code facilement que d'écrire. L'architecture ne dit pas "vous ne devriez pas écrire le code de telle ou telle manière", mais "Si vous le faites, vous allez subir de terribles cauchemars en essayant de le maintenir". Si vous parlez de prototypes, la maintenance n'est pas une obligation. Aller de l'avant. Un prototype devrait prouver un point aussi facilement que possible. Mais lorsque vous essayez d'intégrer tous les points éprouvés dans un système sans le laisser évoluer vers la torture auto-induite par Sisyphe, vous feriez mieux de faire un effort supplémentaire.
back2dos
55

Qu'y a-t-il de plus important et de significatif dans un microservice: son API ou son schéma de base de données? L'API, car c'est son contrat avec le reste du monde. Le schéma de base de données est simplement un moyen pratique de stocker les données gérées par le service, organisées de manière à optimiser les performances de microservice. L'équipe de développement doit être libre de réorganiser ce schéma - ou de passer à une solution de banque de données totalement différente - à tout moment. Le reste du monde ne devrait pas s'en soucier. Le reste du monde se soucie du changement d’API, car c’est le contrat.

Maintenant, si vous allez jeter un coup d'œil dans leur base de données

  • Vous ajoutez une dépendance indésirable sur leur schéma. Ils ne peuvent pas le changer sans impact sur votre service.
  • Vous ajoutez une charge indésirable et imprévisible à leurs internes.
  • Les performances de votre propre service seront affectées par les performances de leur base de données (elles essaieront d'optimiser leur service pour que les clients puissent bien fonctionner et sa base de données ne fonctionne que pour leur service)
  • Vous associez votre implémentation à un schéma qui peut ne pas représenter de manière précise et distincte les ressources dans leur magasin de données. Il peut contenir des détails supplémentaires qui ne sont nécessaires que pour suivre l'état interne ou satisfaire leur implémentation particulière (dont vous ne devez pas vous soucier).
  • Vous pouvez involontairement détruire ou corrompre l’état de leur service (et ils ne sauront pas que vous le faites)
  • Vous pouvez mettre à jour / supprimer / supprimer des ressources de leur base de données sans qu'ils sachent que cela s'est produit.

Les deux derniers points peuvent ne pas se produire si vous n’avez qu’un accès en lecture, mais les autres points sont plus qu’une raison suffisante. Les bases de données partagées sont une mauvaise chose.

Il est courant que les développeurs moins expérimentés (ou ceux qui n’apprennent pas) considèrent que la base de données est plus importante que le service, que la base de données est réelle et que le service n’est qu’un moyen d’y accéder. C'est le mauvais sens.

itsbruce
la source
4
Veuillez noter que tous les points ci-dessus sont valables même si vous êtes le seul développeur travaillant sur l'ensemble du projet. La gestion d'un projet complexe, même par vous-même, fait appel à toutes ces préoccupations.
Itsbruce
15

Il est difficile de décrire l’architecture des microservices, mais la meilleure façon d’y penser est de faire un mariage entre l’architecture orientée composants et l’architecture orientée services. Le logiciel en tant que suite est composé de nombreux composants de petite entreprise avec une responsabilité très spécifique du domaine. Leur interface avec le monde extérieur, que ce soit dans les services fournis ou les services requis, se fait via une API de services clairement définis.

Écrire et même lire à partir d'une base de données en dehors du domaine métier de vos composants va à l'encontre de ce style d'architecture.

La principale raison à cela est qu'une API fournie via un service par un autre composant logiciel via un service peut raisonnablement s'attendre à ce qu'elle soit rétrocompatible à mesure que de nouvelles versions du composant fournissant le service deviennent disponibles. Si je suis le développeur d'un composant "fournissant", je n'ai plus qu'à m'inquiéter de la compatibilité ascendante de mon API. Si je sais que trois autres équipes de développement ont écrit directement des requêtes personnalisées sur ma base de données, mon travail est devenu beaucoup plus compliqué.

Pire encore, peut-être que cette autre équipe qui a écrit ceci est à mi-sprint dans un projet critique et ne peut pas accepter ce changement maintenant de votre composant. Désormais, le développement logiciel pour votre composant sur un domaine professionnel que vous possédez est guidé par le développement sur un autre domaine commercial.

Une interaction complète par le biais des services réduit le couplage entre divers composants logiciels, de sorte que de telles situations ne se produisent pas aussi souvent. En ce qui concerne les autres composants utilisant une vue dans la base de données, vous avez davantage de possibilités pour la rendre rétro-compatible si quelqu'un d'autre a écrit des requêtes à ce sujet. Je pense néanmoins que cela devrait être un cas exceptionnel et ne devrait être fait que pour les rapports ou le traitement par lots, où une application doit lire des quantités énormes de données.

Il est clair que cela fonctionne bien dans les grandes équipes distribuées où les équipes de développement sont séparées par domaine métier comme Amazon. Si vous êtes un petit magasin de développement, vous pouvez toujours bénéficier de ce modèle, en particulier si vous devez vous lancer rapidement dans un projet de grande envergure, mais également si vous devez utiliser des logiciels de fournisseurs.

arbre_érable
la source
4

Au cours des 20 dernières années, j'ai vu quelques grandes conceptions de base de données modulaires et j'ai vu le scénario suggéré par David à plusieurs reprises, où les applications ont un accès en écriture à leur propre schéma / jeu de tables et un accès en lecture à un autre schéma / ensemble de tables. Le plus souvent, les données auxquelles une application / module obtient un accès en lecture seule peuvent être qualifiées de "données de base" .

À l'époque, je n'avais pas vu les problèmes que les réponses précédentes suggéraient que j'aurais dû voir. Je pense qu'il est donc utile d'examiner de plus près les points soulevés dans les réponses précédentes de manière plus détaillée.

Scénario: vous liez directement deux composants à un SGBDR et vous voyez un composant en particulier devenir un goulot d'étranglement

Je suis d'accord avec ce commentaire, sauf que c'est également un argument en faveur d'une copie locale des données pour que le microservice puisse être lu. C'est-à-dire que la plupart des bases de données matures prennent en charge la réplication . Ainsi, sans aucun effort de développement, les "données de base" peuvent être physiquement répliquées dans la base de données microservice si cela est souhaité ou nécessaire.

Certains pourraient reconnaître cela sous une apparence plus ancienne en tant que "base de données d'entreprise" répliquant les tables principales vers une "base de données ministérielle". Un point ici est qu’il est généralement bon qu’une base de données le fasse pour nous avec une réplication intégrée des données modifiées (uniquement les deltas, sous forme binaire et à un coût minimal pour la base de données source).

À l'inverse, lorsque nos choix de base de données n'autorisent pas cette prise en charge de la réplication "standard", nous pouvons nous retrouver dans une situation dans laquelle nous voulons transférer les "données principales" vers les bases de données de microservice, ce qui peut entraîner d'importants efforts de développement et également être un mécanisme sensiblement moins efficace.

peut vouloir dénormaliser la base de données, mais vous ne pouvez pas, car tous les autres composants seraient affectés

Pour moi, cette affirmation n’est tout simplement pas correcte. La dénormalisation est un changement "additif" et non pas un "changement radical" et aucune application ne devrait être interrompue en raison d'une dénormalisation.

La seule façon pour cette interruption d'une application est lorsque le code d'application utilise quelque chose comme "select * ..." et ne gère pas une colonne supplémentaire. Pour moi, ce serait un bug dans l'application?

Comment la dénormalisation peut-elle interrompre une application? Cela ressemble à du fud pour moi.

Dépendance du schéma:

Oui, l'application dépend maintenant du schéma de la base de données, ce qui implique un problème majeur. Bien que l'ajout de toute dépendance supplémentaire ne soit évidemment pas idéal, mon expérience est que la dépendance au schéma de base de données n'a pas posé de problème, alors pourquoi cela pourrait-il être le cas? Est-ce que je viens d'avoir de la chance?

Données de base

Le schéma auquel nous souhaitons généralement qu'un microservice ait un accès en lecture seule est le plus souvent ce que je qualifierais de " données de base " pour l'entreprise. Il contient les données essentielles essentielles à l'entreprise.

Historiquement, cela signifie que le schéma auquel nous ajoutons la dépendance est à la fois mature et stable (assez fondamental pour l’entreprise et immuable).

Normalisation

Si 3 concepteurs de base de données conçoivent un schéma de base de données normalisé, ils se retrouveront dans la même conception. Ok, il pourrait y avoir quelques variations 4NF / 5NF mais pas beaucoup. De plus, le concepteur peut poser toute une série de questions pour valider le modèle, afin de pouvoir être sûr qu'il est arrivé à 4NF (suis-je trop optimiste? Les gens ont-ils du mal à atteindre 4NF?).

update: par 4NF , je veux dire que toutes les tables du schéma ont atteint leur forme normale la plus élevée jusqu'à 4NF (toutes les tables ont été normalisées de manière appropriée jusqu'à 4NF).

Je crois que le processus de conception de la normalisation est la raison pour laquelle les concepteurs de bases de données sont généralement à l'aise avec l'idée de dépendre d'un schéma de base de données normalisé.

Le processus de normalisation donne à la conception de base de données une conception "correcte" connue et les variations à partir de là doivent être dénormalisées pour améliorer les performances.

  1. Il peut y avoir des variations en fonction des types de base de données pris en charge (JSON, ARRAY, prise en charge des types Geo, etc.)
  2. Certains pourraient argumenter pour une variation basée sur 4NF / 5NF
  3. Nous excluons la variation physique (parce que cela n'a pas d'importance)
  4. Nous limitons cela à la conception OLTP et non à la conception DW, car ce sont les schémas auxquels nous voulons accorder un accès en lecture seule.

Si 3 concepteurs avaient une conception à implémenter (sous forme de code), on s'attendrait à 3 implémentations différentes (potentiellement très différentes).

Pour moi, il y a potentiellement une question de "foi en la normalisation".

Briser les changements de schéma?

La dénormalisation, l’ajout de colonnes, la modification de colonnes pour un stockage plus important, l’extension de la conception avec de nouvelles tables, etc. constituent des modifications inébranlables.

Les changements de rupture sont évidemment possibles en supprimant des colonnes / des tableaux ou en effectuant un changement de type de rupture. Oui, mais concrètement, je n’ai rencontré aucun problème ici. Peut-être parce que l'on comprend ce que sont les changements de rupture et que ceux-ci ont été bien gérés?

Je serais intéressé d'entendre des cas de changements de schéma brisés dans le contexte de schémas partagés en lecture seule.

Qu'y a-t-il de plus important et de significatif dans un microservice: son API ou son schéma de base de données? L'API, car c'est son contrat avec le reste du monde.

Bien que je sois d’accord avec cette affirmation, j’estime qu’un architecte de l’entreprise pourrait nous avertir du fait que «les données durent éternellement» . En d’autres termes, bien que l’API soit l’aspect le plus important, les données sont également très importantes pour l’entreprise dans son ensemble et le resteront pendant très longtemps.

Par exemple, une fois que vous avez besoin de renseigner Data Warehouse for Business Intelligence, le schéma et la prise en charge de CDC deviennent importants du point de vue des rapports commerciaux, quelle que soit l'API.

Des problèmes avec les API?

Maintenant, si les API étaient parfaites et faciles, tous les points sont sans objet puisque nous choisirions toujours une API plutôt que d'avoir un accès local en lecture seule. Ainsi, même en considérant l'accès local en lecture seule, il est possible que l'API évite certains problèmes d'utilisation des API.

What motivates people to desire local read-only access?

Optimisation de l'API:

LinkedIn a une présentation intéressante (à partir de 2009) sur la question de l'optimisation de leur API et pourquoi c'est important pour eux à leur échelle. http://www.slideshare.net/linkedin/building-consistent-restful-apis-in-a-highperformance-environment

En bref, une fois qu'une API doit prendre en charge de nombreux cas d'utilisation différents, elle peut facilement se retrouver dans une situation où elle prend en charge un cas d'utilisation de manière optimale et le reste plutôt mal du point de vue du réseau et de la base de données.

Si l'API n'a pas la même sophistication que LinkedIn, vous pouvez facilement obtenir les scénarios suivants:

  • L'API récupère beaucoup plus de données que nécessaire (gaspillage)
  • API Chatty où vous devez appeler l'API plusieurs fois

Oui, nous pouvons bien sûr ajouter la mise en cache aux API, mais au bout du compte, l'appel de l'API est un appel à distance et une série d'optimisations est disponible pour les développeurs lorsque les données sont locales.

Je soupçonne qu'il y a un ensemble de personnes qui pourraient l'additionner comme:

  • Réplication à faible coût des données de base dans la base de données microservice (sans frais de développement et techniquement efficace)
  • Confiance en la normalisation et résilience des applications aux modifications de schéma
  • Possibilité d'optimiser facilement chaque cas d'utilisation et d'éviter potentiellement les appels d'API distants bavards / inutiles / inefficaces
  • Et quelques autres avantages en termes de contraintes et de conception cohérente

Cette réponse est trop longue. Excuses !!

Rob Bygrave
la source
L'ajout d'une colonne interrompt généralement les applications. Si vous avez "salaire", l'application qui additionne toutes les pauses salariales lors de l'introduction d'une nouvelle colonne "salaire_monnaie".
Kubanczyk
Vraiment? Cela dépend de votre définition de "pauses", je suppose. Si l'application était en production et fonctionnait comme prévu sans "salaire_monnaie", pourquoi considéreriez-vous cette application maintenant en panne?
Rob Bygrave
L'application fonctionne sans erreur et affiche un certain nombre. Mais c'est inutile. Lorsque le PDG constate que le montant total des salaires pour le mois dernier est de 6 millions au lieu de 50 000 (à cause d'un nouvel employé rémunéré en Wons sud-coréens), la définition d'une sortie utile / inutile sera peu discutée.
Kubanczyk
0

La gestion des états (potentiellement une base de données) peut être déployée dans le conteneur de Microservice et exposée via une API. La base de données d'un Microservice n'est pas visible par les autres systèmes en dehors du conteneur - uniquement par l'API. Vous pouvez également faire appel à un autre service (un cache, par exemple) pour gérer l'état via une API. Le fait de disposer de toutes les dépendances de Microservice (autres que les appels d'API vers d'autres services) au sein d'un même conteneur déployable est une distinction clé de l'architecture. Si on ne l'obtient pas, retournez et étudiez l'architecture.

Eric Roch
la source