Bonjour, Habr!
La traduction d'aujourd'hui touche non seulement et pas tellement aux microservices - un sujet que tout le monde a sur les lèvres aujourd'hui - mais rappelle également combien il est important d'appeler un chat un chat. La transition vers une architecture de microservices est parfois nécessaire, mais, comme le souligne encore une fois l'auteur, elle nécessite un examen attentif des conséquences. Bonne lecture et fructueuse!

De temps en temps, je pose la même question.
Y a-t-il une vérité si importante que seuls quelques-uns sont d'accord avec vous? - Peter Thiel
Avant de m'asseoir pour ce poste, j'ai essayé sur cette question pendant longtemps sur un sujet, qui est aujourd'hui dans une tendance sérieuse - il s'agit des microservices. Je pense que maintenant j'ai quelque chose à dire; certains résultats sont basés sur la réflexion, d'autres sur l'expérience pratique. Alors, je vous le dis.
Commençons par une vérité importante qui servira de point de référence pour nous le long du chemin comme une étoile polaire.
La plupart des implémentations de microservices ne sont rien d'autre que des monolithes distribués.
Epoque des monolithes
Tout système a commencé comme une application monolithique. Je n'entrerai pas dans les détails de ce sujet ici - beaucoup ont déjà écrit sur beaucoup. Cependant, la part du lion des informations sur les monolithes est consacrée à des questions telles que la productivité et l'évolutivité des développeurs, tout en laissant derrière les crochets l'atout le plus précieux de toute société Internet: les données.
Architecture d'application monolithique typiqueSi les données sont si importantes, alors pourquoi toute l'attention est-elle accordée à d'autres sujets, mais pas à eux? La réponse, en général, est simple: car ils ne sont pas aussi douloureux que la question des données.
Peut-être que le monolithe est la seule étape du cycle de vie du système où vous:
- Comprenez parfaitement votre modèle de données;
- Vous pouvez coopérer avec les données (il est supposé que votre base de données est correctement sélectionnée pour votre application).
En termes de données, le monolithe est idéal. Et puisque les données sont l'actif le plus précieux de toute entreprise, il est préférable de ne pas briser le monolithe, sauf si vous avez une très bonne raison, ou une combinaison de ces raisons. Dans la plupart des cas, la raison décisive de ce type est la nécessité de l'échelle (puisque nous vivons dans le monde réel avec ses limites physiques inhérentes).
Lorsque ce moment arrive, votre système entre très probablement dans une nouvelle hypostase: il
se transforme en un monolithe distribué .
L'ère des monolithes distribués
Supposons que tout se passe bien dans votre entreprise et que l'application doit se développer. Vous avez de plus en plus de gros clients, et vos exigences en matière de facturation et de reporting ont évolué à la fois en termes d'opportunités et de volume.
Reprenant sérieusement la démolition du monolithe, en particulier, vous tenterez de mettre en place deux petits services, dont l'un fournira des rapports, et le second - la facturation. Très probablement, ces nouveaux services fourniront une API HTTP et disposeront d'une base de données dédiée pour le stockage d'état à long terme. Après de nombreuses validations, vous, comme nous chez
Unbabel , pouvez obtenir quelque chose qui ressemble à l'illustration suivante.
Une vue générale de l'architecture du système après avoir détaché les services de facturation et de reporting de l'application monolithique principaleTout se passe comme prévu.
- L'équipe continue de diviser le monolithe en systèmes plus petits;
- Les convoyeurs d'intégration / livraison en continu fonctionnent comme sur des roulettes;
- Le cluster Kubernetes est sain, les ingénieurs sont productifs et satisfaits de tout.
La vie est belle.
Mais que se passe-t-il si je dis qu'en ce moment, de vils complots se tissent contre vous?
Maintenant, en regardant votre système, vous constaterez que les données ont été réparties sur de nombreux systèmes différents. Vous êtes parti de l'étape où vous aviez une base de données unique où tous les objets de données étaient stockés, et maintenant vos objets de données se sont propagés à différents endroits. Vous penserez peut-être qu'il n'y a pas de problème, car des microservices sont nécessaires pour créer des abstractions et sceller des données, cachant la complexité interne du système.
Vous avez absolument raison. Mais avec une échelle croissante, des problèmes plus complexes se posent: maintenant, à tout moment, vous êtes obligé de répondre aux exigences de l'entreprise (par exemple, pour suivre une métrique) qui nécessitent un accès aux données situées dans plusieurs systèmes.
Que faire? En fait, il existe de nombreuses options. Mais pressé, vous devez également servir une énorme fraternité de clients qui se sont récemment inscrits auprès de vous, vous devez donc trouver un équilibre entre «rapide» et «bon». Après avoir discuté des détails, vous décidez de construire un système supplémentaire qui effectuerait un certain travail ETL, contribuant à la solution des tâches finales. Ce système devra avoir accès à toutes les répliques en lecture contenant les informations dont vous avez besoin. La figure suivante montre comment un tel système pourrait fonctionner.
Un exemple généralisé d'un système ETL analytique (dans Unbabel, nous l'avons appelé Automatic Translation Analytics)Chez Unbabel, nous avons utilisé cette approche, car:
- Cela n'affecte pas trop les performances de chaque microservice;
- Il ne nécessite pas de changements majeurs d'infrastructure (il suffit d'ajouter un nouveau microservice);
- Nous avons pu satisfaire assez rapidement nos besoins commerciaux.
L'expérience suggère que pendant un certain temps, cette approche fonctionnera - jusqu'à atteindre une certaine échelle. Chez Unbabel, il nous a très bien servi jusqu'à très récemment, lorsque nous avons commencé à faire face à des défis de plus en plus sérieux. Voici certaines choses qui se sont transformées en maux de tête pour nous:
1. Modifications des donnéesL'un des principaux avantages des microservices est l'encapsulation. La représentation interne des données peut changer, mais cela n'affecte pas les clients du système, car ils communiquent via une API externe. Cependant, notre stratégie exigeait un accès direct à la représentation interne des données, et donc, dès que l'équipe n'a apporté que quelques modifications à la présentation des données (par exemple, renommer un champ ou changer le type de
text
en
uuid
), nous avons également dû changer et redéployer notre ETL- service.
2. La nécessité de traiter de nombreux schémas de données différentsÀ mesure que le nombre de systèmes auxquels nous devions nous connecter augmentait, nous devions faire face à des façons de plus en plus hétérogènes de présenter les données. Il était évident que nous ne pouvions pas mettre à l'échelle tous ces schémas, les relations entre eux et leurs représentations.
La racine de tout malPour avoir une image complète de ce qui se passe dans le système, nous avons dû nous arrêter à une approche ressemblant à un monolithe. La différence était que nous n'avions pas un système et une base de données, mais des dizaines de paires de ce genre, chacune avec sa propre représentation des données; de plus, dans certains cas, les mêmes données ont été répliquées sur plusieurs systèmes.
Je préfère appeler un tel système un monolithe distribué. Pourquoi? Puisqu'il est totalement inapproprié pour suivre les changements dans le système, et la seule façon d'afficher l'état du système est de collecter un service qui se connecte directement aux entrepôts de données de tous les microservices. Il est intéressant de voir combien de colosses d'Internet ont également fait face à des défis similaires à un moment donné de leur développement. Un bon exemple dans ce cas que j'aime toujours donner est le réseau LinkedIn.
C'est le genre d'incident de données que les flux d'informations de Linkedin représentaient vers 2011 - sourceEn ce moment, vous vous demandez peut-être: "qu'est-ce que vous allez faire avec tout ça?" La réponse est simple: vous devez commencer à suivre les modifications et suivre les actions importantes au fur et à mesure qu'elles se produisent.
Briser un monolithe distribué en utilisant Event SourcingComme pratiquement le reste du monde, les systèmes sur Internet sont réactifs. Ainsi, une demande à l'API peut conduire à l'insertion d'un nouvel enregistrement dans la base de données. Actuellement, dans la plupart des cas, ces détails ne nous dérangent pas, car nous souhaitons principalement mettre à jour l'état de la base de données. La mise à jour de l'état d'une base de données est une conséquence conditionnelle d'un événement (dans ce cas, une demande d'API). Le phénomène événementiel est simple et, néanmoins, le potentiel des événements est très important - ils peuvent même être utilisés pour détruire un monolithe distribué.
Un événement n'est rien de plus qu'un fait immuable d'une modification qui s'est produite dans votre système . Dans l'architecture de microservices, les événements deviennent critiques et aident à comprendre les flux de données et, sur leur base, à déduire l'état agrégé de plusieurs systèmes. Chaque microservice qui effectue une action intéressante du point de vue de l'ensemble du système doit générer un événement ainsi que toutes les informations essentielles liées au fait que cet événement représente.
Vous avez peut-être une question:
«Comment les microservices qui génèrent des événements peuvent-ils m'aider à résoudre le problème du monolithe distribué?»
Si vous avez des systèmes qui génèrent des événements, il peut y avoir un journal des faits avec les propriétés suivantes:
- Absence de liaison à tout entrepôt de données: les événements sont généralement sérialisés en utilisant des formats binaires tels que JSON, Avro ou Protobufs;
- Immuabilité: dès qu'un événement est généré, il est impossible de le changer;
- Reproductibilité: l'état du système à un moment donné peut être restauré; pour cela, il suffit de «rejouer» le journal des événements.
À l'aide de ce journal, vous pouvez afficher l'état à l'aide de n'importe quel type de logique au niveau de l'application. Vous n'êtes plus associé à aucun ensemble de microservices et
N façons dont les données sont présentées. La seule source de vérité et votre seul entrepôt de données est désormais le référentiel où vos événements sont stockés.
Voici quelques raisons pour lesquelles le journal des événements me semble être le moyen d'aider à briser le monolithe distribué:
1. La seule source de véritéAu lieu de maintenir N sources de données qui peuvent être nécessaires pour se connecter à des bases de données (multiples) hétérogènes, dans ce nouveau scénario, la vérité ultime est stockée dans exactement un référentiel: le journal des événements.
2. Format de données universelDans la version précédente du système, nous devions gérer de nombreux formats de données, car nous étions directement connectés à la base de données. Dans la nouvelle mise en page, nous pouvons agir de manière beaucoup plus flexible.
Disons que vous avez aimé une photo Instagram publiée par l'un de vos amis. Une telle action peut être décrite: «L'
utilisateur X aimait l'image P ». Et voici un événement représentant ce fait:
Un événement correspondant à l'approche AVO (Acteur, Verbe, Objet), simulant le fait que l'utilisateur sélectionne l'image qu'il aime.3. Affaiblissement de la communication entre producteurs et consommateursEnfin et surtout, l'un des plus grands avantages des opérations événementielles est l'affaiblissement effectif de la communication entre les producteurs de données et les consommateurs. Cette situation simplifie non seulement la mise à l'échelle, mais réduit également le nombre de dépendances entre elles. Le seul contrat restant entre les systèmes dans ce cas est le diagramme d'événements.
Au début de cet article, la question a été posée: existe-t-il une vérité aussi importante dans laquelle seuls quelques-uns sont d'accord avec vous?
Permettez-moi d'y revenir en conclusion de cette excursion. Je pense que la plupart des entreprises ne considèrent pas les données comme des «entités de premier ordre» lorsqu'elles commencent la migration vers une architecture de microservices. On fait valoir que tous les changements de données peuvent encore être effectués via l'API, mais cette approche conduit finalement à une complication constante du service lui-même.
Je crois que la seule véritable approche pour capturer les changements de données dans une architecture de microservices est de faire émettre des événements par les systèmes selon un contrat strictement défini. Le fait d'avoir un journal des événements correctement compilé vous permet d'afficher un grand nombre de données en fonction de n'importe quel ensemble d'exigences métier. Dans ce cas, il vous suffit d'appliquer des règles différentes aux mêmes faits. Dans certains cas, une telle fragmentation des données peut être évitée si votre entreprise (en particulier vos chefs de produit) traite les données comme un produit. Cependant, c'est un sujet pour un autre article.