Peut-on réellement partager une base de données entre microservices ?
Adopter une architecture de microservices réclame généralement de déployer une base de données par service. Cet article démontre qu’il est possible de conserver un SGBD partagé entre plusieurs microservices à condition de respecter certaines exigences.
Depuis des années, les experts insistent sur le fait que le succès d’une architecture de microservices repose sur des contextes délimités. Il s’agit d’établir des frontières claires entre la logique fonctionnelle sous-jacente et les informations sur l’état de l’application. Pour favoriser cette séparation adéquate des services, l’on recommande de passer d’une structure de base de données centralisée à une autre, où chaque service se voit attribuer son propre data store.
Si cette approche favorise l’indépendance des services, le couplage souple et l’isolement des pannes au sein de l’architecture, il est important de tenir compte des contreparties. Déployer une base de données par service complexifie la gestion de l’architecture et s’avère, a priori, plus consommateur en ressources.
Passons en revue les avantages – et les pièges – du déploiement d’une base de données par service par rapport à celui d’un SGBD partagé entre les microservices. Ensuite, nous examinerons si l’approche centralisée peut être bénéfique malgré ses inconvénients potentiels. Nous identifierons dans quel cas ce choix d’architecture s’avère finalement le bon.
Déployer une base de données par service
L’approche consistant à déployer une base de données par service vise à fournir de nombreuses instances d’une fonctionnalité expressément ciblée. Il est possible de choisir différents SGBD, et les services peuvent fonctionner de manière fiable conformément à un schéma de données particulier. De plus, l’architecture peut s’adapter à des débits relatifs et respecter les caractéristiques de lecture/écriture de la base de données. Chaque service évolue de manière indépendante, et les défaillances ou lenteurs causées par des instances voisines ne risquent pas de se propager à de larges portions du système.
Cependant, fournir une base de données dédiée à chaque service présente plusieurs défis. C’est particulièrement le cas dans les SI de grande taille où les exigences d’intégration et de communication sont fortes. Tout d’abord, il faudra beaucoup de temps et d’efforts pour effectuer des jointures de données importantes au-delà des frontières du réseau. La prolifération de tous ces SGBD augmente également le risque d’une redondance de données importante et consommatrice de ressources. Il suffit qu’une équipe ne parvienne pas à définir correctement les contextes délimités. Enfin, le fait de lier des multitudes de bases de données à une grande pile de services indépendants rend difficile le maintien constant de la synchronisation des états des applications.
L’approche de la base de données partagée
La méthode la plus directe pour éviter ces pièges consiste à fournir une base de données unique dans laquelle plusieurs services peuvent puiser les ressources nécessaires. Par exemple, l’utilisation d’un SGBD central rend le processus de combinaison des structures de données d’ensembles disjoints beaucoup plus simple. Tant que toutes les tables requises se trouvent dans une base de données unique, les transactions distribuées peuvent s’exécuter en toute sécurité grâce à leurs fonctionnalités ACID et CRUD (Create, Read, Update, Delete).
Bien entendu, les bases de données partagées comportent leur propre lot d’écueils. Lorsque les schémas des bases de données partagées évoluent au fil du temps, tous les services qui en dépendent devront être mis à jour. Autre inconvénient : tous les services partageant un même SGBD ne l’utiliseront pas nécessairement de la même manière. Donc, la configuration de la base de données pour un service peut provoquer des conflits concernant l’usage des ressources. Par exemple, dans les systèmes logiciels à large échelle, une base de données unique ciblée par plusieurs services est plus susceptible de causer des goulets d’étranglement en matière de débit et de latence.
Une base de données partagée souffrira également lorsqu’elle sera confrontée à des volumes d’écriture élevés. Qui plus est, le compactage des tables de segments peut entraîner des baisses de performances significatives. La problématique du voisin bruyant s’avère alors beaucoup plus difficile à éviter.
Quand utiliser des bases de données partagées entre les microservices
Bien que les inconvénients cités peuvent décourager le déploiement d’une telle architecture, il existe toujours des situations dans lesquelles l’adoption d’une base de données centrale s’avère parfaitement aux microservices.
De fait, il s’agit d’un modèle efficace pour la migration incrémentielle à partir de systèmes complexes et monolithiques. En ce qui concerne la mise en œuvre, la plupart des frameworks modernes de mappage objet-relationnel et d’applications Web permettent facilement à plusieurs services d’utiliser les bases de données simultanément, sans interrompre les opérations.
Voici quelques-uns de ces scénarios pour le maintien de bases de données partagées entre microservices :
Démantèlement d’un monolithe
Lors du découpage d’un monolithe, l’idéal est de commencer par décomposer les collections de logiques métiers sous-jacents en microservices indépendants. Ces microservices peuvent être reliés à une seule base de données. Au fur et à mesure que chaque logique fonctionnelle dispose d’une forme d’indépendance, les tables de la base de données partagée peuvent être partitionnées logiquement pour clarifier la séparation de la logique et des données.
Une fois ces tables correctement partitionnées, il est possible d’adopter l’autre architecture, celle basée sur un SGBD par service. Comme une telle transition peut durer des mois, voire des années, il est judicieux de permettre à un nombre limité de services de partager des bases de données. Et ce même si d’autres services se voient attribuer leur propre data store.
De fortes exigences en matière de cohérence
L’approche de la base de données partagée est également utile lorsque les exigences principales d’une architecture sont axées sur la cohérence des données. Lorsque c’est le cas, malgré la présence de plusieurs services, il peut être utile de créer une base de données partagée qui assure le verrouillage et la synchronisation des données au niveau du SGBD. Les organisations peuvent imposer cette approche soit en l’incluant dans les exigences métier remises aux équipes de développement, soit dans les directives de conception de l’architecture.
Faible volume et forte interdépendance
Les complications liées aux bases de données centralisées s’estompent quand les volumes de données sont faibles. Tant que cette SGBD partagée maintient un partitionnement logique des tables entre les informations logiques et les informations d’état, elle offre une alternative bien plus agréable à la complexité technique associée à la gestion de multiples instances. Même si l’application ou le nombre de services est appelé à croître avec le temps, la base de données partagée peut les supporter jusqu’à ce que le système atteigne une masse critique.
Cela est particulièrement vrai pour les petits systèmes ou applications qui exigent également un certain degré de couplage entre les services. Il est logique de continuer à utiliser une seule base de données dans cette architecture. De fait, vous aurez beaucoup moins de travail de refactoring et de reconception de l’application.
Techniques de prise en charge des bases de données partagées
Comme mentionné précédemment, les bases de données partagées introduisent un couplage étroit entre les services. Elles doivent donc être utilisées avec prudence. Il est par ailleurs important d’examiner si le besoin perçu de partager explicitement une base de données entre des services provient simplement d’une incapacité à définir clairement les contextes délimités.
Toutefois, en supposant que ces contextes délimités soient correctement déterminés, il existe quelques techniques qui peuvent aider les équipes à atténuer les effets indésirables d’un tel data store centralisé.
Partitionnement logique des tables
Même si les microservices partagent une base de données, il est possible de la configurer de sorte que les tables soient séparées par des frontières logiques clairement définies. Ces tables appartiennent alors à des services spécifiques. Il existe des moyens simples de faire respecter cette séparation. Par exemple en attribuant des rôles et des autorisations spécifiques à la base de données aux différents services. Cela permet d’éviter les accès accidentels ou les couplages non désirés entre services. Vous pouvez également créer certaines autorisations communes qui sont utilisées lorsque plusieurs services doivent partager un même ensemble de données.
Un seul writer, plusieurs readers
Il est également possible d’utiliser stratégiquement des tables chaudes (un terme utilisé pour décrire des tables partagées par plusieurs services). L’un des moyens est de permettre à un service de cette table d’être propriétaire de toutes les écritures de données et des processus de mise à jour. Il est nommé « writer ». Pendant ce temps, plusieurs services (via des readers ou réplicas de lecture) peuvent continuer à lire les données sans aucun effet sur les écritures et les mises à jour sous-jacentes. Dans certains cas, il est possible d’effectuer ces mises à jour par le biais d’événements dits change data capture (CDC). Attention, car une seule « tête » d’écriture peut présenter des limites de performance.