...

Ongelijkmatige CPU-belasting in WordPress – hoe cronjobs de prestaties kunnen vernietigen

Een ongelijkmatige CPU-belasting in WordPress wordt vaak veroorzaakt door slecht geconfigureerde wordpress cronjobs, die bij elke paginaweergave als achtergrondprocessen starten en zo pieken veroorzaken. Ik laat zien hoe deze triggers de TTFB verlengen, PHP-workers binden en latentie veroorzaken – en hoe je met systeemcron, intervallen en prioritering weer terug kunt naar gelijkmatiger Kom maar op.

Centrale punten

Het volgende overzicht vat de belangrijkste aspecten samen, voordat ik dieper inga op de materie en concrete stappen uitleg. Ik houd de lijst kort, zodat de focus ligt op Actie en effect ligt.

  • WP-Cron wordt geactiveerd bij het openen van pagina's en veroorzaakt onvoorspelbare belasting.
  • PHP-processen stapelen zich op bij verkeer en vertragen TTFB.
  • Systeem cron ontkoppelt taken van de bezoekersstroom.
  • Intervallen en prioriteiten egaliseren CPU-pieken.
  • Controle ontdekt knelpunten en foutieve gebeurtenissen.

Wat WordPress-cronjobs echt doen – en waar de belasting vandaan komt

WordPress maakt gebruik van een pseudo-cron-systeem: bij het oproepen wordt wp-cron.php via POST geactiveerd, controleert het de geplande gebeurtenissen en start het taken zoals publicaties, updatecontroles, het opslaan van concepten via Heartbeat en het opschonen van de database – elke gebeurtenis kost CPU-tijd. Deze aanpak klinkt comfortabel, maar veroorzaakt oncontroleerbare triggers, omdat bezoeken de uitvoering bepalen en niet een planbare timer. Als er meerdere oproepen tegelijk binnenkomen, starten parallelle PHP-processen die concurreren om workers. Multisite-opstellingen versterken het effect, omdat elke subsite zijn eigen event-stack onderhoudt en zo het aantal controles verhoogt [1]. Wie zich verder in de materie wil verdiepen, vindt gedegen basisinformatie op WP-Cron begrijpen, maar de kernboodschap blijft: bezoekersbegeleiding is niet geschikt als betrouwbare klok.

De echte rem: parallelle PHP-processen door wp-cron.php

Elke cron-trigger start een afzonderlijk PHP-proces dat een worker bindt en zo de beschikbare rekenkracht voor echte paginarenderings. Als er veel triggers zijn, wordt de wachttijd voor een vrije worker langer, wordt de TTFB langer en komt de eerste byte later bij de browser aan [2]. Metingen hebben een vertraging van maximaal 800 milliseconden aangetoond, wat Core Web Vitals belast en de organische zichtbaarheid vermindert [3]. Shared hosting of krap bemeten PHP-FPM-instellingen versterken het effect, omdat max_children snel wordt bereikt en processen in wachtrijen terechtkomen. Vooral tijdens pieken in de winkel of campagnes kan dit een vicieuze cirkel worden: meer verkeer genereert meer cron-controles, die op hun beurt het renderen blokkeren en zo Laadtijden uitrekken [1][2].

Caching, CDN en loopback-valkuilen correct behandelen

WP-Cron gebruikt standaard een interne Loopback-verzoek naar het eigen domein. Als er een agressieve paginacache, een CDN of een Basic-Auth-blokkering voor zit, kan het oproepen mislukken of wachten – cron-runs lopen vast, herhalen zich en verlengen zo de CPU-binding. Ik zorg er daarom voor dat /wp-cron.php niet gecachet, niet rate-limited en intern bereikbaar is. System-Cron vermindert deze kwetsbaarheid omdat het zonder HTTP-loopback voert PHP direct uit. Als er een proxy is aangesloten, controleer ik bovendien of verzoeken aan 127.0.0.1 netjes worden doorgegeven en geen WAF-regel het eindpunt blokkeert. In onderhoudsfasen is het belangrijk om ofwel Cron bewust te pauzeren, ofwel het eindpunt expliciet door te laten, zodat taken die moeten worden uitgevoerd niet als pakket „achteraf“ worden uitgevoerd.

