English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

invité
1 / ?
retour aux leçons

Deux façons de transporter plus de charge

Bienvenue

Lorsqu'un service commence à plier sous la charge, un opérateur est confronté à un choix. Augmenter la boîte existante (plus de CPU, plus de RAM, disques plus rapides). Ou ajouter plus de boîtes qui effectuent le même travail.

La première voie s'appelle l'échelle verticale (augmenter). La seconde s'appelle l'échelle horizontale (agrandir).

Cette leçon enseigne pourquoi presque chaque architecture web moderne choisit l'horizontale et quelle propriété du charge travaille rend cette option viable. La réponse se cache dans un mot : l'état.

À la fin, vous comprendrez:

- Les courbes de coût de l'échelle verticale vs horizontale et où chacune convient

- Ce que 'étatique' et 'sans état' signifient en pratique, et pourquoi l'un d'entre eux se multiplie de manière économique

- Le calcul qui dimensionne un flotteau de répliques sous charge prévue et charge soudaine

- La règle de marge qui empêche un niveau de s'effondrer au-delà du genou de la file d'attente

- Où l'état doit vivre (il disparaît jamais) et comment le pousser hors des couches qui doivent s'agrandir

Pourquoi l'horizontale gagne au-delà d'un seuil

Échelle verticale : Une boîte plus grande

Avantages : simple. Aucunes modifications de code. Aucune coordination. Le même processus a maintenant plus de CPU.

Inconvénients : plafond. La VM la plus grande disponible commercialement a une capacité de RAM et de noyaux finis. Au-delà de cela, de l'argent ne rachète pas plus de marge. Les coûts augmentent de manière exponentielle au-delà du point de vente optimal d'un fournisseur. Une panne de cette seule machine met l'ensemble du service hors service.

Échelle horizontale : De nombreuses petites boîtes

