Snelle samenvatting

Bij piekverkeer in webapplicaties kunnen verschillende symptomen wijzen op problemen in app code, databasebelasting of infrastructuurverzadiging. Het herkennen van deze symptomen is cruciaal voor het effectief aanpakken van bottlenecks.

  • Latency stijgt plotseling zonder volledige CPU-verzadiging, bekend als The Hockey Stick, wat wijst op interne applicatiedruk zoals lock contention of thread starvation.
  • Constant hoog CPU-gebruik met afvlakkende throughput duidt op Infrastructure Saturation, waarbij extra verkeer niet leidt tot meer verwerkingscapaciteit.
  • Oplopend geheugengebruik dat niet terugvalt, wijst op een geheugenlek in de app code, wat tijdens piekverkeer leidt tot verhoogde Garbage Collection en CPU-verzadiging.
  • Verticale schaling is effectiever voor Database Load, terwijl horizontale schaling kostenefficiënter is voor App Code bottlenecks.
  • Monitoring is essentieel om de juiste bottleneck te identificeren en te bepalen of verticale of horizontale schaling nodig is.
  • Onjuiste schaalkeuze kan leiden tot financiële verspilling en operationele complexiteit zonder de onderliggende bottleneck op te lossen.

Symptomen van piekverkeer in webapplicaties

Latency kan tijdens piekverkeer plots scherp oplopen terwijl de CPU nog niet volledig verzadigd is. Dat patroon staat bekend als The Hockey Stick: de responstijd blijft eerst redelijk stabiel, bereikt dan een omslagpunt en stijgt daarna snel. Zo’n verloop wijst niet direct op een tekort aan ruwe infrastructuurcapaciteit, maar eerder op druk die zich binnen de applicatie opstapelt, zoals lock contention of thread starvation. Voor een team voelt dat vaak verwarrend, omdat de traagheid zichtbaar is voor gebruikers terwijl de gebruikelijke indicator van volledige CPU-verzadiging nog uitblijft.

Een ander zichtbaar symptoom is constant hoog CPU-gebruik dat boven de 80% blijft hangen terwijl de throughput, uitgedrukt in requests per seconde, niet verder meegroeit. Dan neemt de belasting wel toe, maar de applicatie verwerkt niet meer verkeer. Dat afvlakken van throughput in combinatie met aanhoudend hoge CPU-belasting past bij Infrastructure Saturation. In de praktijk ontstaat dan een harde grens: extra verkeer levert geen evenredige verwerkingscapaciteit meer op, waardoor wachttijden oplopen en instabiliteit sneller merkbaar wordt.

Juist het verschil tussen deze twee patronen maakt piekverkeer lastig te duiden. Bij The Hockey Stick verschuift het knelpunt naar gedrag binnen de applicatie, terwijl bij Infrastructure Saturation de onderliggende capaciteit zichtbaar tegen zijn limiet aanloopt. Aan de buitenkant kunnen beide situaties beginnen met dezelfde klacht — een trage of haperende webapplicatie — maar het verloop van latency, CPU-gebruik en throughput laat zien dat niet elk piekprobleem uit dezelfde laag komt. Daardoor blijft de storing aan de oppervlakte hetzelfde, terwijl de signalen eronder in een andere richting wijzen.

Oorzaken van prestatieproblemen tijdens piekverkeer

Geheugengebruik dat tijdens piekverkeer in stappen blijft oplopen en niet meer terugvalt naar het eerdere basisniveau, wijst op een lek in de app code dat onder hogere belasting pas echt zichtbaar wordt. Dat patroon blijft niet beperkt tot extra geheugenverbruik. Naarmate meer geheugen vast blijft zitten, neemt ook de activiteit van Garbage Collection toe. Die extra opruimcycli trekken CPU-capaciteit weg van het normale verwerkingspad. Het gevolg is geen geleidelijke vertraging, maar een kettingreactie: de instance raakt verzadigd, health checks beginnen te falen en de load balancer kan nodes verwijderen die functioneel nog niet defect leken. Dan verschuift de druk naar de overblijvende nodes, waardoor een lokaal codeprobleem zich tijdens een verkeerspiek kan gedragen als een breder stabiliteitsprobleem.

Dit maakt app-codeproblemen verraderlijk in de diagnose. De eerste zichtbare klacht is vaak latency of instabiliteit, terwijl de onderliggende oorzaak eerder in oplopend geheugengebruik zit dan in een direct infrastructuurtekort. Het stair-step patroon laat precies dat verschil zien: het geheugen herstelt niet na drukke periodes, waardoor elke volgende piek op een slechter vertrekpunt begint. Onder normale belasting kan zo’n lek nog beperkt blijven, maar tijdens piekverkeer wordt dezelfde fout kritischer omdat Garbage Collection frequenter ingrijpt en CPU-verzadiging sneller bereikt wordt. Wat aan de buitenkant op algemene traagheid lijkt, ontstaat dan uit gedrag in de app code zelf.

