Wisselende traagheid is een heel specifieke vorm van traagheid. Twee identieke verzoeken, een paar minuten na elkaar, hebben totaal verschillende laadtijden. De site is niet kapot. Hij is ook niet constant traag. Hij hapert op een manier die willekeurig voelt voor de bezoeker die toevallig een slechte treft. De kern van dit artikel is dat die hapering nooit echt willekeurig is. Het is een patroon dat je nog niet herkent.
Wat wisselende traagheid eigenlijk is
Wisselende traagheid is variatie in responstijd die overblijft nadat je de voor de hand liggende dingen hebt weggefilterd. Zelfde pagina, zelfde bezoeker, zelfde cachestaat, zelfde regio, zelfde apparaat, vijf minuten ertussen: de ene keer snel, de andere keer traag. De gemiddelden in een hosting dashboard verbergen het, want die vlakken pieken af. De bezoeker die net de piek raakt heeft weinig aan een gemiddelde.
Het patroon is de moeite waard omdat constante traagheid en wisselende traagheid andere oorzaken hebben. Constante traagheid is meestal structureel: te kleine hosting, kapotte cache, zwaar thema. Wisselende traagheid gaat bijna altijd over een gedeelde resource die op specifieke momenten onder druk staat. De site is snel als er niks om die resource vecht en traag als er wel iets om vecht.
Het mechanisme: een wachtkamer met een vast aantal stoelen
Het meest bruikbare mentale model is de PHP-FPM worker pool. Een WordPress site heeft een vast aantal PHP workers. Elk ongecachet verzoek bezet een worker zolang de pagina opgebouwd wordt. Als alle workers bezig zijn, wacht het volgende verzoek in een rij tot er eentje vrijkomt. De pm.max_children directive bepaalt dat plafond, en er is geen overloop boven dat getal.
Die rij is waar wisselende traagheid ontstaat. Zie het als een wachtkamer met een vast aantal stoelen en een balie per stoel. Op een rustige middag loop je zo door. Tijdens een plotselinge drukte sta je even te wachten. Er is niks aan de baliemedewerkers veranderd en ook niks aan jou. Het enige wat veranderde is hoeveel andere mensen op hetzelfde moment binnenkwamen.
Elke vorm van wisselende traagheid is een variant hierop. Of er kwamen meer verzoeken tegelijk binnen dan normaal, of de verzoeken die binnenkwamen kostten meer workertijd dan normaal, of de server liep ergens anders tegen een gedeelde resource aan en de workers moesten daarop wachten. CPU, database verbindingen, disk I/O, externe API's en de cache zelf zijn allemaal gedeelde resources die zich onder druk op dezelfde manier gedragen.
De veelvoorkomende patroonvormen
De helft van de diagnose is gewoon het patroon benoemen. Een handvol vormen dekt bijna elke site.
- Tijd van de dag. Traag op bepaalde uren, snel daarbuiten. Bezoekerspieken botsen met de worker pool tijdens werkuren. Hoge CPU belasting volgt meestal dezelfde curve.
- Per pagina. Gecachete pagina's zijn snel, de cart en checkout zijn traag. Ingelogde pagina's omzeilen de full-page cache by design, dus die betalen de volle PHP prijs op elk verzoek. Categoriepagina's en zoekresultaten kunnen zich hetzelfde gedragen als de onderliggende database queries traag zijn.
- Per gebruiker. Anonieme bezoekers zien een snelle voorkant, ingelogde gebruikers een trage. Zelfde cache-bypass als hierboven. Het artikel over een trage admin behandelt de extreme versie hiervan.
- Lawaaierige buur. Shared hosting betekent dat je CPU, geheugen en disk deelt met andere sites op dezelfde machine. Als een buur een verkeerspiek krijgt of een backup start, wordt jouw site traag zonder dat er aan jouw kant iets verandert. Het enige betrouwbare signaal is dat de traagheid met niks in jouw eigen logs correleert.
- WP-Cron botsing. WordPress plant taken via WP-Cron, en dat draait op page loads, niet op een systeemtimer. De eerste bezoeker na een geplande tijd triggert de achterstallige taak tijdens zijn eigen verzoek. Die bezoeker wacht tot de taak klaar is. Iedereen daarna is weer snel. Backup plugins, sitemap rebuilds en e-mail digests zijn de usual suspects.
- OPcache koude start na een deploy. OPcache bewaart gecompileerde PHP in het geheugen. Na een deploy, een PHP-FPM reload of een server restart is die cache leeg, en elk verzoek van de eerste paar seconden betaalt de compile kost voordat het draait. De eerste handvol verzoeken na een release zijn trager dan alles wat daarna komt.
- Backup venster botsing. Hostingproviders en plugins plannen backups op vaste tijden. Een dump van een grote database terwijl de site verkeer aan het afhandelen is zet de disk I/O vast, en de worker pool gaat erop staan wachten. De traagheid hangt strak aan het backup venster vast en verdwijnt op het moment dat de dump klaar is.
Waarom WordPress hier extra gevoelig voor is
WordPress is uitzonderlijk goed in het omzetten van kleine contentie naar zichtbare traagheid. Ongecachete pagina's bouwen het hele request pad door PHP heen bij elk verzoek, het plugin ecosysteem doet met regelmaat synchrone externe API calls op de voorkant, WP-Cron wordt door verkeer getriggerd in plaats van door een echte timer, en de meeste hosts zetten PHP workers op een vrij laag aantal omdat ze hardware delen tussen veel sites. Elk van die dingen is prima op zichzelf. Samen betekenen ze dat elke kleine fluctuatie in load, externe latency of achtergrondwerk de worker pool even over zijn plafond kan duwen.
Praktische implicaties
De eerste bruikbare stap is altijd: noteer de exacte minuut van een trage event, welke pagina het was en of je ingelogd was. Twee of drie datapunten maken het patroon meestal zichtbaar. Correleer dat tegen de tijden waarop backups draaien, cron jobs afgaan en verkeer normaal piekt. Correleert er niks mee, dan is de volgende kandidaat een buur op shared hosting, en dat is niet iets wat je vanuit WordPress kunt oplossen.
De tweede stap is stoppen met wisselende traagheid als één probleem zien. De fix voor een WP-Cron botsing is WP-Cron verhuizen naar een systeem cron. De fix voor trage ingelogde gebruikers is het admin pad tunen. De fix voor een worker pool plafond is pm.max_children verhogen of het werk per verzoek verlagen. Geen van die fixes werkt voor de andere.
Wat wisselende traagheid niet is
De meeste frustratie rond dit probleem komt doordat mensen het samenvouwen met iets anders. Dit zijn de verwarringen die de moeite waard zijn om hardop te benoemen.
- Niet alleen een hosting tier probleem. "Upgrade je pakket" is het standaardadvies en vaker fout dan goed. Een groter pakket koopt meer CPU en geheugen, maar als de oorzaak een WP-Cron botsing is of een externe API die er drie seconden over doet op de productpagina, helpt die extra capaciteit niks. Je staat nog steeds drie seconden op die derde partij te wachten.
- Niet opgelost met "meer RAM". Geheugenproblemen en wisselende traagheid zijn andere failure modes. Een site die onder geheugendruk pagina's naar disk swapt is constant traag, niet wisselend. Als de traagheid echt wisselt, verandert meer geheugen er meestal niks aan.
- Niet willekeurig. Elke "willekeurige" traagheid heeft een oorzaak die op dat precieze moment gebeurde. De willekeur zit in de meting, niet in het systeem. Als je het patroon niet vindt, heb je of niet genoeg gelogd, of je kijkt naar de verkeerde laag. Het antwoord is nooit "de site is gewoon soms raar".
- Geen thema issue. Thema's produceren constante traagheid, geen wisselende. Een traag thema is traag op elk verzoek. Als jouw verzoeken om 14:00 twee keer trager zijn dan om 10:00 op dezelfde pagina, dan is het thema niet de variabele.
- Wordt niet automatisch opgelost door een CDN. Een CDN cachet statische assets en, met full-page caching, ook gecachete HTML. Gecachete verzoeken zijn per definitie snel. De trage verzoeken tijdens een wisselende traagheid event zijn juist degene die de cache missen: ingelogde gebruikers, de cart, de checkout, niet-cachebare endpoints. Die reizen nog steeds naar de origin en staan nog steeds in dezelfde worker pool te wachten. Een CDN beperkt de schade, maar haalt hem niet weg.
Waar je verder kunt lezen
Lijkt het patroon op "traag overdag, snel 's nachts", dan is PHP workers en pool uitputting de volgende stap, want dat artikel legt het queueing model eronder uit. Lijkt het patroon op "traag op de cart maar snel op de homepage", dan gaat het artikel over een trage database over waarom ongecachete pagina's de database hard raken. Lijkt het patroon op "traag zodra ik inlog", dan behandelt het trage admin artikel waarom het dashboard niet te cachen valt. En sta je nog op het niveau van "de site is traag en ik weet niet waarom", dan tekent het overkoepelende artikel over een trage WordPress site de volledige beslisboom.