Ongelijkmatige CPU-belasting herkennen en classificeren

Typisch zijn piekbelastingen tijdens drukke uren, die niet alleen door bezoekersaantallen kunnen worden verklaard, maar ook door cron-golven van achterstallige gebeurtenissen die zich opstapelen en samen worden geactiveerd. Multisite-installaties vermenigvuldigen de belasting, omdat elke subsite cron-lijsten beheert en bij een bezoek wordt gecontroleerd – dit resulteert in korte, maar zware pieken, die logbestanden weergeven als cascades van wp-cron.php-POSTs [1]. Plugins registreren vaak hun eigen events met te korte intervallen, soms om de vijf minuten of vaker, wat bij tien plugins al snel oplopt tot tientallen controles per oproep. Let ook op je PHP-workerlimiet, want volle workers zorgen voor wachttijden die gebruikers direct merken. Wie deze patronen leest, begrijpt de ongelijke curve als gevolg van triggers, niet als onvermijdelijke humeur van het verkeer.

Waarom System Cron de belasting egaliseert

Een echte systeem-cron ontkoppelt taken van de bezoekersstroom en stelt een duidelijk ritme in, bijvoorbeeld om de vijf minuten, elk uur of elke dag, zodat de uitvoering planbaar is en de belasting gelijkmatig wordt verdeeld [1][6]. Bezoekers activeren dan geen cronjobs meer, wat TTFB ontlast en rendering prioriteit geeft. Zelfs bij weinig verkeer worden taken betrouwbaar uitgevoerd, omdat de server ze uitvoert, zelfs als niemand de pagina bezoekt. Dit helpt updates, e-mails of index-pings op tijd te laten verlopen en voorkomt dat gebeurtenissen „blijven liggen“ en later als pakket worden afgevuurd. Zo creëer ik een voorspelbare systeembelasting, die niet fluctueert naargelang het verkeer.

Stap voor stap: WP-Cron deactiveren en systeem-Cron instellen

Ik begin met het uitschakelen van de interne trigger in wp-config.php, zodat het openen van pagina's geen cronjobs meer start. Voeg hiervoor de volgende regel toe en sla het bestand op, zodat WordPress geen cron-controle uitvoert tijdens het renderen. Vervolgens stel ik een nette crontab-regel in die wp-cron.php cyclisch activeert zonder onnodige uitvoer te genereren. Zo wordt de taak tijdgestuurd uitgevoerd en worden paginaweergaven consequent ontlast. Het resultaat: rendering heeft voorrang, cronjobs hebben een eigen klokfrequentie.

// wp-config.php define('DISABLE_WP_CRON', true);
# Crontab-voorbeeld (elke 5 minuten) */5 * * * * php -q /var/www/html/wp-cron.php > /dev/null 2>&1

WP-CLI in plaats van directe PHP-aanroep

Voor een betere controle stel ik de cron-run graag in via WP-CLI Zo kan ik „alleen geplande“ gebeurtenissen uitvoeren, gedetailleerder loggen en multisites gericht afwerken. Bovendien voorkomt een lock dat meerdere runs tegelijkertijd starten.

# WP-CLI: alleen vervalde gebeurtenissen verwerken */5 * * * * /usr/local/bin/wp cron event run --due-now --path=/var/www/html --quiet

# Met eenvoudige vergrendeling via flock (aanbevolen) */5 * * * * flock -n /tmp/wp-cron.lock /usr/local/bin/wp cron event run --due-now --path=/var/www/html --quiet

In multisite-omgevingen kan ik zo via --url= Bekijk elke site afzonderlijk of laat de sites rouleren via een kleine shell-loop. Zo voorkom je dat 100 subsites tegelijkertijd dezelfde takt halen en piekbelastingen veroorzaken.

Intervallen en prioriteiten: welke taken wanneer moeten worden uitgevoerd

