Ujævn CPU-belastning i WordPress skyldes ofte dårligt konfigurerede wordpress cronjobs, der starter som baggrundsprocesser ved hvert sideopkald og dermed forårsager spidsbelastninger. Jeg viser, hvordan disse triggere forlænger TTFB, binder PHP-workere og skaber ventetid – og hvordan du med system-cron, intervaller og prioritering igen kan opnå mere jævn Sidste kommer.
Centrale punkter
Følgende oversigt opsummerer de vigtigste aspekter, inden jeg går mere i dybden og forklarer konkrete trin. Jeg holder listen kort, så fokus forbliver på Handling og virkning ligger.
- WP-Cron udløses ved sidevisninger og genererer uforudsigelig belastning.
- PHP-processer ophobes ved trafik og forsinker TTFB.
- System cron adskiller opgaver fra besøgsstrømmen.
- Intervaller og prioriteter udjævner CPU-spidsbelastninger.
- Overvågning afslører flaskehalse og fejlbehæftede begivenheder.
Hvad WordPress-cronjobs virkelig gør – og hvor belastningen kommer fra
WordPress bruger et pseudo-cron-system: Når det kaldes, udløses wp-cron.php via POST, kontrollerer forfaldne begivenheder og starter opgaver som offentliggørelser, opdateringskontroller, gemning af kladder via Heartbeat og oprydning i databasen – hver begivenhed koster CPU-tid. Denne tilgang lyder bekvem, men forårsager ukontrollerbare triggere, fordi besøg bestemmer udførelsen og ikke en planerbar timer. Hvis flere opkald mødes, starter parallelle PHP-processer, der konkurrerer om arbejdere. Multisite-opsætninger forstærker effekten, da hver underside vedligeholder sin egen event-stack og dermed øger antallet af kontroller [1]. Hvis du vil uddybe sammenhængene, finder du grundlæggende informationer under Forstå WP-Cron, men kernebudskabet forbliver: Besøgsstyring er ikke egnet som en pålidelig taktgiver.
Den egentlige bremse: parallelle PHP-processer gennem wp-cron.php
Hver Cron-trigger starter en separat PHP-proces, der binder en worker og dermed den tilgængelige beregningstid for ægte siderenderinger. Hvis triggere hober sig op, øges ventetiden på en ledig worker, TTFB forlænges, og den første byte ankommer senere til browseren [2]. Målinger viste en forsinkelse på op til 800 millisekunder, hvilket belaster Core Web Vitals og dæmper den organiske synlighed [3]. Shared hosting eller snævre PHP-FPM-indstillinger forværrer effekten, fordi max_children hurtigt nås, og processer ender i køer. Især ved shop-peaks eller kampagner kan dette blive en ond cirkel: Mere trafik genererer flere cron-tjek, som igen blokerer rendering og dermed Indlæsningstider strække [1][2].
Håndtering af caching, CDN og loopback-fælder
WP-Cron bruger som standard en intern Loopback-anmodning til dit eget domæne. Hvis der foran ligger en aggressiv sidecache, et CDN eller en Basic-Auth-spærring, kan opkaldet mislykkes eller vente – Cron-kørsler går i stå, gentager sig og forlænger dermed CPU-bindingen. Derfor sørger jeg for, at /wp-cron.php ikke cachelagret, ikke hastighedsbegrænset og internt tilgængelig. System-Cron afhjælper denne sårbarhed, fordi den uden HTTP-loopback, der kører PHP direkte. Hvis der er en proxy foran, kontrollerer jeg desuden, om anmodninger til 127.0.0.1 bliver videregivet korrekt, og ingen WAF-regel blokerer slutpunktet. I vedligeholdelsesfaser er det vigtigt enten at sætte Cron bevidst på pause eller eksplicit at lade slutpunktet passere, så forfaldne opgaver ikke „efterfølges“ som pakke.
Identificer og klassificer uensartet CPU-belastning
Typisk er belastningsspidser i spidsbelastningstider, som ikke alene kan forklares med besøgsantal, men med cron-bølger fra forfaldne begivenheder, der hober sig op og udløses samtidigt. Multisite-installationer mangedobler belastningen, da hver underside administrerer cron-lister og kontrolleres ved besøg – dette skaber korte, men hårde spidsbelastninger, som logfiler viser som kaskader af wp-cron.php-POSTs [1]. Plugins registrerer ofte deres egne begivenheder med for korte intervaller, nogle gange hvert femte minut eller oftere, hvilket med ti plugins hurtigt kan blive til snesevis af kontroller pr. opkald. Vær også opmærksom på din PHP-arbejdergrænse, for fulde arbejdere medfører ventetider, som brugerne mærker direkte. Hvis man læser disse mønstre, forstår man den ujævne kurve som en følge af triggere, ikke som uundgåelig humør af trafikken.
Hvorfor System Cron udjævner belastningen
Et ægte system-cron adskiller opgaver fra besøgsstrømmen og sætter en klar rytme, f.eks. hvert femte minut, hver time eller hver dag – det gør udførelsen planerbar og fordeler belastningen jævnt [1][6]. Besøgende udløser derefter ikke længere cronjobs, hvilket aflaster TTFB og prioriterer rendering. Selv ved lav trafik kører opgaver pålideligt, fordi serveren udfører dem, selvom ingen besøger siden. Dette hjælper opdateringer, e-mails eller indeks-pings med at køre til tiden og forhindrer, at begivenheder „bliver liggende“ og senere affyres som et pakke. Sådan skaber jeg en forudsigelig systembelastning, der ikke svinger efter trafikken.
Trin for trin: Deaktiver WP-Cron og opsæt system-Cron
Jeg begynder med at deaktivere den interne trigger i wp-config.php, så ingen sidevisninger længere starter cronjobs. Tilføj følgende linje og gem filen, så WordPress ikke udløser en cron-kontrol ved rendering. Derefter opretter jeg en ren crontab-regel, der starter wp-cron.php cyklisk uden at generere unødvendig output. Således kører jobbet tidsstyret og aflaster konsekvent sidevisninger. Resultatet: Rendering har prioritet, cronjobs har deres egen taktsætning.
// wp-config.php define('DISABLE_WP_CRON', true);
# Crontab-eksempel (hvert 5. minut) */5 * * * * php -q /var/www/html/wp-cron.php > /dev/null 2>&1
WP-CLI i stedet for direkte PHP-kald
For bedre kontrol indstiller jeg gerne cron-kørslen via WP-CLI af. Så kan jeg kun udføre „forfaldne“ begivenheder, logge mere detaljeret og målrettet behandle multisite. Derudover forhindrer en lås, at flere kørsler starter parallelt.
# WP-CLI: kun behandle forfaldne begivenheder */5 * * * * /usr/local/bin/wp cron event run --due-now --path=/var/www/html --quiet
# Med enkel lås via flock (anbefales) */5 * * * * flock -n /tmp/wp-cron.lock /usr/local/bin/wp cron event run --due-now --path=/var/www/html --quiet
I multisite-miljøer kan jeg således via --url= Gennemgå side for side eller lad siderne rotere via en lille shell-loop. Dette forhindrer, at 100 undersider rammer samme takt samtidigt og skaber belastningsspidser.
Intervaller og prioriteter: hvilke opgaver skal udføres hvornår
Ikke alle opgaver behøver at blive udført hvert minut; jeg prioriterer efter relevans og omkostninger, så SEO-kritiske opgaver får forrang, og dyre opgaver flyttes til spidsbelastningstider [1]. Fokus er på oprettelse af sitemaps, indekserings-pings og cache-warming, efterfulgt af databasevedligeholdelse og sletning af transiente data. Jeg planlægger backups i natvinduer og vælger inkrementelle procedurer for at undgå I/O-spidsbelastninger. Jeg samler nyhedsbrevskøer eller importører og lader dem køre i faste slots i stedet for at kontrollere dem ved hvert sidebesøg. Denne orden sikrer klare prioriteter og forhindrer, at korte poll-intervaller CPU tilstoppe.
| Opgave | Anbefalet interval | CPU-påvirkning | Hint |
|---|---|---|---|
| Sitemap/indekserings-pings | hver time til 1×/dag | lav | SEO-relevant; før cache-warming prioritere |
| Cache-opvarmning | 1–2 gange om dagen | Medium | Gradér URL'er, ingen fuld scanninger i spidsbelastningstider |
| Sikkerhedskopier | om natten | høj | inkrementel; fjernmål med båndbreddebegrænsning |
| Oprydning i databasen | dagligt eller ugentligt | Medium | Revisioner/transienter i blokke slette |
| E-mail-beskeder | hver time/1×/dag | lav | Opret batches, brug køen |
Single-run-mekanismer og rene låse
For at Cron-kørsler ikke overlapper hinanden, sætter jeg ved siden af flok også WordPress' egne begrænsninger. WP_CRON_LOCK_TIMEOUT definerer, hvor længe en kørsel forbliver eksklusiv. Hvis siden er langsom, eller hvis der kører lange jobs, øger jeg værdien moderat, så der ikke startes en anden proces for tidligt. Omvendt sænker jeg den, hvis jobbene er korte, og en hængning ikke skal udløse kaskader.
// wp-config.php – Låsetid i sekunder (standard 60) define('WP_CRON_LOCK_TIMEOUT', 120);
Derudover begrænser jeg bevidst parallelitet i plugins (batchstørrelser, trinlængder, pauser mellem anmodninger). På den måde forhindrer jeg, at en cron-kørsel selv genererer snesevis af PHP-processer og øger belastningskurven.
Overvågning og analyse: Synliggørelse af flaskehalse
Jeg starter med Access-logfilerne og filtrerer POST-anmodninger på wp-cron.php for at identificere hyppighed og tidsvinduer; mange korte intervaller indikerer korte intervaller eller blokerende begivenheder. Parallelt tjekker jeg fejllogfiler for timeouts, låsning og databaseventetider, der påvirker cronjobs. I backend giver WP Crontrol indsigt i registrerede begivenheder, deres hooks og planlagte køretider; der sletter jeg forældede eller hængende poster. For at få dybere indsigt i transaktioner, forespørgselstider og PHP-FPM-køer bruger jeg APM-værktøjer til WordPress for at isolere hotspots. På den måde finder jeg årsagerne i stedet for blot at dæmpe symptomerne, og kan målrettet Foranstaltninger prioritere.
Målbare mål og kort test på 10 minutter
Jeg definerer klare målværdier: TTFB p95 for cachelagrede sider under 200–300 ms, for ikke-cachelagrede sider under 800 ms; PHP-FPM-kø permanent tæt på 0; CPU uden spidsbelastninger, der kører i mætning. Den korte test: Deaktiver WP-Cron, indstil system-Cron, behandl forfaldne begivenheder én gang via WP-CLI, og kontroller derefter logfilerne. På 10 minutter kan du se, om TTFB falder, PHP-køen krymper, og om iøjnefaldende hooks (f.eks. opdateringskontroller, importører) udgør hovedparten. Juster derefter intervaller, batchstørrelser og takten, indtil kurverne er stabile.
Tæm Heartbeat-API og plugin-begivenheder
Heartbeat-mekanismen opdaterer sessioner og udkast, men genererer ofte unødvendige anmodninger i frontend; jeg begrænser den til admin-områder eller indstiller passende intervaller. Mange plugins registrerer cronjobs med fabriksindstillinger, der er for tætte; her skifter jeg til længere intervaller og flytter opgaver til spidsbelastningstider. I shop-opsætninger begrænser jeg lagerfeeds og prissynkroniseringer til faste slots i stedet for at pollen hvert minut. Til feeds og cache-warming bruger jeg batch-lister, så ikke alle URL'er kører på én gang. Disse indgreb reducerer anmodningsfrekvenser og udjævner kurve helt klart.
Skalering: Fra cronjobs til køer og arbejdere
Ved høj trafik holder jeg WP-Cron så lille som muligt og flytter beregningsintensive opgaver til køer med dedikerede arbejdere. Jobkøer fordeler belastningen på flere processer, kan udvides horisontalt og undgår, at frontend skal vente. I container- eller orkestreringsopsætninger skalerer jeg arbejdere uafhængigt af PHP-FPM, hvilket giver rendering og baggrundsarbejde separate ressourcer. Køer er særligt nyttige til import, billedbehandling, nyhedsbrevsbatches og API-synkroniseringer. På den måde forbliver frontend reaktionsdygtig, mens baggrundsopgaver kontrolleres og planlægbar løbe.
WooCommerce, Action Scheduler og store køer
WooCommerce bringer med Handlingsplanlægning en egen kø, der behandler bestillingsmails, webhooks, abonnementer og synkroniseringer. Netop her er der risiko for CPU-spidsbelastninger, når tusindvis af handlinger er „forfaldne“. Jeg lader ikke Runner køre, når siden åbnes, men trigger den via System-Cron eller WP-CLI i faste vinduer. Jeg indstiller batchstørrelser og parallelitet, så en kørsel ikke blokerer databasen, og PHP-FPM-workere forbliver frie. Importører, billedregenerering og webhook-spidsbelastninger fordeler jeg på flere små gennemkørsler – hellere 10× kort end 1× i timevis med I/O-blokeringer.
Multisite-specifikationer: Balancering af taktfrekvens pr. site
I multisite-opsætninger akkumuleres belastningen, fordi hver side har sin egen begivenhedsliste. I stedet for at kontrollere alt hvert femte minut, roterer jeg siderne: sidegrupper med let forskudte takter, så ikke alle cron-lister kører samtidigt. For meget aktive sider får køen oftere en plads, mens rolige sider får det sjældnere. Resultatet er en mere jævn CPU-kurve og mindre konkurrence om arbejdere – med samme samlede arbejdsmængde.
Praksis-check: Konfiguration uden faldgruber
Først kontrollerer jeg, om DISABLE_WP_CRON er indstillet korrekt, da dobbelte triggere (internt + eksternt) forværrer belastningsspidser. Derefter kontrollerer jeg crontab: korrekt sti, ingen unødvendig output, fornuftigt interval og ingen overlapninger med backup-vinduer. I WP Crontrol rydder jeg forældede hooks og ændrer korte intervaller til realistiske cyklusser. Jeg tilpasser PHP-FPM-indstillingerne til besøgsprofilen, så PHP-Worker ikke konstant hænger ved den øvre grænse. Til sidst sporer jeg TTFB, svartider og CPU for at få et klart billede af effekten af ændringerne. Vurder.
Dimensionering af PHP-FPM, OPCache og tidsbegrænsninger
Den bedste Cron-strategi går til spilde, hvis PHP-FPM er for lille eller forkert timet. Jeg vælger pm=dynamisk eller pm=efter behov afhængigt af trafikprofilen og videre pm.max_børn fra det reelle RAM-budget: Som tommelfingerregel RAM_til_PHP / gennemsnitligt scriptforbrug. Eksempel: 2 GB budget og ~128 MB pr. proces giver ~16 arbejdere. pm.max_anmodninger Jeg sætter den moderat (500–1000) for at begrænse lækager. request_terminate_timeout begrænset antal afvigende opgaver; en ren slowlog afslører query-sløjfer og eksterne ventetider. En sund OPCache (tilstrækkelig max_accelerated_files, hukommelse_forbrug, interned_strings_buffer) forhindrer kolde opstarter og sparer CPU pr. anmodning – også for cron-kørsler.
Objektcache og optionshygiejne
En vedvarende objektcache (f.eks. Redis/Memcached) reducerer databasetrykket for cron-kontroller betydeligt. Det er vigtigt at Hygiejne i wp_options-Tabel: Indstillingen cron må ikke vokse til flere megabyte, ellers bliver hver kontrol dyr. Jeg fjerner forældede eller hængende begivenheder, reducerer autoload-skrot og sætter store, sjældent anvendte indstillinger til autoload = nej. Dette reducerer forespørgselstiderne, og cron-lister kan evalueres hurtigere.
Finjustering: Takt, rækkefølge og ressourcebegrænsninger
For websteder med spidsbelastning om formiddagen planlægger jeg cache-opvarmning til tidligt om aftenen og kører sitemaps kort før åbningstiden, så crawlere kan se nye data. Dyre databaseoprydninger opdeler jeg i mindre blokke for at reducere låsetider og forhindre spidsbelastning i forespørgsler. Store eksportoperationer placerer jeg i weekendvinduer, hvor der er mindre interaktion. Hvor det er hensigtsmæssigt, begrænser jeg parallelle jobs, så flere cron-php-processer ikke kæmper om I/O på samme tid. Denne finjustering sikrer ensartet gennemstrømning og bedre Svartider.
Sikkerhed: Beskyt wp-cron.php mod ekstern adgang
Da Cron skal udløses internt, blokerer jeg direkte ekstern adgang til /wp-cron.php. Sådan forhindrer du misbrug, DDoS og utilsigtede eksterne opkald. Tillad kun lokale opkald (loopback eller CLI) og bloker alt andet. Det reducerer støj i logfilerne og beskytter PHP-arbejdere.
# Nginx-eksempel location = /wp-cron.php { allow 127.0.0.1; deny all; include fastcgi_params; fastcgi_pass php-fpm; }
# Apache-eksempel Require ip 127.0.0.1
Hyppige årsager til „ghost“-belastning fra Cron
Meget korte intervaller (1–5 minutter) for ikke-kritiske opgaver er blandt de største belastningsfaktorer, især i kombination med mange plugins. Hængende begivenheder, der gentagne gange planlægges på ny på grund af mislykkede kørsler, skaber sløjfer, der oversvømmer logfilerne. Låsningsproblemer i databasen tvinger cronjobs til længere køretider, hvilket øger overlapningen. Desuden kan HTTP-blokeringer (f.eks. DNS eller Remote-API) kunstigt forlænge cron-kørsler og binde arbejdere. Hvis man kender disse mønstre, sparer man meget tid på at finde årsagen og reducerer Tinder hurtigt.
Kort opsummeret
Ujævn CPU-belastning i WordPress stammer ofte fra WP-Cron, der fungerer som trigger ved sidevisninger og binder PHP-workere. Jeg slår den interne trigger fra, indstiller en system-Cron, optimerer intervaller og prioriterer SEO-relevante opgaver, så rendering har førsteprioritet. Overvågning med logs, WP Crontrol og APM-analyser viser mig fejlbehæftede begivenheder, tætte takter og blokerende processer. For store projekter flytter jeg beregningsintensive opgaver til køer for at adskille frontend og baggrundsopgaver tydeligt. Denne metode fører til en jævn belastning, kortere TTFB og mærkbar hurtigere Levering – uden uventede spidsbelastninger.


