Be Software Architecture Wise
Be Wise Apps

Read in English · Leer en español · Auf Deutsch lesen

Chapitre 7 sur 12 · Intermédiaire à avancé

Architecture des données

Les données survivent au code, et dans les systèmes distribués elles sont la partie la plus difficile à réussir. Ce chapitre traite de la question de savoir à qui appartient chaque donnée et pourquoi une base de données partagée couple les services, de la manière de choisir entre bases relationnelles et autres bases, de ce que les transactions et les niveaux d’isolation garantissent réellement, de la façon dont la réplication et le partitionnement fonctionnent et échouent, de CQRS et de l’event sourcing, de la mise en cache, de l’évolution des schémas sans interruption de service, ainsi que de l’analytique, du streaming et du data mesh. Il s’adresse aux développeurs et aux architectes qui connaissent déjà les styles distribués du chapitre 6 et doivent prendre des décisions solides et défendables sur les données.

Introduction vidéo au chapitre 7

7 min · narré en anglais, avec sous-titres
Écouter seulement (audio)
Lire la transcription

Bienvenue dans le chapitre 7 : Architecture des données. Le code peut être réécrit en quelques mois, mais les données vivent pendant des décennies. Les comptes clients, les grands livres, les commandes et les dossiers médicaux survivent à chaque framework et à chaque service qui les touche. Déplacer ces données est lent, risqué et coûteux. C’est pourquoi les décisions de ce chapitre comptent parmi les plus importantes que prend un architecte : elles sont difficiles à défaire, larges dans leur portée, et déterminantes pour la disponibilité, les performances et la modifiabilité.

Ce chapitre s’adresse aux développeurs et aux architectes qui connaissent déjà les styles distribués du chapitre 6, et qui doivent maintenant prendre des décisions solides et défendables sur les données. Il s’appuie directement sur le chapitre 6. Découper le code en services est la moitié facile. Dès qu’il y a plusieurs services, quelqu’un doit décider qui peut modifier chaque donnée, comment les autres la voient, et ce qui se passe quand ses copies divergent. Il suppose aussi acquises les bases des bases de données vues dans la section du chapitre 0 sur le stockage des données. Si les tables, les requêtes et les transactions sont nouvelles pour vous, commencez par là. Et il mène au chapitre 8, qui protège ces données et le système dans son ensemble.

Le chapitre compte huit sections et suit deux exemples récurrents : une plateforme de livraison de repas, avec son coup de feu du soir, la position des livreurs et les cartes, et une banque en ligne, où perdre ou compter deux fois un seul paiement est inacceptable. La section sept point un, sur la propriété des données, pose la règle la plus importante : chaque fait important doit avoir un seul système de référence et un seul rédacteur. Elle explique pourquoi une base de données partagée couple les services, aussi proprement que leur code soit séparé. La section sept point deux passe en revue les bases relationnelles, orientées documents, clé-valeur, orientées graphe, de séries temporelles et d’autres encore. Elle soutient que la base relationnelle reste le bon choix par défaut pour les systèmes de référence, et que chaque base spécialisée doit mériter sa place. La section sept point trois va au-delà du sigle bien connu ACID pour examiner les anomalies que provoque la concurrence, comme les mises à jour perdues et le write skew, et ce que les niveaux d’isolation garantissent réellement dans les bases de données les plus répandues. La section sept point quatre explique comment les bases de données copient et répartissent les données entre plusieurs machines, ce que le retard de réplication et le failover font à l’exactitude, et comment choisir une clé de sharding à partir des chiffres.

Voici la première et la plus importante idée du chapitre, tirée de la section sept point un. L’image compare deux façons de fournir leurs données à trois services. À gauche, les services de commandes, de cuisine et de livraison lisent et écrivent tous dans une même base de données partagée de commandes, de cartes et de livreurs. N’importe quel service peut modifier n’importe quelle table : chaque table est donc une interface publique, et toute modification de schéma exige une mise en production coordonnée. À droite, chaque service a sa propre base de données. Chaque schéma est privé, il n’y a pas de jointures entre bases de données, et les données ne franchissent les frontières que par des appels d’API et des événements. Désormais, chaque propriétaire peut modifier son schéma seul. Cette indépendance a un prix. Les jointures, les transactions et l’intégrité référentielle entre services doivent être remplacées par des API, des événements, des sagas et des pipelines de reporting, et la section montre comment lire des données dont vous n’êtes pas propriétaire.