Niet elke taak hoeft elke minuut te worden uitgevoerd; ik rangschik ze op relevantie en kosten, zodat SEO-kritieke taken voorrang krijgen en dure taken naar daluren worden verplaatst [1]. De focus ligt op het genereren van sitemaps, indexing-pings en cache-warming, gevolgd door databaseonderhoud en het verwijderen van transiënten. Ik plan back-ups in nachtelijke tijdvensters en kies voor incrementele procedures om I/O-pieken te voorkomen. Ik voeg nieuwsbriefwachtrijen of importers samen en laat ze in vaste slots draaien, in plaats van ze bij elke paginaweergave te controleren. Deze volgorde zorgt voor duidelijke prioriteiten en voorkomt dat korte poll-intervallen de CPU verstoppen.

Taak Aanbevolen interval CPU-impact Tip
Sitemap/indexeringspings elk uur tot 1×/dag laag SEO-relevant; vóór cache-warming prioriteren
Cache-warming 1-2 keer per dag medium URL's rangschikken, geen volledige scans tijdens piekuren
Back-ups 's nachts hoog incrementeel; Remote-doel met bandbreedtelimiet
Database opschonen dagelijks of wekelijks medium Revisies/transiënten in blokken verwijder
E-mailmeldingen elk uur/1×/dag laag Batches vormen, wachtrij gebruiken

Single-run-mechanismen en schone locks

Om te voorkomen dat cron-runs elkaar overlappen, zet ik naast kudde ook WordPress-eigen beperkingen. WP_CRON_LOCK_TIMEOUT bepaalt hoe lang een run exclusief blijft. Als de pagina traag is of als er lange taken worden uitgevoerd, verhoog ik de waarde lichtjes zodat er geen tweede proces vroegtijdig wordt gestart. Omgekeerd verlaag ik de waarde als de taken kort zijn en een vertraging geen cascade-effect mag veroorzaken.

// wp-config.php – Lock-tijd in seconden (standaard 60) define('WP_CRON_LOCK_TIMEOUT', 120);

Daarnaast beperk ik bewust de parallelliteit in plug-ins (batchgroottes, staplengtes, slaapstanden tussen verzoeken). Zo voorkom ik dat een cron-run zelf weer tientallen PHP-processen genereert en de belastingscurve omhoog stuwt.

Monitoring en analyse: knelpunten zichtbaar maken

Ik begin bij de toegangslogs en filter POST-verzoeken op wp-cron.php om de frequentie en het tijdvenster te bepalen; veel korte intervallen duiden op korte intervallen of blokkerende gebeurtenissen. Tegelijkertijd controleer ik de foutenlogs op time-outs, locking en wachttijden van de database die van invloed zijn op cronjobs. In de backend geeft WP Crontrol inzicht in geregistreerde gebeurtenissen, hun hooks en geplande looptijden; daar verwijder ik verouderde of vastgelopen vermeldingen. Voor meer inzicht in transacties, query-tijden en PHP-FPM-wachtrijen gebruik ik APM-tools voor WordPress om hotspots te isoleren. Zo vind ik de oorzaken in plaats van alleen de symptomen te onderdrukken, en kan ik gericht Maatregelen prioriteit geven aan.

Meetbare doelen en korte test in 10 minuten

Ik definieer duidelijke streefwaarden: TTFB p95 voor gecachete pagina's onder 200-300 ms, voor niet-gecachete pagina's onder 800 ms; PHP-FPM-wachtrij permanent dicht bij 0; CPU zonder pieken die in verzadiging lopen. De korte test: WP-Cron deactiveren, systeem-Cron instellen, vervalde events eenmalig via WP-CLI verwerken, vervolgens logs controleren. Binnen 10 minuten zie je of de TTFB daalt, de PHP-wachtrij krimpt en of opvallende hooks (bijv. updatecontroles, importers) het grootste deel voor hun rekening nemen. Pas daarna de intervallen, batchgroottes en de kloksnelheid aan totdat de curven stabiel zijn.

