Load balancing uitgelegd: wat het doet en hoe het beslist
Kort antwoord
Een load balancer staat voor een groep servers en verdeelt binnenkomend verkeer daarover, zodat geen enkele server de volledige last hoeft te dragen en de dienst blijft draaien als een van die servers uitvalt. Hij bepaalt waar elk verzoek naartoe gaat: eerst met health checks die controleren of een backend daadwerkelijk reageert, en dan met een algoritme zoals round robin of least connections om te kiezen welke gezonde backend het verzoek krijgt.
Wat een load balancer eigenlijk doet
Draai een dienst op één server, en die server is meteen je capaciteitsplafond én je single point of failure. Een load balancer lost beide problemen tegelijk op. Hij staat voor twee of meer backend-servers die allemaal dezelfde applicatie draaien, en verdeelt binnenkomende verzoeken daarover. Verkeer dat één server zou hebben overbelast, wordt over meerdere servers gespreid. Valt een backend uit, dan stuurt de load balancer er geen verkeer meer naartoe, en blijven de andere backends verzoeken afhandelen zonder dat de bezoeker er iets van merkt.
De backends zelf hoeven niet te weten dat er een load balancer voor ze staat. Voor hen komen verzoeken gewoon binnen. De coördinatie, welke backend welk verzoek afhandelt, gebeurt volledig bij de load balancer.
Health checks: alleen verkeer sturen naar backends die echt actief zijn
Een load balancer die blind een vaste lijst servers afgaat, is maar half zo nuttig, want een server die is vastgelopen of gecrasht staat nog steeds op die lijst. Health checks dichten dat gat. De load balancer polst elke backend op een vast interval, meestal met een simpele TCP-verbindingspoging of een HTTP-verzoek naar een vastgelegd pad, en markeert een backend als ongezond zodra die niet meer correct reageert. Ongezonde backends worden uit de rotatie gehaald totdat ze de checks weer doorstaan.
Dit maakt een load balancer veerkrachtig, in plaats van alleen maar een verkeersverdeler. Zonder health checks zou een uitgevallen backend gewoon een deel van de verzoeken blijven krijgen, en zou elke bezoeker die daarnaartoe wordt gestuurd een foutmelding zien. Mét health checks blijft een storing in één backend onzichtbaar voor bezoekers, zolang de overige backends genoeg reservecapaciteit hebben om het verschil op te vangen.
Veelgebruikte algoritmes: hoe het volgende verzoek wordt toegewezen
Zodra de load balancer weet welke backends gezond zijn, heeft hij nog een regel nodig om te bepalen wie het volgende verzoek krijgt. Twee aanpakken dekken de meeste praktijksituaties:
- Round robin doorloopt de gezonde backends om de beurt: het eerste verzoek naar server A, het volgende naar server B, dan server C, en weer terug naar A. Het is eenvoudig en werkt goed wanneer verzoeken ongeveer even zwaar zijn en backends ongeveer dezelfde capaciteit hebben.
- Least connections stuurt elk nieuw verzoek naar de gezonde backend met op dat moment de minste actieve verbindingen. Dit past zich beter aan dan round robin wanneer verzoeken sterk verschillen in afhandeltijd, omdat het voorkomt dat er nog meer werk terechtkomt bij een backend die al bezet is met trage verzoeken.
Er bestaan ook andere algoritmes: weighted-varianten die krachtigere backends bevoordelen, of algoritmes die routeren op basis van source IP. Maar round robin en least connections dekken verreweg de meeste opzetten.
Sticky sessions: een bezoeker op dezelfde backend houden
Verzoeken spreiden over backends werkt prima zolang elk verzoek op zichzelf staat. Het gaat mis zodra een applicatie sessiestatus, zoals een winkelwagentje of een login-sessie, in het geheugen bewaart van de server die de bezoeker als eerste te verwerken kreeg. Komt het volgende verzoek van diezelfde bezoeker op een andere backend terecht, dan is die status er niet, en wordt de bezoeker uitgelogd of raakt die zijn winkelwagentje kwijt.
Sticky sessions lossen dit op door de verzoeken van een bezoeker voor de duur van diens sessie aan dezelfde backend te koppelen, meestal via een cookie die de load balancer bij elk volgend verzoek uitleest. Het is een tijdelijke oplossing, geen echte fix: het onderliggende probleem is dat sessiestatus op één server staat in plaats van op een gedeelde plek, zoals een externe cache of database. Dat laatste is de robuustere manier om dit aan te pakken zodra een applicatie moet schalen naar meer dan één backend. Sticky sessions ondermijnen ook een eerlijke verdeling van het verkeer een beetje, omdat een backend die toevallig meerdere langlopende sessies binnenkreeg drukker blijft dan een backend waarbij dat niet gebeurde.
TLS-termination: waar versleuteling wordt afgehandeld
Is het verkeer naar de dienst versleuteld, dan moet de load balancer beslissen wat hij met die versleuteling doet. Er zijn twee gangbare patronen:
- TLS passthrough: de load balancer stuurt versleuteld verkeer ongewijzigd door naar de backend, en de backend zelf beëindigt de TLS-verbinding. De load balancer krijgt de ontsleutelde inhoud nooit te zien, en elke backend heeft zijn eigen certificaatconfiguratie nodig.
- TLS offloading: de load balancer beëindigt de TLS-verbinding zelf, ontsleutelt het binnenkomende verkeer, en stuurt het vervolgens door naar de backend, onversleuteld of opnieuw versleuteld via een aparte verbinding. Dit centraliseert het certificaatbeheer op één plek en haalt de rekenkosten van versleuteling bij de backends weg. Daar staat tegenover dat de load balancer het ontsleutelde verkeer te zien krijgt, wat relevant is voor alles waarbij inspectie gevoelig ligt.
Welk patroon past, hangt af van waar je het certificaatbeheer wilt onderbrengen en of backends de overhead van het zelf beëindigen van TLS kunnen dragen. Geen van beide is altijd de juiste keuze.