La seconde moitié du chapitre porte sur les données dérivées des systèmes de référence, et sur le changement dans le temps. La section sept point cinq couvre la séparation des responsabilités entre commandes et requêtes, ou CQRS, et l’event sourcing. Ces approches séparent le modèle qui accepte les changements des modèles qui répondent aux requêtes, et stockent un historique d’événements plutôt que l’état courant, au prix d’une complexité bien réelle. La section sept point six porte sur la mise en cache : conserver des copies au plus près de l’endroit où elles sont nécessaires, du navigateur à la base de données, y compris les ruées sur le cache qui peuvent faire tomber un système quand une entrée très demandée expire. La section sept point sept part du constat que tout schéma, qu’il s’agisse de tables de base de données, de charges utiles d’API ou d’événements, changera pendant que le système fonctionne. Les règles de compatibilité et le patron expansion-contraction permettent ce changement sans interruption de service. Enfin, la section sept point huit passe de la conduite de l’activité à sa compréhension : entrepôts de données, data lakes et lakehouses, traitement de flux, et data mesh, une manière d’organiser les données analytiques autour des domaines.

Les sections forment une chaîne, et ce schéma de la section sept point deux montre cette chaîne dans une plateforme de livraison de repas. Commandes et Cartes écrivent chacun dans leur propre base de données PostgreSQL. Ce sont les deux seuls systèmes de référence, et ils contiennent les commandes, les paiements et les cartes. Tout le reste est une copie délibérée. La position des livreurs est conservée dans une base clé-valeur en mémoire et expire au bout de trente secondes. La capture des données modifiées copie les changements de carte dans un moteur de recherche, avec quelques secondes de retard. Et un entrepôt de données reçoit les commandes, les cartes et un échantillon des points de trajet des livreurs pour l’analytique, avec quelques heures de retard. Chaque copie est plus rapide ou plus pratique pour un certain usage, chacune est périmée dans une certaine mesure, et chacune peut être reconstruite.

Cette chaîne mène à l’idée à retenir de ce chapitre. Pour chaque donnée importante, vous devez pouvoir répondre à trois questions. Premièrement, qui est son seul rédacteur ? Deuxièmement, où ses règles sont-elles appliquées ? Et troisièmement, à quel point chacune de ses copies peut-elle être périmée ? La plupart des problèmes de données des systèmes réels, comme des commandes dont l’état recule, des rapports en désaccord avec le grand livre, des doubles réservations ou des clients qui ne voient pas leurs propres modifications, viennent de ce qu’on n’a pas répondu délibérément à l’une de ces questions. Les techniques de ce chapitre sont des moyens d’y répondre correctement, et chacune d’elles est un compromis entre cohérence, disponibilité, performances, coût et effort d’exploitation du système.

À la fin du chapitre, vous saurez attribuer la propriété des données, y compris dans les cas délicats où plusieurs services veulent écrire les mêmes données. Vous saurez choisir une base de données pour chaque jeu de données, selon sa forme, ses schémas d’accès, ses besoins de cohérence et son échelle, et justifier le coût de chaque base supplémentaire. Vous saurez protéger un chemin lecture-modification-écriture par verrouillage, vérification de version ou transactions sérialisables. Et vous saurez planifier des modifications de schéma, avec des règles de compatibilité et l’expansion-contraction, afin qu’elles n’exigent aucune interruption de service.

Comme les sections forment une chaîne, mieux vaut les lire dans l’ordre. Mais chacune se suffit aussi à elle-même : vous pouvez donc aller directement à la section dont vous avez besoin. Comptez environ trois heures et demie pour lire tout le chapitre. À la fin de chaque section, vous trouverez des questions d’autoévaluation. Répondez-y de tête avant de regarder les réponses ; elles vous montrent rapidement ce que vous avez retenu. Quand vous êtes prêt, un test facultatif du chapitre vous attend ; il dure environ quarante-cinq minutes. Il comporte vingt questions à choix multiples et deux réponses rédigées. La note de réussite est de quatre-vingts pour cent.

Voilà la structure du chapitre. Commencez par la section sept point un, sur la propriété des données et la base de données par service, où la règle d’un seul rédacteur pour chaque fait est exposée en détail. À très vite.

Télécharger le chapitre (PDF)Lire dans l’application

En un coup d’œil

Vous apprendrez à

  • Expliquer pourquoi une base de données partagée couple les services, et attribuer la propriété des données, y compris lorsque plusieurs services écrivent les mêmes données.
  • Choisir une base de données pour chaque ensemble de données selon la forme des données, les modes d’accès, les besoins de cohérence, l’échelle, l’exploitation et les compétences de l’équipe, et justifier le coût de chaque stockage supplémentaire.
  • Distinguer les niveaux d’isolation et les anomalies qu’ils permettent, dont les mises à jour perdues et le write skew, et protéger un chemin lecture-modification-écriture par verrouillage, vérification de version ou transactions sérialisables.
  • Expliquer la réplication leader-suiveur, multi-leader et sans leader, les anomalies causées par le retard de réplication, et les risques du failover et du split brain.
  • Choisir un schéma de partitionnement et une clé de sharding à partir de volumes et de requêtes mesurés, et expliquer le hachage cohérent, les clés très sollicitées et les index secondaires.
  • Décider quand CQRS, l’event sourcing et la mise en cache valent leur coût, et éviter leurs défaillances courantes.
  • Planifier les modifications de schéma avec des règles de compatibilité et le patron expansion-contraction, afin qu’elles n’exigent aucune interruption de service.
  • Distinguer les architectures de données opérationnelles et analytiques : entrepôts de données, data lakes, lakehouses, traitement de flux et data mesh.