Heartbeat-API en plug-in-events temmen

Het Heartbeat-mechanisme werkt sessies en ontwerpen bij, maar genereert vaak onnodige verzoeken in de frontend; ik beperk het tot admin-gebieden of stel geschikte intervallen in. Veel plug-ins registreren cronjobs met fabrieksinstellingen die te kort zijn; hier schakel ik over op langere intervallen en verplaats ik taken naar daluren. In winkelopstellingen beperk ik voorraadfeeds en prijssynchronisaties tot vaste slots, in plaats van elke minuut te pollen. Voor feeds en cache-warming gebruik ik batchlijsten, zodat niet alle URL's in één keer worden uitgevoerd. Deze ingrepen verlagen de verzoekfrequenties en egaliseren de bocht duidelijk.

Schaalbaarheid: van cronjobs naar wachtrijen en workers

Bij veel verkeer houd ik WP-Cron zo klein mogelijk en verplaats ik rekenintensieve taken naar wachtrijen met speciale workers. Jobwachtrijen verdelen de belasting over meerdere processen, kunnen horizontaal worden uitgebreid en voorkomen dat de frontend moet wachten. In container- of orkestratie-opstellingen schaal ik workers onafhankelijk van PHP-FPM, waardoor rendering en achtergrondwerk gescheiden resources krijgen. Wachtrijen zijn vooral rendabel voor imports, beeldverwerking, nieuwsbriefbatches en API-synchronisaties. Zo blijft de frontend snel reageren, terwijl achtergrondtaken gecontroleerd en planbaar rennen.

WooCommerce, Action Scheduler en grote wachtrijen

WooCommerce brengt met de Actieplanner een eigen wachtrij die bestelmails, webhooks, abonnementen en synchronisaties verwerkt. Juist hier dreigen CPU-pieken wanneer duizenden acties „due“ zijn. Ik laat de runner niet draaien wanneer de pagina wordt opgeroepen, maar activeer hem via System Cron of WP-CLI in vaste vensters. Ik stel batchgroottes en parallelliteit zo in dat een run de database niet blokkeert en PHP-FPM-workers vrij blijven. Importer, beeldregeneratie en webhook-pieken verdeel ik over meerdere kleine runs – liever 10× kort dan 1× urenlang met I/O-blokkades.

Multisite-specificaties: timing per site balanceren

In multisite-opstellingen wordt de belasting opgeteld, omdat elke site zijn eigen gebeurtenissenlijst heeft. In plaats van alles om de vijf minuten te controleren, laat ik de sites rouleren: sitegroepen met licht verschoven cycli, zodat niet alle cronlijsten tegelijkertijd worden uitgevoerd. Voor zeer actieve sites krijgt de wachtrij vaker een slot, voor rustige sites minder vaak. Het resultaat is een gelijkmatigere CPU-curve en minder concurrentie om workers – bij hetzelfde totale werkvolume.

Praktijktest: configuratie zonder valkuilen

Ik controleer eerst of DISABLE_WP_CRON correct is ingesteld, omdat dubbele triggers (intern + extern) piekbelastingen verergeren. Daarna controleer ik de crontab: correct pad, geen onnodige output, zinvol interval en geen overlappingen met back-upvensters. In WP Crontrol verwijder ik verouderde hooks en stel ik korte intervallen in op realistische cycli. Ik pas de PHP-FPM-instellingen aan het bezoekersprofiel aan, zodat PHP-workers niet constant aan de bovengrens blijven hangen. Ten slotte track ik TTFB, responstijden en CPU om het effect van de wijzigingen goed te kunnen beoordelen. Prijs.

PHP-FPM, OPCache en tijdslimieten op de juiste manier dimensioneren

