Concepts de system design
199 concepts expliqués simplement, chacun relié aux exercices qui l'entraînent.
Fondamentaux
- Modèle client-serveur Un client envoie une requête sur le réseau et un serveur renvoie une réponse. Tout système web, aussi grand soit-il, répète cet échange des millions de fois.
- Ordres de grandeur de latence Lire la mémoire prend environ 100 ns, une lecture SSD environ 100 µs, un aller-retour dans le même datacenter 0,5 ms et à travers un continent 50 à 150 ms. Ces ordres de grandeur décident où les données doivent vivre.
- Estimation sur un coin de table Transforme les utilisateurs en requêtes par seconde, stockage et bande passante avant de dessiner : 10 millions d'utilisateurs quotidiens qui font 20 requêtes donnent environ 2 300 requêtes par seconde en moyenne, et plusieurs fois plus au pic.
- Latence et débit La latence est la durée d'une requête ; le débit est le nombre de requêtes traitées par seconde. Ajouter des serveurs augmente le débit, mais la latence ne baisse qu'en faisant moins de travail ou en se rapprochant de l'utilisateur.
- La disponibilité et les « nines » 99,9 % de disponibilité autorise 8,8 heures d'arrêt par an, 99,99 % seulement 53 minutes. Des composants en série multiplient leur disponibilité : une chaîne de trois services à 99,9 % n'est disponible qu'à environ 99,7 %.
- Loi de Little Le nombre de requêtes dans un système égale le débit d'arrivée multiplié par le temps passé : 1 000 requêtes par seconde à 200 ms font 200 requêtes en cours. Elle dimensionne pools de threads, pools de connexions et files.
- Files d'attente et taux d'occupation Quand un serveur approche de sa pleine occupation, l'attente explose : à 50 % de charge, une requête attend à peu près sa durée de traitement, à 90 % environ dix fois plus. Garde de la marge plutôt que de tourner à 95 %.
- Latence de queue Le p99 est le temps sous lequel 99 % des requêtes se terminent. Quand une page appelle de nombreux services, elle tombe presque toujours sur un appel lent : c'est la queue, pas la moyenne, qui fait l'expérience utilisateur.
Scalabilité
- Scaling vertical Rendre une machine plus grosse : plus de vCPU, plus de mémoire. C'est simple et ne demande aucun changement de code, mais il y a un plafond, le coût unitaire grimpe en haut de gamme et le point de défaillance unique demeure.
- Scaling horizontal Ajouter des machines derrière un load balancer. La capacité croît presque linéairement et une panne n'en retire qu'une fraction, mais l'application doit être sans état ou partager son état ailleurs.
- Services sans état Un serveur sans état ne garde aucune donnée de session entre deux requêtes : n'importe quelle instance peut répondre à n'importe quel utilisateur. Les sessions partent dans un cache partagé ou un jeton signé, ce qui rend possible le scaling horizontal et l'auto-scaling.
- Répartition de charge Un load balancer répartit les requêtes entre serveurs et retire ceux qui sont malades. Le round robin est simple, moins-de-connexions gère mieux les requêtes inégales, et le hachage garde un client sur le même serveur au prix de points chauds.
- Sessions sticky Envoyer un utilisateur toujours vers le même serveur permet de garder la session en mémoire. Cela casse la répartition équitable et perd les sessions quand ce serveur meurt : préfère des services sans état.
- Auto-scaling Ajouter et retirer automatiquement des instances selon une métrique comme le CPU. Une nouvelle instance met des minutes à devenir utile : l'auto-scaling suit bien les tendances progressives mais n'absorbe pas seul un pic instantané.
- Élasticité La capacité à ajuster les ressources à la demande dans les deux sens et à ne payer que ce qui est utilisé. C'est le principal argument économique du cloud, et cela ne fonctionne qu'avec des composants sans état et rapides à démarrer.
Réseau et protocoles
- Couche 4 et couche 7 Les équipements de couche 4 routent les paquets TCP ou UDP selon l'adresse et le port, très vite et sans connaître le protocole. Ceux de couche 7 lisent le HTTP : ils peuvent router selon le chemin, terminer le TLS et lire les en-têtes, pour un coût un peu plus élevé.
- DNS Le DNS associe des noms à des adresses IP via une hiérarchie de serveurs, avec des réponses mises en cache pendant leur TTL. À cause du cache, un changement DNS ou un basculement par DNS ne prend effet qu'à l'expiration des caches.
- Routage géographique Envoyer chaque utilisateur vers la région la plus proche, par géolocalisation DNS, mesure de latence ou anycast. Cela réduit l'aller-retour et peut garder les données dans la juridiction de l'utilisateur.
- Anycast La même adresse IP est annoncée depuis de nombreux endroits et Internet route chaque utilisateur vers le plus proche. Les CDN et load balancers globaux s'en servent pour basculer sans attendre les caches DNS.
- Polling, long polling, SSE et WebSockets Le polling demande sans cesse, le long polling garde la requête ouverte jusqu'à une nouveauté, les Server-Sent Events diffusent des mises à jour dans un sens, et les WebSockets maintiennent une connexion bidirectionnelle. Un chat temps réel exige des connexions persistantes, qui ont un état à scaler.
- REST, gRPC et GraphQL REST est simple et se met bien en cache sur HTTP ; gRPC utilise Protocol Buffers en binaire sur HTTP/2 pour des appels rapides entre services ; GraphQL laisse le client demander exactement les champs voulus en un seul aller-retour.
- Pagination et versionnement d'API La pagination par curseur reste rapide et stable sur de grandes tables, contrairement aux offsets. Versionne explicitement les API et garde les anciennes versions assez longtemps pour laisser les clients migrer.
- Versions HTTP et TLS HTTP/2 multiplexe les requêtes sur une connexion et HTTP/3 passe par QUIC pour éviter le blocage en tête de file. TLS 1.3 ne demande qu'un aller-retour pour s'établir, et le terminer au load balancer soulage les serveurs.
- Proxys directs et inverses Un proxy direct agit pour les clients, par exemple pour filtrer le trafic sortant ; un proxy inverse se place devant les serveurs pour répartir la charge, mettre en cache et terminer le TLS.
- TCP et UDP TCP garantit une livraison fiable et ordonnée avec poignées de main et retransmissions ; UDP envoie des paquets sans garantie et avec moins de surcoût, ce qui convient à la vidéo, aux jeux et au DNS.
- Formats de sérialisation Le JSON est lisible et universel ; Protocol Buffers et Avro sont compacts, plus rapides à décoder et ont des schémas qui supportent l'évolution. Une compression comme gzip ou zstd réduit la bande passante pour un faible coût CPU.
- Edge computing Exécuter de la logique dans des points de présence proches des utilisateurs supprime l'aller-retour vers une région centrale pour les redirections, la personnalisation ou l'authentification. Tout ce qui a besoin des données centrales paie toujours ce trajet.
- Connectivité privée Les endpoints privés, le peering et les liaisons dédiées gardent le trafic entre ton réseau et les services cloud ou partenaires hors de l'Internet public, ce qui réduit à la fois la surface d'attaque et les coûts de transfert.
Cache
- Réseau de diffusion de contenu (CDN) Un CDN met en cache le contenu statique dans des centaines d'endroits proches des utilisateurs. Il réduit la latence de centaines à quelques dizaines de millisecondes, absorbe les pics et coûte souvent moins cher au gigaoctet que tes propres serveurs.
- Mise en cache Garder le résultat d'une opération coûteuse près de là où on en a besoin pour que la requête suivante soit bon marché. Il y a des caches à chaque couche : navigateur, CDN, application, base. Tout cache échange de la fraîcheur contre de la vitesse.
- Cache-aside L'application lit d'abord le cache et, en cas de miss, lit la base puis remplit le cache. C'est le patron le plus courant : le cache ne contient que ce qui est demandé, et sa panne dégrade en lectures plus lentes plutôt qu'en erreurs.
- Write-through Chaque écriture va dans le cache et dans la base en même temps : le cache est toujours frais. Les écritures sont plus lentes, et les données écrites mais jamais lues occupent quand même la mémoire.
- Write-behind Les écritures vont dans le cache et sont envoyées plus tard à la base par lots. C'est très rapide, mais tout ce qui n'est pas encore écrit est perdu si le nœud de cache tombe : cela convient aux compteurs, pas aux paiements.
- Politiques d'éviction Quand la mémoire est pleine, le cache doit retirer quelque chose. LRU retire la clé la moins récemment utilisée, LFU la moins fréquemment utilisée, qui protège mieux les éléments populaires. Sans éviction, ce sont les écritures qui échouent.
- Durée de vie (TTL) Un TTL fait expirer une donnée en cache après un délai. Un TTL court garde les données fraîches mais baisse le taux de hit ; un TTL long fait l'inverse. Choisis selon le type de donnée, pas une seule valeur pour tout.
- Invalidation de cache Retirer ou mettre à jour les copies en cache quand la source change est réputé difficile : les copies vivent à plusieurs endroits et les mises à jour entrent en concurrence avec les lectures. Les réponses courantes : TTL courts, suppression à l'écriture et clés versionnées.
- Ruée sur le cache Quand une clé populaire expire ou que le cache redémarre, des milliers de requêtes ratent au même instant et frappent la base ensemble. La fusion des requêtes, le rafraîchissement anticipé et des TTL décalés l'évitent.
Données et stockage
- Clés et partitions chaudes Quand une clé, comme le profil d'une célébrité, reçoit une grosse part du trafic, la partition qui la contient sature pendant que les autres sont au repos. Réplique les clés chaudes, ajoute un suffixe aléatoire ou mets-les en cache près de l'application.
- Bases relationnelles Les données vivent dans des tables liées par des clés et s'interrogent en SQL, jointures comprises. Des garanties fortes et un schéma rigide en font le choix par défaut pour les données métier : commandes, comptes, paiements.
- Transactions ACID Atomicité, Cohérence, Isolation, Durabilité : une transaction se fait entièrement ou pas du tout, laisse les données valides, ne voit pas le travail inachevé des autres et survit à un crash une fois validée.
- BASE Basically Available, Soft state, Eventually consistent : la philosophie de nombreux systèmes NoSQL qui privilégient disponibilité et échelle plutôt que cohérence immédiate.
- Niveaux d'isolation Read committed évite les lectures sales, repeatable read empêche aussi les valeurs de changer en cours de route, et sérialisable fait comme si les transactions s'exécutaient une à une. Plus le niveau est fort, moins il y a d'anomalies, mais le débit baisse à cause des verrous et des annulations.
- Index Un index est une structure triée, le plus souvent un B-tree, qui trouve des lignes sans parcourir la table. Il transforme une requête de plusieurs secondes en une requête d'une milliseconde, mais chaque index ralentit les écritures et occupe du stockage.
- B-trees Des arbres équilibrés à nœuds larges qui gardent les données triées sur disque, avec des recherches logarithmiques et des parcours de plages. Ils sont le moteur de stockage de la plupart des bases relationnelles et favorisent la lecture.
- Arbres LSM Les arbres LSM accumulent les écritures en mémoire puis les écrivent en fichiers triés fusionnés en arrière-plan. Les écritures sont très rapides ; une lecture peut consulter plusieurs fichiers, aidée par des filtres de Bloom.
- Journal d'écriture anticipée (WAL) Chaque modification est ajoutée à un journal avant d'être appliquée : après un crash, on récupère en le rejouant. Ce même journal alimente la réplication et la capture de changements.
- Contrôle de concurrence multiversion (MVCC) La base garde plusieurs versions d'une ligne pour que les lecteurs ne bloquent jamais les écrivains : chaque transaction voit un instantané cohérent. Les vieilles versions doivent être nettoyées, c'est le rôle du vacuum dans PostgreSQL.
- Normalisation Stocker chaque fait une seule fois et le relier par des clés, ce qui évite les copies incohérentes. Les lectures demandent alors des jointures, c'est pourquoi les systèmes très orientés lecture dénormalisent parfois volontairement.
- Dénormalisation Dupliquer des données pour qu'une lecture se fasse en un accès au lieu de plusieurs jointures. Les lectures sont plus rapides, au prix de plus de stockage et de copies à garder synchronisées.
- Pool de connexions Ouvrir une connexion à la base coûte cher et chacune consomme de la mémoire serveur. Un pool comme PgBouncer partage quelques connexions entre de nombreux threads applicatifs : ajouter des serveurs n'épuise plus la base.
- Réplication Garder des copies des données sur plusieurs machines pour la disponibilité et la capacité de lecture. Leader-follower envoie toutes les écritures à un nœud, multi-leader accepte des écritures à plusieurs endroits, et sans leader laisse n'importe quel réplica les accepter.
- Réplicas en lecture Des followers qui reçoivent les changements du leader et servent les lectures. Ils absorbent à bon compte les charges très orientées lecture, mais le retard de réplication fait qu'un utilisateur peut ne pas voir sa propre écriture récente, sauf si ces lectures vont au leader.
- Réplication synchrone et asynchrone La réplication synchrone attend les réplicas avant de confirmer une écriture : aucune perte au basculement, mais plus de latence. L'asynchrone confirme tout de suite : plus rapide, mais les dernières écritures peuvent être perdues si le leader meurt.
- Réplication sans leader Les clients écrivent et lisent directement sur plusieurs réplicas, comme dans Dynamo et Cassandra. Grâce au read repair et au hinted handoff, les réplicas convergent ; les quorums décident du niveau de cohérence de chaque opération.
- Stratégies de partitionnement Le partitionnement par plages garde les clés voisines ensemble pour les parcours mais crée des points chauds sur les clés récentes ; le partitionnement par hachage répartit la charge mais perd l'ordre ; l'annuaire est flexible mais ajoute une recherche.
- Hachage cohérent Clés et nœuds sont placés sur un anneau, et chaque clé appartient au nœud suivant dans le sens horaire. Ajouter ou retirer un nœud ne déplace qu'environ 1/N des clés au lieu de presque toutes ; les nœuds virtuels équilibrent la charge.
- Rééquilibrage Déplacer des données quand on ajoute ou retire des nœuds. Cela consomme réseau et disque pendant que le système sert le trafic : il faut le brider, et il coûte bien moins cher avec le hachage cohérent ou un nombre fixe de partitions.
- Familles NoSQL Les bases clé-valeur, documentaires, à colonnes larges et de graphe abandonnent chacune certaines fonctions relationnelles pour gagner en échelle ou en souplesse. Choisis selon les accès : comment les données seront-elles lues et écrites, et à quel volume ?
- Persistance polyglotte Range chaque type de données dans la base dont il a besoin des garanties : du SQL fortement cohérent pour l'argent, un stockage wide-column pour les événements à gros volume, un moteur de recherche pour le texte. Une seule base pour tout impose les garanties les plus chères, et leur coût, à toutes les données.
- Bases clé-valeur Le modèle le plus simple : lire et écrire une valeur par sa clé. Extrêmement rapide et facile à partitionner, mais on ne peut interroger que par clé : les accès doivent être connus d'avance.
- Bases documentaires Chaque enregistrement est un document de type JSON avec sa propre structure, interrogé par champs et index secondaires. Idéal quand les données sont naturellement hiérarchiques ; malcommode pour de nombreuses relations plusieurs-à-plusieurs.
- Bases de graphe Nœuds et arêtes sont des citoyens de première classe : parcourir des relations sur plusieurs niveaux reste rapide. Utilisées pour les réseaux sociaux, la recommandation et la détection de fraude.
- Données de séries temporelles Des mesures indexées par le temps, écrites en énormes volumes et lues comme agrégats sur des plages. Les moteurs spécialisés les compressent fortement et expirent automatiquement les anciennes données.
- Sous-échantillonnage Remplacer les points anciens à haute résolution par des agrégats plus grossiers, comme des moyennes par minute après une semaine, pour maîtriser le stockage et la durée des requêtes.
- Stockage objet Les fichiers sont stockés comme des objets avec une clé et des métadonnées dans un espace plat, servis en HTTP. C'est la bonne place pour les images, vidéos, sauvegardes et fichiers de data lake, pas pour des données modifiées sur place.
- Stocker les fichiers hors de la base Mets le fichier dans le stockage objet et ne garde que sa clé et ses métadonnées en base. Une base coûte cher au gigaoctet et se sauvegarde lentement quand elle contient de gros binaires.
- Durabilité La garantie qu'une donnée confirmée n'est pas perdue. Elle vient de l'écriture sur disque, de la réplication entre machines et zones, et des sauvegardes ; onze neuf de durabilité signifient perdre un objet sur cent milliards par an.
- Codes d'effacement Les données sont découpées en fragments plus des fragments de parité : elles survivent à la perte de plusieurs disques en occupant bien moins de place que des copies complètes. Les stockages objet s'en servent pour une durabilité extrême à bas coût.
- Index inversé Une table qui associe chaque mot aux documents qui le contiennent. C'est ce qui permet à un moteur de recherche de trouver en quelques millisecondes tous les documents contenant plusieurs mots.
- Recherche plein texte Rechercher par mots avec racinisation, tolérance aux fautes et classement par pertinence. Les requêtes SQL LIKE n'y arrivent pas à grande échelle ; un moteur de recherche synchronisé depuis la base principale, si.
- OLTP et OLAP L'OLTP sert de nombreuses petites transactions utilisateurs en millisecondes ; l'OLAP exécute quelques énormes requêtes analytiques sur l'historique. Faire de l'analytique sur la base de production ralentit les utilisateurs : on sépare donc les deux.
- Stockage en colonnes Stocker chaque colonne ensemble rend rapide le parcours d'une colonne sur des milliards de lignes et se compresse très bien, d'où son usage dans les entrepôts. Récupérer une ligne complète est plus lent.
- ETL et ELT Extraire les données des sources, les transformer et les charger dans un entrepôt, ou charger d'abord puis transformer dans l'entrepôt. Ces pipelines tournent par lots ou en continu, hors du chemin des requêtes utilisateurs.
- Pipelines de données Des chaînes de traitements qui déplacent et remodèlent les données entre systèmes. Ils exigent des étapes idempotentes, une surveillance de la fraîcheur et un moyen de recharger l'historique.
- Data lake Un stockage de données brutes en formats ouverts sur du stockage objet, assez bon marché pour tout garder. Les formats de table y ajoutent transactions et évolution de schéma.
- Schéma à la lecture Les données sont stockées telles qu'elles arrivent et un schéma est appliqué à la lecture. Souple pour l'exploration, mais les erreurs apparaissent tard et la qualité dépend de la discipline.
- Traitement par lots Traiter de gros jeux de données bornés d'un coup, par exemple chaque nuit, avec des frameworks comme Spark ou MapReduce. Débit élevé et reprise simple, mais les résultats datent de plusieurs heures.
- Capture des changements (CDC) Diffuser chaque insertion, mise à jour et suppression depuis le journal de la base vers d'autres systèmes. Cela garde caches, index de recherche et entrepôts synchronisés sans doubles écritures dans l'application.
- Région d'origine et transfert des écritures Chaque enregistrement a une région d'origine qui détient ses écritures, souvent pour des raisons légales ou de cohérence. Les autres régions servent les lectures depuis des copies locales et transmettent les écritures à la région d'origine de façon asynchrone, en échangeant quelques secondes de fraîcheur contre une latence locale.
- Write concern et accusé de réception Combien de réplicas doivent confirmer une écriture avant d'annoncer le succès au client. Attendre une majorité survit à un basculement ; attendre le seul primaire est plus rapide mais peut perdre des écritures confirmées.
- Recherche vectorielle Textes, images et produits sont transformés en embeddings, et les éléments similaires sont ceux dont les vecteurs sont proches. Les index de plus proches voisins approximatifs comme HNSW rendent cela rapide à grande échelle, avec une petite perte de rappel.
- Systèmes de fichiers distribués et réseau HDFS répartit de gros fichiers sur de nombreuses machines pour le traitement par lots ; les services de type NFS permettent à plusieurs serveurs de monter les mêmes fichiers. Les deux sont plus lents qu'un disque local, et le stockage objet est souvent un meilleur choix par défaut.
Cohérence et consensus
- Théorème CAP Quand une partition réseau sépare des nœuds, un système distribué doit choisir entre cohérence (refuser les requêtes qu'il ne peut pas servir correctement) et disponibilité (répondre, éventuellement avec une donnée périmée). Les partitions sont inévitables : le vrai choix, c'est C ou A pendant l'une d'elles.
- PACELC Prolonge CAP : en cas de Partition, choisir Disponibilité ou Cohérence ; sinon (Else), en fonctionnement normal, choisir Latence ou Cohérence. Attendre l'accord de plus de réplicas est toujours plus lent, même quand rien n'est en panne.
- Cohérence forte Chaque lecture renvoie la dernière écriture confirmée, comme s'il n'existait qu'une copie. Cela exige une coordination entre réplicas, payée en latence et en disponibilité pendant les pannes.
- Linéarisabilité La garantie la plus stricte sur un objet : dès qu'une écriture est terminée, toute lecture ultérieure, où qu'elle soit, la voit, dans l'ordre réel. Indispensable pour les verrous, l'élection de leader et les contraintes d'unicité.
- Cohérence éventuelle Si les écritures s'arrêtent, tous les réplicas finissent par converger vers la même valeur, mais entre-temps les lectures peuvent être périmées. Acceptable pour des likes ou des compteurs de vues, dangereux pour un solde bancaire.
- Lire ses propres écritures Un utilisateur voit toujours ses propres modifications, même si les autres les voient plus tard. On l'obtient en lisant sur le leader peu de temps après une écriture, ou en attachant l'utilisateur à un réplica à jour.
- Lectures monotones Un utilisateur ne voit jamais les données revenir en arrière, ce qui arrive quand des lectures successives tombent sur des réplicas au retard différent. Attacher une session à un réplica l'évite.
- Cohérence causale Les opérations qui dépendent les unes des autres sont vues dans le même ordre par tous : personne ne voit une réponse avant le message auquel elle répond. Plus fort qu'éventuel, moins coûteux que linéarisable.
- Quorums Avec N réplicas, écrire sur W et lire sur R réplicas garantit qu'une lecture voit la dernière écriture dès que R + W > N. Avec N = 3, des lectures et écritures QUORUM (2 + 2 > 3) sont cohérentes ; ONE et ONE ne le sont pas.
- Cohérence réglable Certaines bases laissent choisir le niveau de cohérence à chaque requête. Utilise des niveaux forts pour l'argent et les stocks, faibles pour les fils d'actualité et l'analytique, en acceptant consciemment l'écart de latence.
- Consensus Faire s'accorder plusieurs machines sur une valeur malgré les pannes. Il faut une majorité : un cluster de 2f + 1 nœuds tolère f pannes, et c'est ce qui rend sûres l'élection de leader et les bases SQL distribuées.
- Raft et Paxos Les deux algorithmes de consensus classiques. Raft élit un leader qui réplique un journal vers les followers et valide une entrée dès qu'une majorité l'a stockée ; il est utilisé par etcd, Consul et CockroachDB.
- Élection de leader Choisir un nœud pour coordonner le travail, comme accepter les écritures ou lancer une tâche planifiée. Elle repose sur le consensus et des baux, afin qu'un nouveau leader soit choisi quand l'ancien ne répond plus.
- Split brain Deux nœuds se croient tous deux leaders, en général après une partition réseau, et acceptent des écritures contradictoires. Les quorums majoritaires et les jetons de fencing l'empêchent.
- Jetons de fencing Chaque nouveau détenteur d'un verrou reçoit un numéro plus élevé, et le stockage rejette les écritures portant un numéro plus ancien. Un ancien leader mis en pause qui se réveille ne peut pas corrompre les données.
- Verrous distribués Exclusion mutuelle entre machines, construite sur un stockage à consensus avec des baux. Un verrou expire si son détenteur plante : il faut donc le combiner à des jetons de fencing pour être sûr.
- Horloges vectorielles Chaque réplica garde un compteur par nœud, ce qui permet de savoir si deux versions sont ordonnées ou concurrentes. Des versions concurrentes sont des conflits à fusionner.
- Dérive d'horloge Les horloges des machines dérivent de quelques millisecondes ou plus : on ne peut pas se fier aux horodatages de serveurs différents pour ordonner les événements. Le « dernier écrit gagne » sur l'heure murale perd des données en silence.
- CRDT Des types de données répliqués sans conflit, comme des compteurs et des ensembles, qui fusionnent automatiquement et de façon déterministe les modifications concurrentes. Ils alimentent l'édition collaborative et la réplication multi-leader.
- Protocoles de gossip Les nœuds échangent périodiquement leur état avec quelques pairs au hasard : l'information atteint tout le cluster en un nombre logarithmique de tours. Utilisé pour l'appartenance au cluster et la détection de pannes.
- Arbres de Merkle Un arbre de hachages où chaque parent hache ses enfants. Deux réplicas comparent leur racine et ne descendent que dans les branches qui diffèrent, ce qui rend la réparation anti-entropie peu coûteuse.
Algorithmes et structures de données
- Filtres de Bloom Un tableau de bits compact qui répond « absent à coup sûr » ou « peut-être présent ». Les bases s'en servent pour éviter de lire les fichiers qui ne peuvent pas contenir une clé.
- HyperLogLog et count-min sketch Des structures probabilistes qui comptent les visiteurs distincts ou estiment les éléments les plus fréquents en quelques kilo-octets, avec environ 1 % d'erreur. Un comptage exact à cette échelle demanderait des gigaoctets.
- Indexation géospatiale Les geohashes, quadtrees et cellules S2 transforment une position en clé, de sorte que des points proches partagent un préfixe. C'est ainsi que les applications de VTC et de livraison trouvent vite les chauffeurs proches.
- Génération d'identifiants uniques L'auto-incrément ne fonctionne pas entre shards. Les identifiants Snowflake, UUIDv7 et ULID sont générés indépendamment sur chaque serveur, restent uniques et se trient à peu près par date de création.
Messagerie et streaming
- Files de messages Une file découple le producteur du consommateur : la requête est acceptée rapidement et le travail lent se fait plus tard, au rythme que les workers peuvent tenir. Elle lisse les pics et isole les pannes.
- Traitement asynchrone Répondre à l'utilisateur dès que le travail est enregistré en sécurité, puis le traiter en arrière-plan. La latence baisse et la capacité se dimensionne sur la moyenne plutôt que le pic, au prix d'états « en cours » à afficher.
- Garanties de livraison Au-plus-une-fois peut perdre des messages, au-moins-une-fois peut les dupliquer, et le traitement exactement-une-fois s'obtient en combinant livraison au-moins-une-fois et traitement idempotent ou transactions.
- Traitement exactement-une-fois L'effet de chaque message se produit une seule fois même s'il est livré deux fois. On y arrive par des écritures idempotentes, des clés de déduplication ou des offsets transactionnels, jamais en faisant confiance au réseau.
- Dead-letter queues Les messages qui échouent un certain nombre de fois sont mis de côté pour inspection : un seul mauvais message ne bloque plus la file et ne brûle plus la capacité des workers.
- Messages empoisonnés Un message qui fait planter son consommateur à chaque fois, par exemple à cause de données malformées. Sans limite de tentatives, il est relivré sans fin.
- Publication-abonnement Les producteurs publient des événements dans un topic sans savoir qui les consomme, et chaque abonné reçoit sa propre copie. Les nouvelles fonctionnalités s'abonnent sans toucher au producteur.
- Fan-out à l'écriture et à la lecture Un fil social peut se construire en poussant chaque publication dans le fil de chaque abonné à l'écriture, ce qui rend la lecture bon marché, ou en rassemblant les publications à la lecture, ce qui convient aux comptes à millions d'abonnés. Les grands systèmes mélangent les deux.
- Streaming d'événements Un journal d'événements en ajout seul conservé des jours ou pour toujours, que de nombreux consommateurs lisent à leur rythme et peuvent rejouer. Il devient la colonne vertébrale qui alimente caches, recherche, analytique et autres services.
- Garanties d'ordre Un ordre global ne passe pas à l'échelle ; la plupart des systèmes garantissent l'ordre par clé en envoyant tous les événements d'une clé dans la même partition. Choisis la clé pour que les événements qui doivent rester ordonnés la partagent.
- Groupes de consommateurs Les consommateurs d'un groupe se partagent les partitions d'un topic, chaque partition étant lue par un seul consommateur. En ajouter au-delà du nombre de partitions les laisse inactifs.
- Traitement de flux Calculer des résultats en continu à l'arrivée des événements : comptages en direct, détection de fraude, tableaux de bord temps réel. L'état et les checkpoints permettent de reprendre sans perdre sa place.
- Fenêtrage Regrouper un flux sans fin en fenêtres fixes, glissantes ou de session pour que les agrégats aient un début et une fin. Les événements en retard demandent une règle : attendre grâce aux watermarks ou corriger ensuite.
Fiabilité
- Point de défaillance unique Tout composant dont la panne arrête tout le système. Trouve-les en demandant, pour chaque boîte, ce qui se passe si elle disparaît ; supprime-les par la redondance entre instances, zones ou régions.
- Capacité N+1 Dimensionne chaque étage pour qu'il porte encore le pic après la perte de sa plus grosse unité, qu'il s'agisse d'une instance, d'une zone ou d'une région entière. Deux régions dimensionnées chacune pour la moitié du trafic ne sont pas redondantes : quand l'une tombe, l'autre s'effondre sous le double de sa charge.
- Health checks Des sondes périodiques indiquent au load balancer quelles instances peuvent recevoir du trafic. Un intervalle court détecte plus vite les pannes mais ajoute de la charge ; un contrôle profond qui teste la base peut retirer tous les serveurs d'un coup si la base hoquette.
- Limitation de débit Plafonner les requêtes qu'un client peut envoyer par seconde. Le token bucket autorise de courtes rafales, le leaky bucket lisse la sortie, la fenêtre fixe est simple mais laisse passer des doubles rafales aux frontières, et la fenêtre glissante corrige cela pour un léger coût mémoire.
- Contre-pression (backpressure) Quand un composant ne suit plus, il signale à l'amont de ralentir au lieu de tout empiler en silence. Files bornées, réponses 429 et consommateurs en mode pull sont des formes de contre-pression.
- Effet troupeau De nombreux clients se réveillent et réessaient exactement au même moment, par exemple après une panne, et refont tomber le service qui se relevait. Le jitter, le backoff et la limitation de débit les étalent.
- Basculement (failover) Déplacer automatiquement le trafic ou le rôle de leader vers un secours quand le primaire tombe. Il faut détecter la panne de façon fiable, éviter deux leaders en même temps et accepter que quelques secondes de requêtes échouent.
- Idempotence Une opération est idempotente si la faire deux fois a le même effet que la faire une fois. Une clé d'idempotence sur une demande de paiement permet de réessayer sans débiter le client deux fois.
- Circuit breaker Après trop d'échecs, cesser d'appeler une dépendance pendant un moment et échouer vite ou renvoyer un repli, puis la sonder à nouveau. Cela évite l'empilement de threads sur des timeouts et laisse la dépendance récupérer.
- Timeouts Chaque appel réseau doit avoir une échéance, sinon une dépendance lente monopolise des threads indéfiniment. Fixe-la à partir du p99 de la dépendance, et vérifie que la somme des timeouts imbriqués tient dans la patience de l'utilisateur.
- Retries, backoff et jitter Réessayer masque les pannes passagères, mais des retries immédiats multiplient la charge sur un service en difficulté. Le backoff exponentiel espace les tentatives et le jitter aléatoire empêche les clients de réessayer en même temps.
- Pannes en cascade Un composant lent fait attendre ses appelants, qui épuisent leurs threads et ralentissent à leur tour leurs propres appelants, jusqu'à la panne générale. Timeouts, circuit breakers, cloisons et délestage la contiennent.
- Cloisons (bulkheads) Isoler les ressources, comme les pools de threads ou les instances, par dépendance ou par client, pour qu'une partie surchargée ne fasse pas couler les autres, comme les compartiments d'un navire.
- Dégradation gracieuse Quand une dépendance non essentielle tombe, continuer à servir l'essentiel en version réduite : masquer les recommandations, afficher des prix en cache. Un utilisateur remarque bien moins une page dégradée qu'une page d'erreur.
- Délestage Rejeter volontairement une partie du trafic en cas de surcharge, de préférence la moins importante, pour garder des réponses rapides pour le reste. Mieux vaut bien servir 80 % que mal servir 100 %.
- Auto-réparation La plateforme détecte les instances en panne et les remplace sans intervention humaine. Combinée à la redondance, une panne devient un non-événement plutôt qu'un incident.
- Architecture multi-régions Tourner dans plusieurs régions protège d'une panne régionale et rapproche les données des utilisateurs. La difficulté, ce sont les données : la réplication synchrone ajoute la latence inter-régions aux écritures, l'asynchrone risque de perdre les écritures récentes.
- Actif-actif et actif-passif L'actif-passif garde une région de secours qui prend le relais en cas de panne : plus simple, mais le secours est inactif et le basculement prend des minutes. L'actif-actif sert le trafic depuis toutes les régions à la fois : meilleure latence et basculement immédiat, mais il faut gérer les conflits d'écriture.
- Stabilité statique Un système est statiquement stable quand il continue de fonctionner avec ce qu'il a déjà pendant que quelque chose dont il dépend est en panne : une autre région, un plan de contrôle, un service de configuration. Chaque région fait tourner sa propre copie de chaque dépendance appelée au moment de la requête et est provisionnée à l'avance : rien n'a besoin de démarrer ni d'être joint pendant une panne.
- Stratégies de reprise après sinistre Du moins cher au plus rapide : sauvegarde et restauration, veilleuse (pilot light), secours tiède, multi-site actif-actif. Chaque niveau réduit le temps de reprise et la perte de données, et augmente le coût.
- RPO et RTO Le RPO (Recovery Point Objective) est la quantité de données que tu peux te permettre de perdre, le RTO (Recovery Time Objective) la durée d'arrêt acceptable. Un RPO de cinq minutes exclut les sauvegardes quotidiennes comme seule protection.
- Rayon d'impact La part des utilisateurs qu'une seule panne, un mauvais déploiement ou une migration peut toucher. Les cellules, le sharding, les bases par équipe et les déploiements progressifs la plafonnent : les incidents deviennent partiels au lieu d'être totaux.
- Heartbeats et détection de pannes Les nœuds envoient des signaux périodiques ; en manquer plusieurs fait présumer qu'un nœud est mort. Impossible de distinguer un nœud mort d'un nœud lent : les détecteurs arbitrent entre rapidité de détection et fausses alertes.
- Sauvegardes et tests de restauration La réplication copie les erreurs aussi fidèlement que les données : seules les sauvegardes protègent des suppressions, de la corruption et des rançongiciels. Garde des copies dans un autre compte ou une autre région, et répète les restaurations pour connaître le vrai temps de reprise.
- Dépendances tierces Les API externes apportent leur latence, leurs limites et leurs pannes dans ton système. Isole-les avec timeouts, circuit breakers et files, mets leurs réponses en cache quand c'est possible, et décide ce que fait ton produit quand elles tombent.
Patrons d'architecture
- API Gateway Un point d'entrée unique qui gère authentification, quotas, routage et transformation des requêtes pour de nombreux services. Il simplifie clients et services, mais devient une infrastructure critique qui doit elle-même tenir la charge.
- Backend for frontend (BFF) Une couche d'API dédiée à chaque type de client, comme mobile et web, taillée pour ses écrans. Elle évite les clients bavards et permet à chaque équipe de faire évoluer son API indépendamment.
- Architecture orientée événements Les services communiquent en émettant des faits survenus, comme CommandePassée, au lieu de s'appeler. Le couplage baisse et l'ajout de consommateurs est facile, mais les flux de bout en bout deviennent plus difficiles à suivre.
- Couplage faible Des composants qui se connaissent peu peuvent évoluer, scaler et tomber indépendamment. Les files, les événements et des API stables sont les principaux outils.
- Event sourcing Stocker la suite des événements qui ont modifié une entité plutôt que son état courant, et reconstruire l'état en les rejouant. On obtient un historique complet et le voyage dans le temps, mais l'évolution du schéma et les requêtes demandent du soin.
- CQRS Command Query Responsibility Segregation sépare le modèle d'écriture d'un ou plusieurs modèles de lecture optimisés pour les requêtes, synchronisés par événements. Les lectures scalent indépendamment, au prix d'une cohérence éventuelle.
- Architectures Lambda et Kappa Lambda fait tourner une couche batch pour l'exactitude à côté d'une couche temps réel pour la fraîcheur ; Kappa utilise un seul pipeline de streaming et rejoue le journal pour recalculer. Kappa est plus simple quand le traitement de flux est fiable.
- Patron saga Une longue transaction métier découpée en étapes locales, chacune avec une action de compensation si une étape suivante échoue, comme rembourser un paiement quand la livraison est impossible. Elle remplace les verrous distribués entre services.
- Validation en deux phases (2PC) Un coordinateur demande à chaque participant de se préparer, puis ordonne à tous de valider. C'est atomique entre systèmes mais bloquant si le coordinateur tombe, on l'évite donc entre services.
- Transactions distribuées Garder des données cohérentes entre plusieurs bases ou services. Les options vont de la validation en deux phases et du SQL à consensus aux sagas et au patron outbox, en arbitrant simplicité, latence et disponibilité.
- Patron outbox transactionnel Écrire le changement métier et l'événement à publier dans la même transaction, puis relayer l'événement vers le broker. On évite de perdre des événements ou d'en publier pour des changements annulés.
- Exécution durable Les moteurs de workflow persistent chaque étape d'un long processus pour qu'il reprenne après un crash, un timeout ou un déploiement, ce qui supprime beaucoup de code de retry et d'état écrit à la main.
- Serverless Tu déploies des fonctions que le fournisseur exécute, scale et facture à l'exécution. Aucun serveur à gérer et un coût quasi nul au repos, mais des démarrages à froid, des limites d'exécution et un prix à la requête élevé à fort volume.
- Démarrages à froid La première requête vers une nouvelle instance de fonction ou de conteneur paie le chargement du runtime et du code, d'environ 100 ms en Go à près d'une seconde en Java. La capacité provisionnée garde des instances chaudes.
- Conteneurs Une application empaquetée avec ses dépendances tourne de la même façon partout et démarre en quelques secondes. Les orchestrateurs comme Kubernetes placent les conteneurs, les redémarrent et les répartissent entre les zones.
- Monolithe et microservices Un monolithe est une seule unité déployable : simple à construire, tester et exploiter. Les microservices le découpent en services déployables indépendamment et confiés à des équipes, ce qui aide les grandes organisations mais ajoute des appels réseau, des données distribuées et un coût d'exploitation.
- Service mesh Des proxys sidecar à côté de chaque service gèrent retries, timeouts, TLS mutuel et télémétrie pour le trafic entre services : cette logique n'est plus réécrite dans chaque base de code.
- Découverte de services Les instances s'enregistrent et les clients consultent les adresses à jour, via DNS, un registre ou l'orchestrateur. Une liste d'IP statiques casse dès que l'auto-scaling remplace des instances.
- Architecture cellulaire Le système est répliqué en cellules indépendantes, chacune servant une partie des clients. Un mauvais déploiement ou une panne n'affecte qu'une cellule, ce qui limite le rayon d'impact.
- Multi-location (multi-tenancy) Un seul système sert de nombreux clients. Une base partagée coûte peu mais expose aux voisins bruyants et aux fuites de données ; une base par client isole bien mais multiplie l'exploitation.
- Migration par étranglement (strangler fig) Remplacer progressivement un système hérité en routant une fonctionnalité à la fois vers la nouvelle implémentation derrière une façade, jusqu'à pouvoir éteindre l'ancien, sans bascule brutale.
- Loi de Conway Les systèmes reflètent la structure de communication de l'organisation qui les construit. Conçois ensemble les frontières des équipes et celles des services.
- Architecture Decision Records (ADR) Un court document par décision importante : contexte, options étudiées, choix et conséquences. Les futurs ingénieurs comprennent le pourquoi, pas seulement le quoi, et les décisions peuvent être revues en connaissance de cause.
- Applications twelve-factor Des principes pour des services adaptés au cloud : configuration dans l'environnement, processus sans état, services externes vus comme des ressources attachées, logs en flux, démarrage rapide et arrêt propre.
- Servir des modèles de machine learning L'inférence dépend du GPU et chaque requête est lente : on planifie la capacité en requêtes par GPU. Le regroupement dynamique, le cache des réponses, des modèles plus petits et l'autoscaling sur la profondeur de file tiennent latence et coût.
- Systèmes de notification E-mails, SMS et notifications push sont envoyés de façon asynchrone depuis des files, avec un prestataire par canal, des retries, les préférences des utilisateurs et une déduplication pour que personne ne reçoive deux fois la même alerte.
Sécurité
- Défense en profondeur Empiler des couches de sécurité indépendantes, comme WAF, isolation réseau, authentification, chiffrement et moindre privilège, pour qu'une seule faille n'expose pas tout.
- OWASP Top 10 La liste de référence des vulnérabilités web les plus courantes : contrôle d'accès défaillant, injection, conception non sécurisée et autres. Un WAF aide, mais la plupart des corrections se font dans le code.
- Résidence des données et lois sur la vie privée Des lois comme la Loi 25 au Québec et le RGPD encadrent où les données personnelles peuvent être stockées et qui peut y accéder. L'architecture doit savoir quelle région détient les données de chaque utilisateur et permettre les demandes de suppression.
- Authentification Prouver qui est un utilisateur ou un service, par mot de passe, MFA, authentification unique ou certificat. Centralise-la dans un fournisseur d'identité plutôt que dans chaque service.
- OAuth 2.0 et OpenID Connect OAuth 2.0 permet à une application d'agir pour le compte d'un utilisateur avec des droits limités ; OpenID Connect y ajoute la connexion. Ils sont derrière « Se connecter avec Google » et les jetons d'accès aux API.
- JSON Web Tokens (JWT) Des jetons signés qui transportent des informations : tout service peut vérifier un utilisateur sans appeler le fournisseur d'identité. Garde-les à courte durée de vie, car un jeton signé se révoque difficilement.
- Chiffrement en transit et au repos Le TLS protège les données qui circulent sur le réseau ; le chiffrement des disques et des bases protège les données stockées. Les deux sont attendus par défaut aujourd'hui et presque gratuits dans les services managés.
- Chiffrement par enveloppe Les données sont chiffrées avec une clé de données, elle-même chiffrée par une clé maîtresse conservée dans un KMS. Faire tourner la clé maîtresse ne demande pas de rechiffrer toutes les données.
- Gestion des secrets Les identifiants vont dans un coffre dédié avec contrôle d'accès, audit et rotation, pas dans le code, les images ou de simples fichiers d'environnement.
- Moindre privilège Chaque utilisateur, service et machine ne reçoit que les droits dont il a besoin. Quand quelque chose est compromis, les dégâts restent limités.
- Segmentation réseau Séparer les couches publique, applicative et données en sous-réseaux avec des règles strictes entre eux. Un serveur web compromis ne doit pas pouvoir atteindre directement la base.
- URL présignées Le serveur signe une URL temporaire pour que le navigateur envoie ou télécharge un fichier directement depuis le stockage objet. Les gros fichiers ne transitent plus par tes serveurs applicatifs.
- Protection contre les DDoS Les attaques par déni de service distribué inondent un système de trafic venant de nombreuses machines. Les déluges volumétriques sont absorbés par le réseau mondial d'un fournisseur ; ceux de la couche applicative sont filtrés par limitation de débit, règles WAF et détection de bots.
- Accès zero trust Aucun emplacement réseau n'est digne de confiance par défaut : chaque accès à un serveur, une base ou un outil est authentifié, autorisé et journalisé, avec des identifiants éphémères plutôt que des clés permanentes.
Observabilité
- Observabilité Métriques, logs et traces réunis permettent de répondre à de nouvelles questions sur un système en marche sans livrer de nouveau code. On ne répare pas ce qu'on ne voit pas.
- Les quatre signaux dorés Latence, trafic, erreurs et saturation décrivent la santé de presque n'importe quel service. Alerte sur eux avant d'alerter sur le CPU ou la mémoire.
- SLI, SLO et SLA Un SLI est une mesure, comme la part des requêtes sous 300 ms ; un SLO est l'objectif fixé, comme 99,9 % par mois ; un SLA est la promesse contractuelle, avec pénalités. L'écart entre 100 % et le SLO est le budget d'erreurs.
- Logs structurés Des logs écrits en champs clé-valeur plutôt qu'en texte libre peuvent être filtrés et agrégés. Mets un identifiant de requête dans chaque ligne pour suivre une requête d'un service à l'autre.
Exploitation
- Feature flags Des interrupteurs de configuration qui activent ou désactivent des chemins de code à l'exécution, par utilisateur ou par pourcentage. Ils séparent le déploiement de la mise en production et offrent un arrêt d'urgence instantané.
- Déploiements canary et blue-green Le canary envoie une petite part du trafic vers la nouvelle version et surveille les erreurs avant d'aller plus loin ; le blue-green garde deux environnements complets et bascule le trafic d'un coup, avec retour arrière instantané.
- Gestion d'incident Détecter, atténuer d'abord, communiquer, puis corriger et apprendre. Un postmortem sans reproche et un runbook mis à jour transforment une panne en amélioration durable.
- MTTR et MTBF Le temps moyen de rétablissement et le temps moyen entre pannes. La disponibilité dépend des deux, et en pratique il est souvent bien moins cher de raccourcir le rétablissement que d'empêcher chaque panne.
- Chaos engineering Injecter volontairement des pannes, comme tuer des instances ou ajouter de la latence, pour vérifier que le système tient avant qu'un vrai incident le fasse à ta place. Ce simulateur est un laboratoire de chaos.
- Planification de capacité Prévoir la charge à partir de la croissance et de la saisonnalité, mesurer ce qu'une instance tient, puis garder assez de marge pour les pics et pour la perte d'une zone.
- Tests de charge Rejouer un trafic réaliste à volume croissant pour trouver le point de rupture avant les utilisateurs. Mesure la latence p99 et les erreurs, pas seulement le temps de réponse moyen.
- Optimisation des coûts cloud Bien dimensionner les instances, réserver la capacité constante, autoscaler le reste et surveiller les transferts de données, souvent surprenants. Le coût par requête est l'indicateur qui compte.
Aucun concept ne correspond à ces filtres.