Avant de commencer

Le chapitre 6, en particulier les sections sur les microservices, l’architecture pilotée par les événements, la cohérence, CAP et PACELC, et les sagas. La section du chapitre 0 sur le stockage des données couvre les bases des bases de données supposées acquises ici.

Durée

Environ 3 heures et demie de lecture ; 45 minutes pour le test.

Termes clés

système de référence · base de données par service · persistance polyglotte · niveau d’isolation · isolation par instantané · write skew · retard de réplication · hachage cohérent · CQRS · event sourcing · cache-aside · expansion-contraction · lakehouse · data mesh

Pourquoi les données sont la partie difficile

Le code peut être réécrit en quelques mois ; les données vivent pendant des décennies. Les comptes clients, les grands livres, les commandes et les dossiers médicaux survivent à chaque framework et à chaque service qui les touche, et les déplacer est lent, risqué et coûteux. C’est pourquoi les décisions de ce chapitre comptent parmi les plus importantes que prend un architecte, au sens du chapitre 1 : elles sont difficiles à défaire, larges dans leur portée et déterminantes pour des attributs de qualité comme la disponibilité, les performances et la modifiabilité.

Le chapitre 6 a découpé les systèmes en services qui communiquent par le réseau. Découper le code est la moitié facile. Dès qu’il y a plusieurs services, quelqu’un doit décider qui peut modifier chaque donnée, comment les autres la voient, quelles garanties tiennent quand de nombreux utilisateurs agissent en même temps, et ce qui se passe quand les copies des données divergent. Le chapitre suit deux exemples récurrents : une plateforme de livraison de repas, avec son coup de feu du soir, la position des livreurs et les cartes des restaurants, et une banque en ligne, où perdre ou compter deux fois un seul paiement est inacceptable.

Posséder, stocker et protéger les données

Les quatre premières sections portent sur les données opérationnelles qui font tourner les systèmes. Propriété des données établit la règle la plus importante : chaque fait important doit avoir un seul système de référence et un seul rédacteur. Elle explique pourquoi une base de données d’intégration partagée couple les services, aussi proprement que leur code soit séparé, comment résoudre les cas où plusieurs services veulent écrire les mêmes données, comment lire des données dont vous n’êtes pas propriétaire, et comment les contrats de données rendent fiables les données partagées.

Choisir une base de données passe en revue les bases relationnelles, orientées documents, clé-valeur, orientées colonnes larges, orientées graphe, de séries temporelles, de recherche, vectorielles et SQL distribuées, et soutient que la base relationnelle reste le bon choix par défaut pour les systèmes de référence, les bases spécialisées ne méritant leur place qu’en satisfaisant une exigence que le choix par défaut ne peut pas satisfaire. Transactions et isolation va au-delà du sigle bien connu ACID pour examiner les anomalies que provoque la concurrence, comme les mises à jour perdues et le write skew, ce que les niveaux d’isolation garantissent réellement dans PostgreSQL, MySQL, Oracle et SQL Server, et quand utiliser des verrous, des vérifications de version ou des transactions sérialisables. Réplication et partitionnement explique comment les bases de données copient et répartissent les données entre plusieurs machines, ce que le retard de réplication et le failover font à l’exactitude, et comment choisir une clé de sharding à partir des chiffres.

Dériver, mettre en cache et faire évoluer les données

La seconde moitié porte sur les données dérivées des systèmes de référence, et sur le changement dans le temps. CQRS et event sourcing sépare le modèle qui accepte les changements des modèles qui répondent aux requêtes, et montre comment stocker un historique d’événements plutôt que l’état courant permet l’audit et les requêtes temporelles, au prix d’une complexité bien réelle. Mise en cache couvre les patrons, les niveaux et les défaillances de la conservation de copies au plus près de l’endroit où elles sont nécessaires, du navigateur à la base de données, y compris les ruées sur le cache qui peuvent faire tomber un système quand une entrée très demandée expire.

Évolution des schémas part du constat que tout schéma, qu’il s’agisse de tables de base de données, de charges utiles d’API ou d’événements, changera pendant que le système fonctionne, et montre comment les règles de compatibilité et le patron expansion-contraction permettent ce changement sans interruption de service. Enfin, analytique et streaming passe de la conduite de l’activité à sa compréhension : entrepôts de données, data lakes et lakehouses, traitement de flux, et le data mesh comme manière d’organiser les données analytiques autour des domaines.

