Twee Manieren om Meer Belasting te Vervoeren
Welkom
Als een service begint onder de last te buksen, staat een operator voor een keuze. Maak de bestaande machine groter (meer CPU, meer RAM, snellere schijven). Of voeg meer machines toe die elk hetzelfde werk uitvoeren.
De eerste weg gaat als verticale schaling (omhoog). De tweede gaat als horizontale schaling (uitbreiden).
Dit lesje leert waarom bijna elke moderne webarchitectuur kiest voor horizontale schaling en welk eigenschap van de belasting die keuze haalbaar maakt. Het antwoord schuilt in één woord: state.
Na het lezen begrijp je:
- De kostenkurven van verticale vs horizontale schaling en waar elke optie zinvol is
- Wat 'stateful' en 'stateless' betekent in de praktijk en waarom één van hen goedkoop meerdere keren kan worden vermenigvuldigd
- De wiskunde die een replica-vloot groot maakt onder verwachte en piekbelasting
- De headroom-regel die een laag voorkomt dat het instort onder de wachtrijknikker
- Waar state moet worden geplaatst (het verdwijnt nooit) en hoe je het kunt verplaatsen uit de lagen die moeten schalen
Waarom Horizontaal Wint Na Een Dreklijn
Verticale Schaling: Een Grotere Doos
Voordelen: eenvoudig. Geen code wijzigingen. Geen coördinatie. Hetzelfde proces heeft nu meer CPU.
Nadelen: plafond. De grootste commercieel beschikbare VM heeft beperkte RAM en cores. Boven dat niveau koopt niets meer hoofdruimte. De kosten lopen exponentieel door na het zoetpunt van een aanbieders aanbod. Een fout in die ene machine brengt de hele service ten val.
Horizontale Schaling: Veel Kleinere Dozen
Voordelen: geen plafond (tot je bereid bent machines te betalen voor en te coördineren). Capaciteit voegt zich lineair met het aantal replica's, voorspelbaar. De fout van een enkele replica verwijdert 1/N van de capaciteit, niet 100%.
Nadelen: vereist dat de belasting het ondersteunt. Sommige belastingen (een enkele grote database, een stateful game server die live sessies vasthoudt) verzetten zich tegen horizontale schaling. Coördinatie en belastingverdeling worden operationele zorgen.
De crossover: elke productieservice die een enkele machinefout moet overleven, moet draaien op minstens twee machines. Zodra je twee accepteert, heb je al horizontale schaling gekozen. Daarna is de vraag niet 'moeten we?' maar 'hoe goedkoop kunnen we de volgende replica toevoegen?'
Het sleuteltechnologie: een belasting die geen per-verzoekstaat op de machine zelf vasthoudt. Dan kan elk replica elke aanvraag beantwoorden & toevoegen van een replica voegt capaciteit toe zonder coördinatie.
Stateful vs Stateless in de praktijk
Staat gaat nooit verloren, het verplaatst zich gewoon
Stateful component: houdt informatie vast waarvan de verlies zou veranderen. Een database die gebruikersaccounts bevat. Een cache die sessie tokens bevat. Een werker die een lange loopende streamingverbinding koppelt aan een specifieke gebruiker.
Stateless component: houdt geen informatie vast waarvan het verlies van belang zou zijn. Een weblaag die een aanvraag leest, een database raadpleegt en een antwoord schrijft. Elke aanvraag staat alleen; de laag herinnert niets tussen aanvragen.
Hoofdinsight: staat gaat nooit uit een systeem verdwijnen. Het verplaatst zich naar een laag die ontworpen is om het vast te houden (een database, een Redis cluster, een objectopslag). De lagen die verkeer raken kunnen dan stateless gaan en stateless lagen schalen horizontaal omdat elk replica elke aanvraag kan beantwoorden.
Praktische test: als je één proces in deze laag willekeurig zou doden en opnieuw zou starten, zou een gebruiker dan een verkeerd antwoord of een verloren sessie ervaren? Als ja, dan bevat het staat. Als nee, dan bevat het niet.
Voorbeelden
- Een Python webproces dat aanvragen leest, Postgres raadpleegt en JSON retourneert: stateless. Staat bevindt zich in Postgres.
- Een Python webproces dat lokale geheugen gebruikt om winkelwagens van gebruikers te bewaren: stateful. Het doden van het proces verliest winkelwagens.
- Een WebSocket-server die open verbindingen onderhoudt met chatgebruikers: stateful in de zin van de verbinding. Het doden van het proces verliest verbindingen; klanten moeten opnieuw verbinden. Deze schalen horizontaal met voorzichtigheid (plaksessies, consistent hashen).
- Een Redis-cache die Postgres voorafgaat: stateful voor de inhoud van de cache, maar acceptabel als cache mis zijn tolerabel. Een replica-fout betekent cache mis, niet gegevensverlies.
Het ontwerpen voor horizontale schaling = het uit het laag halen van de staat die moet schalen.
Audit een Verdacht Niveau
Een team draait een aanbevelingen-API op 6 achterste VM's achter een omgekeerde proxy. De toepassing: leest een gebruikers-ID uit de aanvraag, haalt de recente activiteiten van de gebruiker op uit Postgres, voert een score-algoritme uit, retourneert een lijst met aanbevolen items. Twee niet-standaardgedragingen:
- De toepassing houdt een 'recente gebruikersactiviteit' cache in het procesgeheugen, geïnitialiseerd bij de eerste aanvraag voor een gebruiker, hergebruikt bij vervolgvragen.
- De toepassing maakt gebruik van vastgelopen sessies: als een gebruiker VM #3 raakt, gaan alle vervolgvragen naar VM #3 (de proxy is geconfigureerd voor vastgerouteerde sessies op basis van een cookie).
Het Formulier van de Replica
De Eenvoudigste Capaciteitsformule
Zodra een niveau staatloos wordt, wordt de groottebepaling wiskunde. Je hebt voldoende replica's nodig zodat de continue belasting toekomt en vertrekt op dezelfde manier, met headroom voor overlast.
Het formuleer:
replicas = ⌈ (peak_load × surge_factor) / per_replica_capacity ⌉ + headroom
Waar:
- peak_load: maximale gesustende aanvragen per seconde die je in normale omstandigheden verwacht
- surge_factor: een multiplier die korte stoten boven de piek (vaak 1,5x tot 2x voor voorspelbare verkeer, 3x of meer voor virale/onvoorspelbaar)
- per_replica_capacity: aanvragen per seconde die één replica acceptabel handelt met betrekking tot latentie & belasting (vaak gemeten op 70% CPU, niet op de rand)
- headroom: extra replica's zodat een paar replica-fouten het niveau niet laten instorten (vaak 1-2 replica's voor kleine vloten, 10-20% voor grotere)
Worked voorbeeld: een backend verwerkt 100 aanvragen per seconde (req/s) met 70% CPU per replica. De piekbelasting is 600 req/s. Je verwacht af en toe een 2x piek. Je wilt dat de service 2 replica-fouten overleeft.
replicas = ⌈ (600 × 2) / 100 ⌉ + 2 = 12 + 2 = 14 replicas
Het 80%-regel
De capaciteit per replica is niet het zaaipunt van verzadiging. Meet de capaciteit op 70-80% CPU, nooit op 100%.
Rond de 80% benutting stijgt de wachtrijkromme scherp: een wachtrij die in 10 ms liep bij 60% benutting, loopt in 80 ms bij 90% benutting. Latentie, niet doorvoering, breekt allereerst. (De bijbehorende les geometry_of_stateless_horizontal_scaling berekent deze kromme wiskundig.)
Autoscaling vs Statisch voorziening
Statisch: voorzien in de capaciteit voor de piek × reserveringsmarge voor pieken & accepteer de kosten van het draaien met lage benutting buiten piek.
Autoscaling: een controller voegt & verwijdert replicas op basis van waargenomen benutting, doellatentie of wachtrijdiepte.
Waarschuwing voor Autoscaling: de opwarmtijd telt. Als een nieuwe replica 2 minuten nodig heeft om op te starten, kan autoscaling niet reageren op een piek van 30 seconden. Volwassen autoscaling houdt een warme pool vooraf voorzien replicas aan die net onder de schaalsom threshold liggen.
Grootte van een vloot voor een nieuw service
Je team plannen om een video-metadata API te lanceren. Benchmarktests tonen aan dat een enkele replica 250 req/s verwerkt bij 70% CPU & 50 ms p99 latentie. Marketing voorspelt een piekbelasting van 4.000 req/s tijdens de piekuren. Een geplande actie kan de belasting verhogen tot 3x de piek. Je wilt dat de service 3 gelijktijdige replica-fouten overleeft zonder de overbelasting van 80% te bereiken op de overlevenden.
Opwarmtijd, langzame aftapping & andere echte randen
Echte vloten hebben echte randen
De formule gaat ervan uit dat replicas direct verschijnen, verkeer direct accepteren & verkeer direct afwijzen. Dat klopt allemaal niet in productie.
Koude start: een nieuwe replica moet de OS opstarten, het proces starten, de configuratie laden, caches opwarmen en gezondheidstests doorlopen. Overgang van 5 seconden (container herstart) tot 5 minuten (volledige VM opstarten + afbeelding laden). Autoscaling kan niet reageren op pieken korter dan deze vertraging.
Trage aftapping: een replica die uit de pool wordt verwijderd, heeft tijd nodig om in-vluchtende verzoeken af te handelen voordat deze wordt geëindigd. Anders zien gebruikers afgeknipte antwoorden. Reverse proxies ondersteunen aftapping (nieuwe verzoeken stoppen, actieve verzoeken afronden), maar dit kost seconden tot minuten.
Oprolingspool: productie vlootslagen houden een pool met vooraf geïnitieerde maar inactieve replicas klaar om verkeer te accepteren op signaal. Handelt een kleine constante kosten uit tegen snelle reactie op pieken.
Aftapping vs directe afsluiting: een zachte opname maakt verschil. Een SIGTERM die de aftapping activeert, duurt langer dan SIGKILL, maar breekt geen gebruikersverzoeken.
Gezondheidstestvenster: een replica die pas is gestart, kan zijn eerste gezondheidstest doorstaan voordat zijn databaseverbindingspool warm is; de proxy stuurt dan echte verkeer en de eerste twaalf verzoeken zijn traag. Pas gezondheidstests aan om de echte pad te testen, niet alleen de proceslevensvattheid.
Klemmendheid groei: zelfs nominale stateless lagen krijgen klemmendheid over tijd (CDN caches, DNS oplosser caches, verbindingsspools). Wees vermoedelijk van 'identieke replicas' die echter anders reageren.
Oprolingspool of Reactieve Autoscaling?
Je video metadata API (dezelfde als in de vorige vraag, uitgerust met 51 replicas voor de constante piek + piek) ervaart een piek van 30 seconden tot 5x normale belasting wanneer een nieuw virale video wordt geüpload. Autoscaling neemt momenteel 90 seconden in beslag om een nieuwe replica vanaf de koude stand (afbeelding laden + opwarmen) te creëren. Tijdens de 90-secondenluchthaven stijgt de latentie sterk en mislukken sommige verzoeken.
Ontwerp een Stateless Laag Onder Beperkingen
Synthese
Je hebt geleerd waarom horizontale scaling beter is na een bepaalde drempel, wat staat betekent in de praktijk, hoe je een vloot kunt grootten onder verwachte en piekbelasting, & waar horizontale scaling breekt aan de randen.
Pas alle vier toe.
Ontwerp een backendlaag voor feed.example.com, een social-feed API. Beperkingen: per-replica capaciteit 200 aanvragen per seconde bij 70% CPU; verwachte piekbelasting 1500 aanvragen per seconde; piekfactor 2,5x (gelegenheidsverhalen over trending onderwerpen); kan 2 gelijktijdige replica-fouten overleven; starttijd bij koude toestand 60 seconden; pieken kunnen 45 seconden duren; budgettoelating voor enige idle capaciteit maar niet voor 2,5x permanente provisioning.
Waar Dit Cursus Verder Gaat
Waar Gaat Deze Cursus Verder
Je hebt nu een functioneel mentaal model van een staatloze laag: waarom het schaal, hoe je het groott, wat breekt aan de randen & waar staat moet verplaatsen wanneer je het uit de laag duwt die moet groeien.
De volgende les in deze cursus (cs_distsys_ingress_egress_separation) behandeelt een subtielere probleem: zelfs een perfect geschaalde staatloze laag kan mislukken op onverwachte manieren wanneer inkomende en uitgaande verkeer dezelfde netwerkpad delen. Het klassieke voorbeeld betreft een proxy die probeert zichzelf te verbinden; de oplossing houdt in het splitsen van één laag in twee met verschillende verantwoordelijkheden.
Complementaire les: geometry_of_stateless_horizontal_scaling ontleedt de wachtrijcurve, Little's Wet toegepast op een replica-vloot & de geometrische betekenis van de knie van 80% belasting.
Goed gedaan. Doorzetten.