Avantages : pas de plafond (jusqu'à votre volonté de payer pour et de coordonner les machines). La capacité augmente linéairement avec le nombre de répliques, de manière prévisible. Une panne d'une seule réplique supprime 1/N de capacité, et non 100%.

Inconvénients : nécessite que le charge travail supporte cela. Certains charges (une grande base de données unique, un service avec état jouant des sessions en direct) résistent à l'échelle horizontale. La coordination et la distribution de la charge deviennent des préoccupations opérationnelles.

Le crossover: tout service de production qui doit résister à l'échec d'une machine unique doit tourner sur au moins deux machines. Une fois que vous acceptez deux, vous avez déjà choisi l'échelle horizontale. Dès lors, la question n'est pas 'devrions-nous?' mais 'comment pouvons-nous ajouter le prochain réplica le moins cher possible?'

L'élément clé: un charge travail qui n'entretient pas d'état par requête sur la machine elle-même. Alors, n'importe quel réplica peut répondre à n'importe quelle requête, et ajouter un réplica ajoute la capacité sans coordination.

Échelle verticale contre échelle horizontale: courbe de coût et plafond

Une équipe exécute un service sur une seule VM avec 8 CPUs gérant 800 demandes par seconde à 60% de CPU. Ils prévoient que le trafic augmentera de 4 fois au cours des prochaines années. Ils débattent : louer une VM de 32 CPUs (vertical), ou exécuter quatre VMs identiques de 8 CPUs derrière un équilibreur de charge (horizontal). Quelle option recommandez-vous et nommez deux raisons qui vont au-delà de la capacité brute.

Étatful vs Étatless en pratique

L'état ne disparaît jamais, il se déplace simplement

Composant étatful: conserve des informations dont la perte modifierait le comportement. Une base de données qui conserve les comptes d'utilisateurs. Une cache qui conserve les jetons de session. Un travailleur qui maintient une connexion en streaming à long terme attachée à un utilisateur spécifique.

Composant étatless: ne conserve aucune information dont la perte serait importante. Une couche web qui lit une requête, interroge une base de données et écrit une réponse. Chaque requête se déroule indépendamment ; la couche ne se souvient de rien entre les requêtes.

Intuition clé: l'état ne disparaît jamais d'un système. Il se déplace vers une couche conçue pour le conserver (une base de données, un cluster Redis, un objet stocké). Les couches qui font face au trafic peuvent alors devenir étatless, et les couches étatless s'échelonnent horizontalement car n'importe quel réplica peut répondre à n'importe quelle requête.

Test pratique: si vous tuiez arbitrairement un processus dans cette couche et le redémarriez, une utilisation aurait-elle une mauvaise réponse ou une session perdue ? Si oui, il conserve de l'état. Si non, il ne le conserve pas.

Exemples

- Un processus web Python qui lit des requêtes, interroge Postgres et retourne du JSON : étatless. L'état vit dans Postgres.

- Un processus web Python qui conserve les paniers d'achat des utilisateurs dans la mémoire locale : étatful. La suppression du processus entraîne la perte des paniers.

- Un serveur WebSocket qui maintient des connexions ouvertes aux utilisateurs de chat : étatful au sens de la connexion. La suppression du processus coupe les connexions ; les clients doivent se reconnecter. Ces derniers peuvent souvent s'échelonner horizontalement avec soin (sessions collantes, hachage cohérent).

- Un cache Redis protégeant Postgres : l'état des contenus cache est persistant, mais acceptable si les manques de cache sont tolérables. Une panne d'un réplica entraîne une erreur de cache, pas une perte de données.

Concevoir pour l'échelle horizontale = déplacer l'état hors du niveau qui doit s'échelonner.

Auditer un niveau suspect

Une équipe gère une API de recommandation sur 6 VM de serveur en arrière-plan derrière un proxy inversé. L'application : lit un ID utilisateur dans la demande, récupère les activités récentes de l'utilisateur depuis Postgres, exécute un algorithme de notation, retourne une liste d'articles recommandés. Deux comportements non standards :

- L'application maintient un cache 'des activités récentes de l'utilisateur' en mémoire processeur, initialisé lors de la première demande pour un utilisateur, réutilisé lors des demandes ultérieures.

- L'application utilise les sessions collantes : une fois qu'un utilisateur atteint la machine n°3, toutes leurs demandes ultérieures sont dirigées vers la machine n°3 (le proxy est configuré pour la routage collant sur une cookie).

Identifiez quel de ces deux comportements rend le niveau étatique et expliquez ce qui se briserait si l'équipe tentait de passer de 6 VM à 12. Proposez ensuite une refonte qui permet à ce niveau de s'échelonner horizontalement sans perdre l'avantage du cache utilisateur.

La formule des réplicas

La formule de capacité la plus simple

Une fois qu'un niveau devient étatique, la taille devient une arithmétique. Vous avez besoin d'asseoir suffisamment de réplicas pour que le charge en état constant arrive et part à la même vitesse, avec un marge de sécurité pour les surcharges.

La formule :

réplicas = ⌈ (charge_max × facteur_surge) / capacité_par_réplica ⌉ + marge

Où :

- charge_max: demande maximale en requêtes/secondes que vous prévoyez en opération normale

- facteur_surge: un multiplicateur couvrant les hausses brèves au-dessus de la charge maximale (généralement 1,5x à 2x pour un trafic prévisible, 3x ou plus pour viral / imprévisible)

- capacité_par_réplica: requêtes/secondes qu'un réplica gère avec un délai acceptable et utilisation (généralement mesuré à 70% CPU, pas à saturation)

- marge: réplicas supplémentaires pour que quelques pannes de réplica ne collasent pas le niveau (généralement 1-2 réplicas pour de petites flottes, 10-20% pour les plus grandes)

Exemple de travail : un backend gère 100 req/s pour 70% de CPU par réplica. La charge maximale est de 600 req/s. Vous prévoyez des surges occasionnels de 2x. Vous souhaitez survivre à 2 échecs de réplica.

réplicas = ⌈ (600 × 2) / 100 ⌉ + 2 = 12 + 2 = 14 réplicas

La règle des 80%

La capacité par réplica n'est pas le point de saturation. Mesurez la capacité à 70-80% de CPU, jamais à 100%.

À partir de 80% d'utilisation, les courbes de files d'attente augmentent fortement : une file qui prenait 10 ms à 60% d'utilisation prend 80 ms à 90% d'utilisation. Le latence, et non la bande passante, rompt en premier. (La leçon complémentaire geometry_of_stateless_horizontal_scaling dérive cette courbe mathématiquement.)

Autoscaling vs Provisionnement Statique

Statique : provisionner pour le pic × marge de surcharge et accepter le coût de fonctionnement à faible utilisation en dehors des heures creuses.

Autoscaling : un contrôleur ajoute et supprime des instances en fonction de l'utilisation observée, de la latence cible ou de la profondeur de la file d'attente.

Avertissement sur l'autoscaling : le temps de démarrage froid compte. Si une nouvelle instance prend 2 minutes pour s'initialiser, l'autoscaling ne peut pas répondre à une surcharge de 30 secondes. Un autoscaling mature garde une piscine de réplicas prédimensionnés et prêts à l'emploi juste en dessous du seuil de mise à niveau.

Formule de dimensionnement des réplicas avec exemple de travail

Dimensionner un parc de machines pour un nouveau service

Votre équipe prévoit de lancer une API de métadonnées vidéo. Les benchmarks montrent qu'une seule instance gère 250 req/s pour 70% de CPU et 50 ms de latence p99. La marketing prévoit une charge maximale de 4 000 req/s pendant les heures de pointe. Un événement promotionnel prévu pourrait surger à 3x la charge maximale brièvement. Vous souhaitez que le service survive à 3 échecs de réplica sans dépasser 80% d'utilisation sur les survivants.

Appliquez la formule des réplicas pour dimensionner le parc de lancement. Montrez vos calculs étape par étape, puis expliquez une raison pour laquelle votre nombre pourrait encore être erroné (démarrage froid, réchauffage de la cache, latence des dépendances, n'importe quoi que vous pouvez défendre).

Démarrage froid, vidage lent et autres bords réels

Les véritables parcs ont des bords réels

La formule suppose que les instances apparaissent instantanément, acceptent le trafic instantanément et déchargent le trafic instantanément. Aucun de ces points n'est valable en production.

Démarrage froid: une nouvelle copie doit démarrer le système d'exploitation, lancer le processus, charger la configuration, réchauffer les caches et passer les vérifications de santé. Entre 5 secondes (redémarrage du conteneur) et 5 minutes (démarrage complet du VM + téléchargement de l'image). L'autoscaling ne peut pas répondre à des pics plus courts que ce délai.

Tir vers le bas lent: une copie en cours d'effacement du pool a besoin de temps pour terminer les demandes en cours avant de se terminer. Sinon, les utilisateurs voient des réponses tronquées. Les proxies inverses prennent en charge le vidage (arrêt de la réception de nouvelles demandes, fin des demandes actives) mais cela prend des secondes à des minutes.

Pool chaud: les flottes de production maintiennent un pool de copie pré-provisionnées mais inactives prêtes à prendre le trafic sur signal. Échange une petite coûts constant contre une réponse rapide aux pics.

Évacuation de la connexion vs mort immédiate: le redémarrage gracieux compte. Un SIGTERM qui déclenche le vidage prend plus de temps qu'un SIGKILL mais ne casse pas les demandes de l'utilisateur.

Fenêtre de vérification de santé: une copie qui vient de démarrer peut passer sa première vérification de santé avant que sa connexion de base de données ne soit chaude ; le proxy envoie alors réellement du trafic et les premières douzaines de demandes sont lentes. Ajuster les vérifications de santé pour tester le véritable chemin, pas seulement la vivacité du processus.

Étape vers la collanté: même les niveaux nominalement étatiques acquièrent de la collanté sur le temps (cache CDN, cache résolveur DNS, pools de connexions). Soyez méfiant face aux "copies identiques" qui agissent cependant différemment.

Pool chaud ou autoscaling réactif?

Votre API de métadonnées vidéo (la même que dans la question précédente, dimensionnée à 51 copies pour le pic normal + surcroît) subit une haugue de 30 secondes à 5 fois la charge normale à chaque fois qu'une nouvelle vidéo virale est publiée. L'autoscaling prend actuellement 90 secondes pour ajouter une nouvelle copie à partir de froid (téléchargement d'image + mise en route). Durant les 90 secondes d'intervalle, la latence augmente fortement et certaines demandes échouent.

Propose une solution. Choisissez : (a) garder l'autoscaling réactif mais le tuner différemment, (b) prévoir un pool de copie chaudes inactives, ou (c) prévoir statiquement pour les pics de 5x. Justifiez votre choix & donnez un nom à un coût que les deux autres options imposeraient.

Concevez un niveau étatique sans contraintes

Synthèse

Vous avez appris pourquoi l'agrandissement horizontal gagne au-delà d'un petit seuil, ce que l'état signifie en pratique, comment dimensionner un ensemble de replicas sous charge normale et sous charge de surcroît, et où l'agrandissement horizontal cesse à la périphérie.

Appliquez les quatre points.

Concevez un niveau arrière pour feed.example.com, une API de flux social. Contraintes : capacité par replica de 200 req/s avec 70% de CPU ; charge de pointe prévue de 1500 req/s ; facteur de surcharge de 2,5x (histoires tendance occasionnelles) ; résistance à 2 échecs de replicas simultanés ; temps de démarrage froid de 60 secondes ; hausses pouvant durer 45 secondes ; budget permet des capacités inactives mais pas de provisionnement permanent de 2,5x.

Dimensionnez le flot stable (montrer les calculs), choisissez votre stratégie de gestion des surcharges (bain chaud / autoscaling réactif / les deux) et identifiez une partie de l'état par utilisateur que l'application probablement détient et où elle doit se déplacer pour conserver l'état sans niveau.

Où Ce Cours Va Prochainement

Où Ce Cours Va Prochainement

Vous avez maintenant un modèle mental de travail d'un niveau sans état : pourquoi il s'agrandit, comment le dimensionner, ce qui cesse à ses bords et où l'état doit se déplacer lorsque vous le repoussez hors du niveau qui doit croître.

La prochaine leçon de ce cours (cs_distsys_ingress_egress_separation) traite d'un problème plus subtil : même un niveau sans état parfaitement dimensionné peut échouer de manière surprenante lorsque les traitements entrants et sortants partagent le même chemin réseau. L'exemple classique implique un proxy qui tente de se connecter à lui-même ; la solution implique la division d'un niveau en deux avec des responsabilités différentes.

Leçon complémentaire : geometry_of_stateless_horizontal_scaling dérive la courbe de file d'attente, la loi de Little appliquée à un ensemble de replicas et la signification géométrique du genou à 80% d'utilisation.

Bien joué. En avant.