Comment les sections s’articulent

Les sections forment une chaîne. La propriété décide où chaque fait est écrit. Le choix de la base de données et ses garanties transactionnelles décident quelles règles peuvent être appliquées à moindre coût chez ce propriétaire. La réplication et le partitionnement décident comment les données du propriétaire survivent aux défaillances et grandissent au-delà d’une seule machine. Tout le reste du chapitre est une copie délibérée : modèles de lecture, caches, index de recherche, entrepôts de données et flux. Chaque copie est plus rapide ou plus pratique pour un certain usage, et chacune est périmée dans une certaine mesure. L’évolution des schémas permet au propriétaire et à toutes ses copies de changer sans se casser mutuellement.

Le chapitre suppose acquis le vocabulaire des systèmes distribués du chapitre 6, en particulier les modèles de cohérence, l’architecture pilotée par les événements et les sagas et le patron outbox. Il passe ensuite le relais au chapitre 8, qui protège ces données, et au chapitre 9, qui garde rapides et disponibles les systèmes qui les détiennent.

L’idée à retenir

Pour chaque donnée importante, vous devez pouvoir répondre à trois questions : qui est son seul rédacteur, où ses règles sont-elles appliquées, et à quel point chacune de ses copies peut-elle être périmée ? La plupart des problèmes de données des systèmes réels, comme des commandes dont l’état recule, des rapports en désaccord avec le grand livre, des doubles réservations ou des clients qui ne voient pas leurs propres modifications, viennent de ce qu’on n’a pas répondu délibérément à l’une de ces questions. Les techniques de ce chapitre sont des moyens d’y répondre correctement, et chacune d’elles est un compromis entre cohérence, disponibilité, performances, coût et effort d’exploitation du système.

Les 8 sections

7.1 · Intermédiaire · 24 minPropriété des donnéesQui peut modifier chaque donnée, pourquoi une base de données partagée couple les services, comment résoudre une propriété conjointe, et comment lire des données dont vous n’êtes pas propriétaire, en tirer des rapports et établir des contrats à leur sujet.Lire →7.2 · Intermédiaire · 25 minChoisir une base de donnéesCe que chaque famille de bases de données fait bien et mal, du relationnel au vectoriel et au SQL distribué, et comment choisir selon la forme des données, les schémas d’accès, la cohérence, l’échelle, l’exploitation et les compétences de l’équipe.Lire →7.3 · Avancé · 28 minTransactionsCe que garantit réellement ACID, les anomalies que permettent les niveaux d’isolation, comment fonctionnent le MVCC et l’isolation par instantané, pourquoi les noms des niveaux sont trompeurs, et quand utiliser le verrouillage, les vérifications de version ou les transactions sérialisables.Lire →7.4 · Avancé · 30 minRéplication et partitionnementComment les bases de données copient les données pour la disponibilité et le passage à l’échelle des lectures, ce que le retard de réplication et le failover font à l’exactitude, et comment le partitionnement par plage ou par hachage, le hachage cohérent et les index secondaires façonnent une conception partitionnée (sharding).Lire →7.5 · Avancé · 26 minCQRS et event sourcingSéparer le modèle qui modifie les données des modèles qui les lisent, stocker l’état comme une séquence d’événements en ajout seul, et les coûts réels : cohérence à terme, versionnage des événements et données à caractère personnel.Lire →7.6 · Intermédiaire · 24 minMise en cachePourquoi les caches accélèrent les systèmes et ce qu’ils coûtent : cache-aside, read-through, write-through, write-behind et refresh-ahead, TTL et invalidation, ruées sur le cache, niveaux de cache, en-têtes HTTP et éviction.Lire →7.7 · Intermédiaire · 25 minÉvolution des schémasModifier les schémas de bases de données, d’API et d’événements pendant que le système continue de fonctionner : rétrocompatibilité, compatibilité future et compatibilité complète, expansion-contraction, outils de migration, backfills de grande ampleur et registres de schémas pour Avro et Protocol Buffers.Lire →7.8 · Avancé · 27 minAnalytique et streamingComment s’architecturent les données analytiques : OLTP et OLAP, entrepôts de données et schémas en étoile, ETL et ELT, lacs de données et lakehouses, traitement de flux avec temps de l’événement et filigranes (watermarks), Lambda et Kappa, et data mesh.Lire →

Test du chapitre

Vérifiez votre compréhension du chapitre 7

Facultatif : 20 questions à choix multiples et 2 courtes réponses rédigées, tirées à chaque fois d’une banque de 72 questions. Note de réussite : 80 %. Réussir tous les tests de chapitre, puis l’évaluation finale, donne droit au Certificat de fin de formation Be Wise.

Passer le test du chapitre 7 dans l’app

Lectures complémentaires