J'ai récemment lu cet excellent article sur l'architecture des microservices: 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 décrit que toutes les communications entre les microservices ne peuvent passer que par une API. Ma question est pourquoi il est si mauvais de dire que toutes les écritures de base de données ne peuvent passer que par une API, mais 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 qui gère le micro service sache que tant qu'elles conservent ces vues intactes, elles peuvent changer la structure de la base de données de leur micro service autant qu'elles vouloir.
Est-ce que j'ai râté quelque chose? Y a-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 beaucoup plus petite qu'Amazon (et le sera toujours) et le nombre maximum d'utilisateurs que nous pouvons avoir est d'environ 5 millions.
Les bases de données ne sont pas très efficaces pour masquer des informations, ce qui est tout à fait plausible, car leur travail consiste à exposer des informations. Mais cela en fait un outil moche quand il s'agit d'encapsulation. Pourquoi voulez-vous une encapsulation?
Scénario: vous liez directement quelques composants à un SGBDR et vous voyez un composant particulier devenir un goulot d'étranglement pour lequel vous voudrez peut-être dénormaliser la base de données, mais vous ne pouvez pas car tous les autres composants seraient affectés. Vous pouvez même vous rendre compte que vous seriez mieux avec un magasin de documents ou une base de données de graphiques 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 de manière transparente des couches de cache et autres.
Trébucher avec la couche de stockage directement à partir de la couche d'application est l'opposé diamétral de ce que le principe d'inversion de dépendance suggère de faire.
Qu'est-ce qui est plus important et 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 la base de données est simplement un moyen pratique de stocker les données gérées par le service, espérons-le organisé de manière à optimiser les performances du microservice. L'équipe de développement devrait être libre de réorganiser ce schéma - ou de passer à une solution de banque de données entièrement différente - à tout moment. Le reste du monde ne devrait pas s'en soucier. Le reste du monde se soucie du changement de l'API, car l'API est le contrat.
Maintenant, si vous allez jeter un œil dans leur base de données
Les deux derniers points peuvent ne pas se produire si vous ne disposez que d'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 pour les développeurs moins expérimentés (ou ceux qui n'apprennent pas) de voir la base de données comme plus importante que le service, de voir la base de données comme la chose real et le service juste un moyen d'accéder à il. C'est le mauvais sens.
L'architecture de microservices est difficile à décrire, mais la meilleure façon d'y penser est 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 petites entreprises avec une responsabilité de domaine métier très spécifique. 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.
L'écriture et même la lecture à partir d'une base de données située en dehors du domaine d'activité de vos composants va à l'encontre de ce style d'architecture.
La raison principale en est qu'une API fournie via un service par un autre composant logiciel a une attente raisonnable que l'API sera très probablement rétrocompatible à mesure que de nouvelles versions du composant fournissant le service deviendront disponibles. Si je suis le développeur d'un composant "fournissant", je n'ai qu'à me soucier de la compatibilité descendante avec mon API. Si je sais qu'il y a trois autres équipes de développement qui ont écrit directement des requêtes personnalisées sur ma base de données, mon travail est devenu beaucoup plus compliqué.
Pire encore, cette autre équipe qui les a écrites est en cours de sprint dans un projet critique et elle ne peut pas accepter ce changement maintenant de votre composant. Désormais, le développement de logiciels pour votre composant sur un domaine métier que vous possédez est piloté par le développement sur un autre domaine métier.
Une interaction complète via les services réduit le couplage entre les différents composants logiciels, de sorte que des situations comme celle-ci ne se produisent pas si fréquemment. En ce qui concerne les autres composants utilisant une vue dans la base de données, vous avez plus de possibilités pour rendre la vue rétrocompatible si quelqu'un d'autre a écrit des requêtes à son sujet. Cependant, je pense toujours que cela devrait être le cas d'exception et ne devrait être fait que pour peut-être le reporting ou le traitement par lots où une application devra lire d'énormes quantités de données.
De toute évidence, cela fonctionne bien dans les grandes équipes distribuées où les équipes de développement sont séparées par domaine d'activité comme Amazon. Si vous êtes une petite boutique de développement, vous pouvez toujours bénéficier de ce modèle, surtout si vous avez besoin de monter rapidement en puissance pour un gros projet, mais aussi si vous devez traiter avec un logiciel fournisseur.
Au cours des 20 dernières années, j'ai vu quelques grandes conceptions de bases de données modulaires et j'ai vu à plusieurs reprises le scénario suggéré par David où les applications ont un accès en écriture à leur propre schéma/ensemble de tables et un accès en lecture à un autre schéma/ensemble de tables. Le plus souvent, ces données auxquelles une application/un module obtient un accès en lecture seule peuvent être décrites comme "données de base" .
Pendant ce temps, je n'ai pas vu les problèmes que les réponses précédentes suggèrent que j'aurais dû voir, donc je pense qu'il vaut la peine d'examiner de plus près les points soulevés dans les réponses précédentes.
Scénario: vous liez directement quelques composants à un SGBDR et vous voyez un composant particulier devenir un goulot d'étranglement performant
Je suis d'accord avec ce commentaire sauf que c'est aussi un argument pour avoir une copie des données localement pour que le microservice puisse les lire. Autrement dit, la plupart des bases de données matures prennent en charge la réplication et donc sans aucun effort de développeur, les "données de base" peuvent être physiquement répliquées dans la base de données de microservices si cela est souhaité ou nécessaire.
Certains pourraient reconnaître cela sous une forme plus ancienne comme une "base de données d'entreprise" répliquant des tables de base dans une "base de données départementale". Un point ici est que, généralement, il est bon qu'une base de données le fasse pour nous avec une réplication intégrée des données modifiées (deltas uniquement, sous forme binaire et à un coût minimal pour la base de données source).
Inversement, lorsque nos choix de bases de données ne permettent pas cette prise en charge de la réplication "standard", nous pouvons entrer dans une situation où nous voulons pousser les "données de base" vers les bases de données de microservices et cela peut entraîner une quantité importante d'efforts de développement et être également un mécanisme sensiblement moins efficace.
peut vouloir dénormaliser la base de données, mais vous ne pouvez pas parce que 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 un "changement de rupture" et aucune application ne devrait se casser en raison de la dénormalisation.
La seule façon de casser une application est que 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 casser une application? Cela ressemble à du FUD pour moi.
Dépendance du schéma:
Oui, l'application dépend maintenant du schéma de base de données et cela implique que cela devrait être un problème majeur. Bien que l'ajout d'une dépendance supplémentaire ne soit évidemment pas idéal, mon expérience est qu'une dépendance vis-à-vis du schéma de base de données n'a pas été un problème, alors pourquoi est-ce le cas? Suis-je juste chanceux?
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 de base essentielles à l'entreprise.
Historiquement, cela signifie que le schéma sur lequel nous ajoutons la dépendance est à la fois mature et stable (quelque peu fondamental pour l'entreprise et immuable).
Si 3 concepteurs de bases de données choisissent un schéma de base de données normalisé, ils se retrouveront dans la même conception. Ok, il pourrait y avoir une variation de 4NF/5NF mais pas beaucoup. De plus, il y a une série de questions que le concepteur peut poser pour valider le modèle afin que le concepteur puisse être sûr qu'il est arrivé à 4NF (Suis-je trop optimiste? Les gens ont-ils du mal à accéder à 4NF?).
mise à jour: Par 4NF ici, je veux dire que toutes les tables du schéma ont pu 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 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 amène la conception DB à une conception connue "correcte" et les variations à partir de là devraient être une dénormalisation pour les performances.
Si 3 programmeurs recevaient une conception à implémenter (sous forme de code), l'attente serait pour 3 implémentations différentes (potentiellement très différentes).
Pour moi, il y a potentiellement une question de "foi dans la normalisation".
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. sont tous des changements incessants et les concepteurs de bases de données qui sont arrivés à la 4e forme normale en seront confiants.
Les changements de rupture sont évidemment possibles en supprimant les colonnes/tables ou en effectuant un changement de type de rupture. Oui, mais en termes pratiques, je n'ai rencontré aucun problème ici. Peut-être parce qu'on comprend ce que sont les changements de rupture et ceux-ci ont été bien gérés?
Je serais intéressé d'entendre des cas de rupture de modifications de schéma dans le contexte de schémas partagés en lecture seule.
Qu'est-ce qui est plus important et 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 déclaration, je pense qu'il y a une mise en garde importante que nous pourrions entendre d'un architecte d'entreprise qui est "Les données vivent pour toujours" . Autrement dit, bien que l'API soit la chose la plus importante, les données sont également assez importantes pour l'entreprise dans son ensemble et elles le seront pendant très longtemps.
Par exemple, une fois qu'il est nécessaire de remplir le Data Warehouse pour Business intelligence le schéma et la prise en charge CDC deviennent alors importants du point de vue du reporting métier, quelle que soit l'API.
Maintenant, si les API étaient parfaites et faciles, tous les points sont sans objet, car nous choisirions toujours une API plutôt que d'avoir un accès local en lecture seule. Par conséquent, la motivation pour considérer même l'accès local en lecture seule est qu'il peut y avoir des problèmes d'utilisation d'API que l'accès local évite.
What motivates people to desire local read-only access?
LinkedIn a une présentation intéressante (à partir de 2009) sur la question de l'optimisation de leur API et pourquoi elle est importante 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 la 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 dans lesquels:
Oui, nous pouvons bien sûr ajouter la mise en cache aux API, mais finalement, l'appel d'API est un appel à distance et il existe une série d'optimisations disponibles pour les développeurs lorsque les données sont locales.
Je soupçonne qu'il y a un ensemble de personnes qui pourraient l'ajouter comme:
Cette réponse est beaucoup trop longue. Toutes mes excuses !!
La gestion des états (potentiellement une base de données) peut être déployée dans le conteneur du microservice et exposée via une API. La base de données d'un microservice n'est pas visible pour les autres systèmes en dehors du conteneur - uniquement l'API. Alternativement, vous pouvez avoir un autre service (par exemple un cache) gérer l'état via une API. Le fait d'avoir toutes les dépendances du microservice (autres que les appels d'API à d'autres services) dans un seul conteneur déployable est une distinction clé dans l'architecture. Si on ne l'obtient pas, revenez en arrière et étudiez l'architecture.