Database load en infrastructuurverzadiging blijven tegelijk logische oorzaken, juist omdat ze aan de buitenkant vergelijkbare symptomen kunnen geven. Tijdens een piekperiode ontstaat daardoor makkelijk verwarring in de analyse: een team ziet vertraging en richt de aandacht direct op de database, terwijl het probleem ook kan beginnen in de applicatielaag. Die verwarring heeft een praktisch effect. Onder tijdsdruk verschuift het onderzoek naar het onderdeel dat het meest zichtbaar of het makkelijkst aanwijsbaar is, niet per se naar de werkelijke bron van de vertraging. Daardoor kan de database als eerste verdacht worden, terwijl het prestatieverlies al eerder in de keten is ingezet door geheugenlekken en oplopende CPU-druk.

Infrastructuurverzadiging past in hetzelfde beeld van piekverkeer, maar de oorzaak ligt dan niet in vasthoudend geheugen of databasebelasting, maar in een grens die onder extra vraag wordt bereikt. Het lastige is dat de uitkomst voor gebruikers opnieuw op instabiliteit lijkt: tragere respons, falende controles en capaciteit die onder druk wegvalt. Zonder scherp onderscheid tussen app code, database load en verzadigde infrastructuur blijft de storing zich presenteren als één probleem, terwijl de onderliggende oorzaak ergens anders in de keten zit en tijdens health-checkfouten zelfs kan eindigen in het verwijderen van nog draaiende nodes.

Factoren bij het kiezen van een aanpak voor bottlenecks

Opschalen in de verkeerde richting laat de vertraging bestaan en vergroot soms alleen de kosten of de diagnose-onzekerheid. De keuze tussen verticale en horizontale schaling draait hier niet om een algemene voorkeur, maar om het soort bottleneck dat tijdens piekverkeer zichtbaar wordt.

FactorWaar de keuze op wijstOperationele afweging
Verticale schalingPast sneller bij Database Load.Deze route sluit aan op situaties waarin extra capaciteit op één plek directer effect heeft. De afweging is dat dit een andere richting is dan bij App Code-bottlenecks, waardoor extra capaciteit weinig oplost als de vertraging niet primair uit de database komt.
Horizontale schalingPast kostenefficiënter bij App Code bottlenecks.Deze keuze ligt meer voor de hand als de beperking niet in de database zelf zit maar in de applicatielaag. De afweging zit in de match tussen oorzaak en schaalrichting: meer instanties toevoegen helpt minder als de druk vooral op databaseverwerking blijft liggen.
Monitoring als selectiecriteriumMonitoring bepaalt of het team de bottleneck kan toewijzen aan App Code, Database Load of infrastructuurgedrag.Zonder betere zichtbaarheid blijft de keuze tussen verticale en horizontale schaling grotendeels reactief. Dan ontstaat makkelijk een patroon waarin eerst infrastructuur wordt uitgebreid, terwijl de werkelijke oorzaak onduidelijk blijft en extra uitgaven de onderliggende vertraging niet wegnemen.
Risico van onvolledige observatieBeperkte monitoring vertraagt het herkennen van de echte oorzaak.Als teams de oorzaak niet snel kunnen aanwijzen, verschuift de aandacht vaak direct naar database-optimalisaties of extra capaciteit. Dat vergroot de kans op omwegen: meer onderhoud, technische schuld en blijvende performanceproblemen terwijl de oorspronkelijke bottleneck nog aanwezig is.
Kostendruk bij verkeerde schaalkeuzeOver-provisioning kan App Code-problemen maskeren in plaats van oplossen.Meer infrastructuur toevoegen kan tijdelijke ruimte geven, maar laat inefficiënte code ongemoeid. In dat patroon lopen resourcegebruik en kosten op, terwijl dezelfde vertraging bij een volgende piek opnieuw zichtbaar wordt.

Praktische toepassing van bottleneck-oplossingen