De beste cron-strategie faalt als PHP-FPM te klein is of verkeerd is getimed. Ik kies pm=dynamic of pm=op aanvraag afhankelijk van het verkeersprofiel en leid pm.max_kinderen van het werkelijke RAM-budget: als vuistregel geldt RAM_voor_PHP / gemiddeld scriptverbruik. Voorbeeld: 2 GB budget en ~128 MB per proces leveren ~16 workers op. pm.max_aanvragen Ik stel een gematigde waarde in (500-1000) om lekken te beperken. verzoek_terminate_timeout beperkt aantal uitzonderlijke opdrachten; een nette slowlog ontdekt query-lussen en externe wachttijden. Een gezonde OPCache (voldoende max_accelerated_files, geheugen_verbruik, interned_strings_buffer) voorkomt koude starts en bespaart CPU per verzoek – ook voor cron-runs.

Objectcache en optiehygiëne

Een persistente objectcache (bijv. Redis/Memcached) vermindert de druk op de database voor croncontroles aanzienlijk. Belangrijk hierbij is de hygiëne in de wp_opties-Tabel: De optie cron mag niet groter worden dan enkele megabytes, anders wordt elke controle duur. Ik verwijder verouderde of vastgelopen events, ik verminder autoload-rommel en ik zet grote, zelden gebruikte opties op autoload = nee. Zo worden query-tijden korter en kunnen cron-lijsten sneller worden geëvalueerd.

Fijnafstemming: tempo, volgorde en beperkingen van middelen

Voor websites met pieken in de ochtend plan ik cache-warming in de vroege avond en laat ik sitemaps kort voor kantooruren draaien, zodat crawlers nieuwe gegevens zien. Dure databaseopschoningen splits ik op in kleinere blokken om lock-tijden te verkorten en query-pieken te voorkomen. Grote exports plan ik in het weekend, wanneer er minder interactie plaatsvindt. Waar zinvol, beperk ik parallelle taken, zodat niet meerdere cron-php-processen tegelijkertijd om I/O strijden. Deze fijnafstemming zorgt voor een gelijkmatige doorvoer en betere Reactietijden.

Beveiliging: wp-cron.php beschermen tegen externe toegang

Omdat Cron intern moet worden geactiveerd, blokkeer ik directe externe toegang tot /wp-cron.php. Zo voorkom je misbruik, DDoS en onbedoelde externe oproepen. Sta alleen lokale oproepen toe (loopback of CLI) en blokkeer al het andere. Dit vermindert ruis in de logbestanden en beschermt PHP-workers.

# Nginx-voorbeeld location = /wp-cron.php { allow 127.0.0.1; deny all; include fastcgi_params; fastcgi_pass php-fpm; }

# Apache-voorbeeld  Require ip 127.0.0.1

Veelvoorkomende oorzaken van „ghost“-belasting door cron

Zeer korte intervallen (1-5 minuten) voor niet-kritieke taken behoren tot de grootste belastingfactoren, vooral in combinatie met veel plug-ins. Hangende gebeurtenissen, die door mislukte runs steeds opnieuw worden gepland, veroorzaken lussen die de logboeken overspoelen. Vergrendelingsproblemen in de database dwingen cronjobs tot langere looptijden, waardoor overlappingen toenemen. Bovendien kunnen HTTP-blokkades (bijv. DNS of Remote API) cronruns kunstmatig verlengen en workers binden. Wie deze patronen kent, bespaart veel tijd bij het zoeken naar de oorzaak en verlaagt de Pieken snel.

Kort samengevat

Een ongelijkmatige CPU-belasting in WordPress is vaak te wijten aan WP-Cron, dat bij het openen van pagina's als trigger fungeert en PHP-workers bindt. Ik schakel de interne trigger uit, stel een systeem-Cron in, optimaliseer intervallen en geef prioriteit aan SEO-relevante taken, zodat rendering voorrang krijgt. Monitoring met logs, WP Crontrol en APM-analyses toont me foutieve gebeurtenissen, korte cycli en blokkerende processen. Voor grote projecten verplaats ik rekenintensieve taken naar wachtrijen om frontend- en achtergrondtaken netjes van elkaar te scheiden. Deze aanpak leidt tot een gelijkmatige belasting, een kortere TTFB en een merkbaar sneller Levering – zonder onverwachte pieken.

Huidige artikelen