3.4 Architecture et stockage des données
Vue d’ensemble et motivation
Les données survivent au code. Les applications sont réécrites tous les quelques années, mais les données qu’elles gèrent (dossiers clients, grands livres financiers, historiques de prestations, dossiers de santé) persistent pendant des décennies. C’est souvent l’actif le plus précieux et le plus réglementé de l’organisation. L’architecture des données est la discipline de décider comment ces données sont modélisées, où elles sont stockées, comment elles sont gardées cohérentes, comment elles évoluent, et comment elles sont servies assez rapidement à l’échelle. Pour une grande organisation, ces décisions sont fondatrices. Votre choix de moteurs de stockage et de modèles de données contraint ce que l’affaire peut faire, à quelle vitesse elle peut bouger, et combien cela coûte, pour toute la vie du système.
Les enjeux sont les plus élevés dans l’entreprise et l’administration publique à cause de l’échelle, la longévité, et la réglementation. Le magasin de transactions d’une banque ne doit jamais perdre ou compter en double un centime. Un registre gouvernemental doit conserver les enregistrements pour des périodes légales et prouver leur intégrité aux auditeurs. Un système de santé doit imposer des règles d’accès et de résidence à grain fin. En même temps, ces organisations servent d’énormes volumes de lecture et d’écriture et ne peuvent pas se permettre que chaque requête frappe une seule base de données relationnelle. Donc l’architecture des données doit concilier la correction et la durabilité avec la performance et l’échelle, et le faire pendant que le schéma continue de changer pour satisfaire de nouveaux mandats.
Ce chapitre couvre les principaux paradigmes de stockage et quand utiliser chacun, la discipline de la persistance polyglotte, la modélisation de données et le problème fréquemment sous-estimé de l’évolution et de la migration de schéma, la mise en cache et les CDN (réseaux de diffusion de contenu) avec le problème notoirement difficile de l’invalidation, et comment les transactions, le verrouillage, et la concurrence se comportent quand vous les poussez à l’échelle. Le fil conducteur est simple : il n’y a pas de base de données universelle. Il y a des compromis, et une bonne architecture des données signifie les choisir consciemment, une charge de travail à la fois.
Principes clés
- Modélisez les données pour s’adapter aux motifs d’accès, pas l’inverse. Concevez le stockage autour de comment les données seront lues et écrites, pas autour d’un modèle abstrait « correct ».
- Il n’y a pas une seule base de données pour tout gouverner. Différentes charges de travail veulent différents moteurs ; la persistance polyglotte est normale à l’échelle.
- La correction d’abord pour les systèmes de référence. Pour les données faisant autorité, la durabilité et la cohérence ne sont pas négociables ; optimisez la performance autour d’elles, pas à travers elles.
- Le schéma changera, donc planifiez-le. Les migrations sont une activité d’ingénierie de premier ordre et continue, pas un événement ponctuel.
- Possédez vos données derrière une frontière de service. Chaque contexte borné (un modèle de domaine autonome avec sa propre frontière explicite) possède ses données ; partager une base de données couple les équipes et détruit l’autonomie.
- La mise en cache est un problème de correction déguisé en gain de performance. Chaque cache introduit un risque de péremption et d’invalidation ; traitez-le délibérément.
- La dénormalisation est un échange, pas un péché. Dupliquer des données pour la performance de lecture est légitime si vous possédez les conséquences de cohérence.
- La cohérence et l’échelle s’échangent. Plus la garantie transactionnelle est forte, plus elle est difficile à distribuer ; achetez seulement ce dont la charge de travail a besoin.
Recommandations
Choisir le paradigme de stockage à partir de la charge de travail
Assortissez chaque charge de travail au modèle qui lui convient. Les bases de données relationnelles donnent une cohérence forte, des jointures, et des transactions matures ; elles sont la valeur par défaut pour les systèmes de référence et tout ce qui a des règles d’intégrité complexes. Les magasins de documents conviennent aux données hiérarchiques, à schéma flexible, lues comme une unité (une commande entière, un profil entier). Les magasins clé-valeur donnent une vitesse extrême pour des recherches simples (sessions, indicateurs de fonctionnalité, caches). Les bases de données graphe excellent là où les relations sont la requête (réseaux de fraude, organigrammes, droits, chaînes d’approvisionnement). Les magasins colonnaires alimentent les requêtes analytiques qui parcourent peu de colonnes sur des milliards de lignes (entrepôts de données, rapports). Les bases de données de séries temporelles optimisent pour des données horodatées à forte charge d’ajout (métriques, télémétrie, capteurs de l’internet des objets (IoT), données de marché). Résistez à forcer un moteur unique à faire chaque travail. Utiliser une base de données relationnelle comme une file, ou un magasin de documents comme un grand livre, invite la douleur.
Adopter délibérément la persistance polyglotte
Les grands systèmes utilisent légitimement plusieurs magasins : un système de référence relationnel, un index de recherche, un cache, un entrepôt analytique, et peut-être un moteur graphe ou de séries temporelles. C’est la persistance polyglotte, et c’est le bon motif quand les charges de travail diffèrent vraiment. Le coût est opérationnel, parce que vous avez maintenant plus de moteurs à exploiter, sécuriser, sauvegarder, et doter en personnel. Gérez ce coût en traitant chaque magasin comme possédé par un service, en standardisant l’outillage opérationnel, et en gardant le nombre de technologies limité à celles qui méritent leur place. Méfiez-vous d’adopter une nouvelle base de données pour chaque besoin mineur. Chacune est un engagement opérationnel permanent.
Modéliser les données et traiter l’évolution de schéma comme continue
Investissez dans la modélisation de données en amont pour les systèmes de référence. Normalisez pour protéger l’intégrité, puis dénormalisez sélectivement pour des points chauds de lecture prouvés. Quel que soit le modèle, le schéma évolue pour toujours, donc rendez les migrations sûres et routinières. Utilisez des scripts de migration versionnés, automatisés, et à sens unique vers l’avant, versionnés dans le contrôle de source et appliqués à travers le pipeline de déploiement. Pour des changements sans temps d’arrêt sur de grandes tables, utilisez le motif expand-contract (changement parallèle) : ajoutez la nouvelle colonne ou table, faites un remplissage rétroactif et une double écriture, migrez les lecteurs, puis retirez l’ancienne forme. Jamais une seule modification cassante. Rendez les changements de schéma rétrocompatibles à travers les déploiements pour que l’ancien et le nouveau code fonctionnent en même temps. Dans les systèmes sourcés par événements ou basés sur les messages, versionnez explicitement vos schémas d’événement et de message et prenez en charge le surclassement des anciens événements (les transformer vers le schéma actuel à la lecture).
Concevoir la mise en cache et l’invalidation les yeux ouverts
La mise en cache et les CDN sont les outils de performance au levier le plus élevé. Un CDN sert du contenu statique et mettable en cache depuis la périphérie près des utilisateurs, et les caches d’application épargnent à la base de données des lectures répétées. Mais la partie difficile est l’invalidation : savoir quand les données en cache sont périmées. Choisissez une stratégie par cas. Utilisez l’expiration basée sur le temps (TTL) là où une légère péremption est acceptable et la plus simple. Utilisez l’invalidation explicite ou l’écriture directe là où la fraîcheur compte. Utilisez le cache-aside là où l’application gère le remplissage. Fixez les TTL consciemment, gardez-vous des ruées de cache (de nombreux clients reconstruisant la même entrée expirée à la fois) avec du verrouillage ou de la coalescence de requête, et prévenez les troupeaux tonitruants sur des caches froids. Ne mettez jamais en cache des données dont la péremption pourrait causer un échec de correction ou de conformité (droits, soldes, consentement) sans un chemin d’invalidation explicite et testé. Traitez les clés de cache, les TTL, et l’invalidation comme des artefacts conçus, pas une configuration accessoire.
Gérer les transactions, le verrouillage, et la concurrence pour l’échelle
Comprenez les niveaux d’isolation et choisissez le plus faible qui reste correct pour chaque transaction, parce qu’une isolation plus élevée coûte de la concurrence. Préférez le contrôle de concurrence optimiste (vérifications de version à l’écriture) pour les charges de travail à faible contention et lourdes en lecture, et recourez au verrouillage pessimiste seulement sous une vraie contention chaude, en gardant les verrous courts et ordonnés de façon cohérente pour éviter les interblocages. À mesure que vous échelonnez, une seule base de données inscriptible devient le goulot d’étranglement. Introduisez des répliques de lecture pour l’échelle de lecture (en acceptant le décalage de réplication), et faites du sharding/partitionnement par une clé qui répartit la charge uniformément et garde les données liées ensemble pour éviter les transactions inter-shards. Rappelez-vous que le sharding échange les jointures inter-shards faciles et les transactions ACID (Atomicité, Cohérence, Isolation, Durabilité) multi-shards, ce qui est souvent pourquoi les sagas et la dénormalisation apparaissent. N’introduisez ces techniques que quand la charge de travail l’exige. Le sharding prématuré ajoute une complexité permanente.
Compromis : avantages et inconvénients
| Type de magasin | Meilleur pour | Forces | Faiblesses |
|---|---|---|---|
| Relationnel | Systèmes de référence, intégrité complexe | ACID, jointures, outillage mature | Plus difficile à échelonner les écritures horizontalement |
| Document | Lectures agrégées, schéma flexible | Lecture/écriture rapide d’objet entier, flexible | Jointures/transactions inter-documents faibles |
| Clé-valeur | Sessions, caches, recherches simples | Vitesse et échelle extrêmes | Aucune requête au-delà de la clé |
| Graphe | Requêtes lourdes en relations | Traversées rapides, expressif | Compétences opérationnelles de niche, limites d’échelle |
| Colonnaire | Analytique, rapports | Balayages agrégés rapides, compression | Mauvais pour les écritures transactionnelles au niveau ligne |
| Séries temporelles | Métriques, télémétrie, IoT | Ajout efficace et requêtes temporelles | But étroit |
Le compromis dominant est la cohérence et les requêtes riches contre l’évolutivité horizontale et la vitesse. Les systèmes relationnels donnent les garanties les plus fortes et les requêtes les plus flexibles, mais ils sont les plus difficiles à échelonner en écriture à travers de nombreuses machines. Les familles NoSQL (non relationnelles) relâchent les jointures, les transactions, ou le schéma pour gagner de l’échelle et de la vitesse. La mise en cache échange de la fraîcheur contre de la latence. Le sharding échange des transactions inter-partitions contre du débit d’écriture. Aucun de ceux-ci n’est universellement juste. L’art est de placer chaque charge de travail sur le point de la courbe que ses besoins réels de correction et de performance exigent.
Questions à discuter avec votre équipe
Pour chaque jeu de données critique, tout le monde peut-il nommer le système de référence unique, ou les caches et projections sont-ils discrètement traités comme la vérité ? Les données survivent au code, et les incidents de données les plus dommageables viennent de la dérive : un cache, un index de recherche, ou une projection de lecture est confondu avec ce qui fait autorité et diverge silencieusement de la vraie source. Dans une grande équipe, cela arrive quand la propriété est floue et que plusieurs services écrivent des copies qui se chevauchent, donc personne ne peut dire quelle valeur est correcte pendant un incident. Apportez une carte de vos données importantes et, pour chaque élément, le magasin unique qui fait autorité plus les copies dérivées qui doivent pouvoir être reconstruites à partir de lui. En finance et en administration publique, pouvoir prouver quel enregistrement est la source légale et reconstruire le reste est souvent une exigence réglementaire, pas une commodité. Tout ce que vous ne pouvez pas reconstruire depuis le système de référence est lui-même un système de référence, que vous l’ayez voulu ou non.
Que coûte réellement chaque moteur de base de données de votre parc à exploiter, sécuriser, et sauvegarder, et chacun mérite-t-il encore sa place ? La persistance polyglotte est juste quand les charges de travail diffèrent vraiment, mais chaque moteur est un engagement opérationnel permanent : correctifs, sauvegardes, surveillance, relecture de sécurité, et du personnel qui le connaît à 3 heures du matin. Une grande organisation peut dériver vers un zoo de magasins adoptés pour une fonctionnalité chacun, et le marginal ajoute du coût pour toujours pendant qu’il sert une charge de travail qu’un magasin que vous exploitez déjà pourrait gérer. Listez chaque moteur, la charge de travail qui le justifie, et qui est d’astreinte pour lui, puis signalez tout adopté pour un besoin qu’un magasin principal pourrait maintenant satisfaire. L’adoption d’une nouvelle base de données devrait franchir une barre élevée, parce qu’en retirer une plus tard signifie une autre migration. Standardiser l’outillage opérationnel à travers les magasins que vous gardez est comment vous gardez le coût bas sans forcer un moteur à faire chaque travail.
Où un utilisateur peut-il lire une valeur périmée d’une réplique juste après sa propre écriture, et cela brise-t-il une promesse que vous lui avez faite ? Les répliques de lecture échelonnent les lectures mais ont du retard sur le primaire, donc un utilisateur qui met à jour un profil et recharge immédiatement peut voir l’ancienne valeur, ce qui se lit comme un bug ou, pour un solde ou un drapeau de consentement, un échec de conformité. Décidez par flux si lecture-de-vos-écritures compte, et acheminez ces lectures vers le primaire ou utilisez un mécanisme de cohérence de session. Apportez la liste des flux servis depuis des répliques et marquez lesquels un utilisateur agit sur immédiatement après avoir écrit. Pour les soldes, les droits, et le consentement, traitez les lectures périmées comme des échecs de correction, pas cosmétiques. Le but est d’acheter la cohérence dont chaque charge de travail a réellement besoin, et de rendre la péremption que vous acceptez explicite plutôt qu’accidentelle.
Pouvez-vous changer le schéma de votre plus grande table la plus fréquentée aujourd’hui sans temps d’arrêt, et qui a réellement répété les étapes d’expand-contract ? Le schéma évolue pour toujours, et l’échec qui fait le plus mal est une modification à grand fracas qui verrouille une énorme table, gèle le service, et ne peut pas être annulée proprement. Dans une grande équipe, le risque se multiplie parce que plusieurs services lisent la même forme, donc un changement cassant a besoin que l’ancien et le nouveau code fonctionnent côte à côte à travers un déploiement échelonné. La tension concurrente est la vitesse : une seule modification est rapide à écrire, tandis qu’expand-contract (ajouter la nouvelle forme, remplir rétroactivement, double écriture, migrer les lecteurs, retirer l’ancienne forme) est plus d’étapes et plus de patience. Apportez votre plus grande table, une estimation honnête de combien de temps une modification naïve la verrouillerait, et une migration spécifique que quelqu’un a exécutée de bout en bout en répétition plutôt qu’en théorie. Dans les systèmes d’entreprise et gouvernementaux qui fonctionnent continuellement et portent des cibles de disponibilité légales, le temps d’arrêt pour une migration est une violation, donc la discipline expand-contract est le prix d’être autorisé à changer le schéma du tout.
Quelles valeurs mises en cache ou répliquées, si servies périmées, causeraient un échec de conformité ou de sécurité plutôt que cosmétique, et chacun de ces chemins d’invalidation est-il testé ? La mise en cache est un problème de correction portant un costume de performance : le danger n’est pas la lenteur mais servir un droit, un solde, un drapeau de consentement, ou une décision d’accès après qu’il a changé. Pour une grande organisation, le danger est diffus, parce que les caches et les couches de périphérie s’accumulent à travers les équipes et qu’aucune personne seule ne peut lister ce qui est en cache où ou quand cela s’efface. La tension est réelle : une mise en cache agressive et de longs TTL achètent de la latence et protègent la base de données, tandis qu’une fraîcheur stricte coûte les deux. Apportez un inventaire des données mises en cache et servies par CDN, marquées pour quelles entrées portent une conséquence de conformité ou de sécurité, plus la preuve que le chemin d’invalidation pour chacune d’elles a été exercé dans la pratique plutôt que simplement configuré. Dans les contextes régulés et publics, une valeur de consentement ou d’éligibilité périmée est un échec auditable, donc ces éléments ont besoin d’un chemin d’invalidation explicite et testé ou ne devraient pas être mis en cache du tout.
Quelle est votre stratégie de rétention, d’archivage, et de résidence des données pour chaque magasin faisant autorité, et pouvez-vous la prouver à un auditeur ? Les données survivent au code et souvent survivent à l’équipe qui l’a écrit, donc la croissance non bornée et les règles de résidence vagues deviennent discrètement le problème que personne ne possède jusqu’à ce qu’une table devienne ingérable ou qu’un enregistrement se trouve dans la mauvaise juridiction. Une grande organisation s’étend sur de nombreux magasins et régions, et les considérations concurrentes sont le coût (le stockage chaud est cher, donc archivez et hiérarchisez), la performance (des tables gonflées ralentissent tout), et le devoir légal (des planchers de rétention légaux et des plafonds de résidence qui peuvent entrer en conflit). Apportez, par jeu de données faisant autorité, la période de rétention, où les données vivent physiquement, le mécanisme d’archivage et de suppression, et le nom de la personne responsable. Pour les systèmes d’entreprise et particulièrement gouvernementaux, la rétention et la résidence sont généralement des mandats légaux avec des exigences d’audit et de souveraineté, donc pouvoir prouver où vit chaque enregistrement, combien de temps il est gardé, et quand il est détruit est un permis d’exploiter, pas une commodité.
Regard sectoriel
Jeune pousse. Exploitez une base de données et résistez au zoo. Un seul magasin relationnel géré vous donne des transactions, une chose à sauvegarder, et un seul endroit pour raisonner sur la cohérence, ce qui est exactement ce qu’une équipe de trois personnes peut se permettre de garder en tête. Ajoutez un cache, une réplique de lecture, ou un index de recherche seulement quand une requête lente spécifique ou un vrai volume de lecture le force, pour que la complexité arrive avec une raison payante. Gardez les migrations versionnées dès le premier jour, parce que rétro-adapter une discipline de migration sur un produit en direct est bien plus difficile que de commencer avec.
Petite entreprise. Vous n’avez pas de spécialiste de base de données et pas de temps pour exploiter plusieurs moteurs, donc favorisez un magasin géré et laissez votre fournisseur de plateforme gérer les sauvegardes, les correctifs, et la réplication. Traitez la sélection de magasin comme une décision d’achat : choisissez le moteur ennuyeux et bien soutenu que vos outils intègrent déjà plutôt que le plus rapide sur un benchmark. Fixez une politique de rétention et de sauvegarde simple que vous pouvez réellement vérifier, et ne mettez jamais en cache quoi que ce soit lié à l’argent ou aux permissions sans un moyen clair de l’effacer, parce qu’un prix ou un droit périmé vous coûte un client.
Grande entreprise. Le défi central est la persistance polyglotte à travers de nombreuses équipes : un système de référence relationnel plus de la recherche, un cache, un entrepôt, et peut-être des moteurs graphe ou de séries temporelles, chacun possédé par un service plutôt que partagé. Standardisez l’outillage opérationnel, la sauvegarde, et la surveillance à travers les magasins que vous gardez, tenez l’adoption de nouveau moteur à une barre élevée, et faites des migrations expand-contract et de l’invalidation de cache explicite la valeur par défaut. Gérez le parc comme un portefeuille avec une propriété de données claire, pour qu’aucun moteur ne survive au-delà de la charge de travail qui l’a justifié et qu’aucune équipe ne soit couplée à travers une base de données partagée.
Gouvernement. La résidence des données, la rétention légale, et l’intégrité prouvable façonnent chaque choix. Provisionnez chaque magasin dans des régions souveraines, configurez les CDN pour ne mettre en cache que des données non personnelles, et gardez un historique d’audit immuable pour les enregistrements qui doivent être reconstructibles pour les régulateurs. Les migrations mandatées par une nouvelle législation doivent être appliquées de façon rétrocompatible à travers le pipeline pour que le service reste disponible à travers les échéances législatives, et le système de référence doit être identifiable pour que vous puissiez prouver quelle valeur est la source légale et reconstruire chaque copie dérivée à partir de lui.
Exemples
Jeune pousse. Une start-up en phase d’amorçage fait tout tourner sur une seule instance PostgreSQL gérée et résiste à l’envie d’ajouter un moteur de recherche séparé, un cache, et un entrepôt avant d’en avoir besoin. Une base de données signifie une chose à sauvegarder, un endroit pour raisonner sur la cohérence, et des transactions qui fonctionnent simplement, ce qui compte quand toute l’équipe compte trois ingénieurs. Elle ajoute un cache Redis et une réplique de lecture seulement quand une requête lente spécifique et un vrai volume de lecture le justifient, pour que la complexité arrive avec une raison payante plutôt qu’en avance sur une.
Grande entreprise. Une banque de détail garde son grand livre faisant autorité dans une base de données relationnelle fortement cohérente : chaque écriture est une vraie transaction ACID, shardée par plage de compte pour l’échelle d’écriture. Autour d’elle se trouve un parc polyglotte : un index de recherche pour la recherche client, un cache Redis (écriture directe, TTL court) pour les résumés de compte sur l’application mobile, un entrepôt colonnaire pour le reporting réglementaire et analytique, et une base de données graphe pour la détection de fraude en réseau de transactions. Les changements de schéma du grand livre utilisent expand-contract avec des doubles écritures pour que le système 24/7 ne prenne jamais de temps d’arrêt pour une migration.
Gouvernement. Un registre national des véhicules stocke les enregistrements faisant autorité dans un système de référence relationnel avec une rétention légale et un historique d’audit complet. Les recherches orientées public « vérifier un véhicule » sont servies depuis une réplique de lecture et un cache de périphérie avec un TTL court, parce que des données publiques légèrement périmées sont acceptables et que le volume de lecture éclipse les écritures. La loi sur la résidence des données exige que tous les enregistrements restent dans le pays, donc chaque magasin est provisionné dans des régions souveraines et le CDN est configuré pour ne mettre en cache que des données non personnelles. Les migrations pour ajouter de nouveaux champs mandatés par la politique de transport sont appliquées de façon rétrocompatible à travers le pipeline pour que le service reste disponible pendant les échéances législatives.
Argumentaire économique : motivations, retour sur investissement et coût total de possession
Les décisions d’architecture des données ont parmi les traînées de coût les plus longues et les plus grandes en logiciel, parce que les données et leur schéma sont les choses les plus difficiles à changer une fois que les systèmes et les intégrations en dépendent. Le coût d’adoption de bonnes pratiques (sélection délibérée de magasin, migrations disciplinées, mise en cache conçue, et sharding approprié) est principalement du temps d’ingénierie senior et un peu d’outillage opérationnel supplémentaire. Le coût de ne pas les adopter se manifeste comme une seule base de données surchargée qui étrangle toute l’affaire, un re-portage d’urgence quand le mauvais magasin est découvert trop tard, des pannes prolongées d’une migration bâclée, et, le plus dommageable, une corruption de données ou une violation de conformité d’un cache mal invalidé ou d’une transaction perdue.
Faites valoir cela auprès de la direction en termes de marge d’évolutivité, de risque d’incident, et d’exposition réglementaire. Les bons choix de stockage sont ce qui permet à l’affaire de faire grandir le volume de lecture et d’écriture sans réécriture. Des migrations disciplinées sont ce qui permet au schéma de suivre le rythme des nouveaux mandats sans temps d’arrêt. Une mise en cache correcte est ce qui livre des expériences utilisateur rapides sans bugs de péremption silencieux. Quantifiez le CTP sur la vie du système. Une seule architecture de données bien choisie évite le coût récurrent de contourner une mauvaise, et un incident de corruption de données évité éclipse typiquement le coût entier de bien le faire. Dans les secteurs régulés, la capacité de prouver l’intégrité et la résidence des données n’est pas un centre de coût mais un permis d’exploiter.
Anti-patterns et pièges
- Base de données partagée à travers les services. Plusieurs services lisant et écrivant un seul schéma, couplant les équipes et faisant de chaque changement une crise de coordination.
- Une base de données pour tout. Forcer l’analytique, les files, la recherche, et les transactions dans un seul moteur relationnel jusqu’à ce qu’il s’effondre.
- Migrations à grand fracas. Des changements de schéma cassants uniques qui exigent un temps d’arrêt et ne peuvent pas être annulés en sécurité.
- Mise en cache sans stratégie d’invalidation. Des données périmées servies indéfiniment, ou des bugs de correction parce que personne ne possède quand le cache s’efface.
- Sharding prématuré. Distribuer les données avant que la charge ne l’exige, perdant définitivement les jointures et les transactions sans bénéfice.
- Ignorer le décalage de réplication. Lire votre propre écriture depuis une réplique en retard et obtenir des données périmées, brisant les attentes des utilisateurs.
- Croissance de données non bornée. Aucune stratégie d’archivage ou de rétention, donc les tables grandissent jusqu’à ce que la performance et le coût deviennent intenables.
- Stocker des données dérivées comme vérité. Traiter un cache, un index, ou une projection comme le système de référence, puis découvrir qu’il a dérivé.
Modèle de maturité
- Niveau 1 (Initier) : Une base de données est utilisée pour chaque but. Les changements de schéma sont manuels et ad hoc, sans discipline de migration. La mise en cache est accessoire et l’invalidation une réflexion après coup. Les problèmes de performance sont résolus réactivement en achetant une machine plus grosse, et personne ne peut nommer de façon fiable le système de référence pour un jeu de données donné.
- Niveau 2 (Développer) : Certains choix de stockage sont délibérés et un cache ou un entrepôt est apparu, mais la pratique varie par équipe. Les migrations sont versionnées mais exigent parfois un temps d’arrêt, et expand-contract est utilisé par quiconque le connaît. Plusieurs services partagent encore une base de données, et les stratégies de mise en cache diffèrent d’une équipe à l’autre.
- Niveau 3 (Standardiser) : La persistance polyglotte est assortie aux charges de travail, chaque magasin possédé par un service et jamais partagé. Les migrations expand-contract automatisées, rétrocompatibles, et sans temps d’arrêt sont la norme documentée et imposée à l’échelle de l’organisation. Les stratégies de mise en cache, les TTL, et les chemins d’invalidation sont des artefacts de conception explicites, et le système de référence unique pour chaque jeu de données est documenté, avec des copies dérivées reconstructibles à partir de lui.
- Niveau 4 (Gérer) : Le parc de données est mesuré et contrôlé par rapport à des références. Vous suivez la durée de migration et le taux d’annulation, le décalage de réplication par rapport aux exigences de lecture-de-vos-écritures, le ratio de succès de cache et les incidents de péremption, le coût opérationnel par magasin, et la latence de requête aux percentiles cibles, puis agissez sur les chiffres. La rétention et la résidence sont auditées par rapport aux exigences légales, la correction des données dérivées est vérifiée continuellement, et chaque moteur doit justifier son coût par rapport à la charge de travail qu’il sert.
- Niveau 5 (Orchestrer) : L’architecture des données est continuellement améliorée et intégrée à la planification de capacité, de coût, et de risque à travers l’organisation. Les choix de sharding, de mise en cache, et de cohérence sont rééquilibrés par charge de travail à mesure que les motifs d’accès et le coût changent, et les magasins qui ne méritent plus leur place sont retirés à travers des migrations planifiées. L’évolution de schéma, l’archivage, et la résidence sont entièrement automatisés et adaptatifs, si bien que le parc se refaçonne à de nouveaux mandats et charge sans re-portage d’urgence.
Pistes de réflexion
- Lesquels de vos magasins actuels font un travail pour lequel ils n’étaient pas conçus, et quel serait le bon moteur ?
- Pouvez-vous effectuer un changement de schéma sur votre plus grande table aujourd’hui avec zéro temps d’arrêt ? Sinon, pourquoi pas ?
- Où votre système met-il en cache des données dont la péremption pourrait causer un échec de conformité ou de correction ?
- Quels services partagent une base de données, et que faudrait-il pour donner à chacun la sienne ?
- Où une seule base de données inscriptible est-elle votre plafond d’échelle, et la réplication de lecture ou le sharding est-il la bonne prochaine étape ?
- Quelle est votre stratégie de rétention et d’archivage, et qui en est responsable ?
Points clés à retenir
- Les données survivent au code ; les décisions de stockage et de modélisation contraignent l’affaire pour toute la vie du système.
- Assortissez chaque charge de travail au paradigme de stockage qui convient à son motif d’accès ; attendez-vous à de la persistance polyglotte à l’échelle.
- Donnez à chaque service la propriété de ses données ; ne couplez jamais des équipes à travers une base de données partagée.
- Traitez l’évolution de schéma comme continue et utilisez des migrations expand-contract rétrocompatibles et sans temps d’arrêt.
- La mise en cache est un problème de correction : concevez les TTL, l’invalidation, et la protection contre les ruées délibérément, et ne mettez jamais en cache des données critiques pour la conformité sans un chemin d’invalidation testé.
- Achetez seulement la cohérence et les garanties transactionnelles dont chaque charge de travail a besoin ; le sharding et la réplication échangent des transactions inter-partitions contre de l’échelle.
Références et lectures complémentaires
- Martin Kleppmann, Designing Data-Intensive Applications
- Pramod Sadalage et Martin Fowler, NoSQL Distilled
- Pramod Sadalage et Scott Ambler, Refactoring Databases: Evolutionary Database Design
- C. J. Date, An Introduction to Database Systems
- Joe Celko, SQL for Smarties
- Vlad Mihalcea, High-Performance Java Persistence (transactions, isolation, concurrence)
- Eric Evans, Domain-Driven Design (contextes bornés et propriété des données)
- Werner Vogels, « Eventually Consistent »