GC-overhead kan tijdens piekverkeer zoveel CPU-cycli opeisen dat de App Code korte, merkbare pauzes krijgt in plaats van een gelijkmatige verwerking. In de praktijk zie je dan geen stabiele vertraging maar een patroon van schokken: de runtime maakt geheugen vrij, de verwerking valt stil, en daarna komt er weer even ruimte voordat dezelfde druk terugkeert. Dat maakt app-optimalisatie een concrete bottleneck-oplossing, omdat de oorzaak hier niet in extra infrastructuur zit maar in wat de runtime onder belasting moet opruimen. Zolang die opruimdruk hoog blijft, verschuift extra capaciteit het probleem vooral in tijd in plaats van dat de onderbrekingen in de App Code verdwijnen.

Die toepassing wordt vaak zichtbaar in de volgorde waarin een piek zich ontvouwt. Eerst loopt de belasting op. Daarna gaat de runtime meer CPU gebruiken voor Garbage Collection. Vervolgens ontstaan de 'stop-the-world' pauzes in de App Code, juist op het moment dat de verwerking eigenlijk door moet lopen. Het operationele gevolg is dat teams een vertraging aan de buitenkant kunnen zien terwijl de rem intern door geheugenbeheer wordt veroorzaakt. In zo’n situatie is optimalisatie van app code geen abstract verbetertraject maar een directe ingreep op het deel van de verwerking dat onder druk stilvalt.

HPA-lag laat een ander praktisch patroon zien. De verzadiging wordt wel gedetecteerd, maar nieuwe instances zijn niet meteen beschikbaar. Tijdens die tussenperiode blijft het bestaande deel van de infrastructuur al het extra verkeer verwerken, terwijl de schaalreactie nog onderweg is. Daardoor ontstaat een venster waarin schaling formeel actief is, maar operationeel nog geen verlichting geeft. Voor eindgebruikers vertaalt dat zich in verhoogde latency en timeouts, ook al is de infrastructuur in theorie ingesteld om horizontaal op te schalen.

Juist daarom ziet infrastructuurschaling er in de praktijk anders uit dan simpelweg ‘meer capaciteit toevoegen’. Bij een plotselinge piek bepaalt de vertraging tussen detectie en beschikbaarheid van nieuwe instances hoe lang de applicatie op een verzadigd niveau blijft draaien. Als de hoofdoorzaak in GC-overhead zit, blijft die druk bovendien bestaan binnen elke instance die wordt toegevoegd. Als de hoofdoorzaak vooral capaciteitsdruk is, kan horizontale schaling wel helpen, maar pas nadat de nieuwe instances daadwerkelijk beschikbaar zijn. In beide gevallen wordt het verschil pas duidelijk in het runtime-verloop: of de verwerking stokt door pauzes in de App Code, of de infrastructuur blijft te lang wachten op extra instances.

Beperkingen en risico's bij het oplossen van bottlenecks

Het oplossen van bottlenecks brengt blijvende beperkingen en risico's met zich mee, vooral wanneer de gekozen aanpak niet aansluit op de werkelijke oorzaak. Een veelvoorkomend financieel risico is het onnodig opschalen van infrastructuur terwijl de bottleneck in de database lock-mechanismen zit. In deze situatie wordt extra capaciteit toegevoegd aan een deel van de omgeving dat de vertraging niet veroorzaakt. Dit leidt tot financiële verspilling: de kosten voor extra infrastructuur lopen op, maar de prestatiegrens blijft onveranderd omdat de onderliggende blokkade in de database blijft bestaan.

Operationeel gezien ontstaan er specifieke uitdagingen bij het implementeren van dergelijke oplossingen. Onder druk van piekverkeer kiezen teams vaak voor snelle schaalacties, omdat deze organisatorisch eenvoudiger te realiseren zijn dan het grondig analyseren van de bottleneck. Dit vergroot de kans op misconfiguraties en verhoogt de beheerlast, doordat extra capaciteit moet worden gemonitord en onderhouden zonder dat dit de kern van het probleem oplost. Bovendien leidt deze aanpak tot afstemmingsproblemen tussen ontwikkelings- en operationele teams: onduidelijkheid over verantwoordelijkheden bij het beheren van database- en infrastructuurproblemen kan vertragingen veroorzaken in het oplossen van incidenten. Hierdoor blijft de oorzaak van de bottleneck bestaan, terwijl de operationele complexiteit en de kosten toenemen.

Wanneer slechts gedeeltelijk wordt ingegrepen—bijvoorbeeld door alleen infrastructuur op te schalen zonder de interactie met de database te verbeteren—blijft het patroon zich herhalen. Tijdens volgende piekperiodes ontstaan opnieuw vertragingen en extra kosten, omdat de bottleneck in de database lock-mechanismen niet wordt weggenomen. Dit maakt bottleneck-resolutie niet alleen een technische uitdaging, maar ook een bron van financiële en operationele risico's zolang de beperking in de database blijft bestaan.

Bronnen