WordPress CPU wird schnell zum Engpass, weil jede Anfrage PHP-Code, Datenbankabfragen und viele Hooks ausführt und damit Rechenzeit frisst. Ich zeige konkret, wo die CPU-Zeit verloren geht und wie ich sie mit Caching, sauberem Code und einem passenden Hosting-Setup deutlich senke.
Zentrale Punkte
Die folgenden Stichpunkte geben dir einen schnellen Überblick über die wichtigsten Ursachen und Gegenmaßnahmen.
- Dynamik statt statischer Auslieferung treibt die CPU-Last pro Request hoch.
- Plugins und Page Builder erhöhen Codepfade und Queries.
- Datenbank-Ballast und fehlende Indizes verlängern Abfragen.
- Caching auf mehreren Ebenen reduziert PHP-Workload massiv.
- WP-Cron, Bots und APIs erzeugen Zusatzlast je Seitenaufruf.
Statisch vs. dynamisch: Warum WordPress mehr CPU braucht
Eine statische Site liest Dateien und sendet sie direkt, während WordPress pro Aufruf PHP startet, Queries fährt und Hooks abarbeitet. Ich sehe in Audits, dass schon geringe Zusatzlogik die CPU-Zeit pro Request deutlich verlängert. Jeder Filter und jede Action erweitert den Codepfad und erhöht die Anzahl der Funktionsaufrufe, was die Antwortzeit pro Anfrage streckt. Fehlt ein Page Cache, durchläuft jede Seite die volle Pipeline und addiert vermeidbare Millisekunden auf Serverebene. Genau deshalb priorisiere ich früh die Trennung zwischen dynamischen und statischen Pfaden und reduziere die PHP-Ausführung, wo immer möglich.
Plugins als CPU-Treiber: Viel Code, viele Hooks
Jedes Plugin erweitert den Stack, oft global geladen und auf jeder Seite aktiv, was die CPU belastet. Ich prüfe deshalb Funktionen, die nur auf Teilseiten nötig sind, und lade sie bedarfsabhängig. Schleifen über große Datenmengen, wiederholte Optionen-Reads und exzessives Logging erzeugen unnötige Arbeit pro Request. Besonders Page Builder, Formularsuiten, Shops und Membership-Module bringen viele Abhängigkeiten mit und erhöhen die Ausführungszeit. In der Praxis lohnt sich ein Audit mit Fokus auf init-Hooks, Autoloads und doppelte Funktionsblöcke, die ich gezielt deaktiviere oder ersetze.
Unoptimierte Datenbank und teure Queries
Über die Zeit füllen Revisionen, Spam-Kommentare, verwaiste Metadaten und abgelaufene Transients die Datenbank. Das führt zu längeren Scans, fehlenden Cache-Treffern und spürbarer CPU-Last beim Sortieren und Joinen. Ich begrenze Revisionen, bereinige Kommentar-Tabellen und entferne alte Transients regelmäßig. Dazu prüfe ich Indizes für häufige Suchen und optimiere Queries, die ganze Tabellen ohne Filter durchlaufen. Mit einem sauberen Schema und gezielten Indizes sinkt die Abfragezeit, und PHP wartet weniger auf Ergebnisse.
Caching-Layer: Wo sie greifen und wie viel CPU sie sparen
Ich setze auf abgestufte Caches, damit PHP seltener ausführt und die CPU mehr Requests pro Sekunde schafft. Page Cache liefert fertiges HTML, Object Cache hält häufige Query-Ergebnisse, und ein Opcode Cache spart das Parsen von Skripten. Ein Browser- und CDN-Cache reduziert außerdem Last auf dem Ursprung und verbessert Time-to-First-Byte. Wichtig ist die korrekte TTL-Strategie und, dass eingeloggte Nutzer oder Warenkörbe selektiv dynamisch bleiben. So senke ich die durchschnittliche Antwortzeit und halte Spitzenlasten beherrschbar.
| Ebene | Beispiel | Entlastet | Typischer Gewinn | Hinweis |
|---|---|---|---|---|
| Page Cache | Statisches HTML | PHP-Ausführung | Sehr hoch | Bypasse für eingeloggte Nutzer |
| Object Cache | Redis/Memcached | Datenbank-Reads | Hoch | Cache-Keys konsistent halten |
| Opcode Cache | OPcache | Parsing & Kompilierung | Mittel | Warmer Cache nach Deploys |
| Browser/CDN | Assets an der Edge | Ursprung-Traffic | Mittel bis hoch | TTL, Versionierung beachten |
WP-Cron und Hintergrundjobs: Lastspitzen entschärfen
wp-cron.php läuft bei Seitenaufrufen mit und startet Tasks wie Veröffentlichungen, Mails, Backups und Importe, was die CPU zusätzlich bindet. Ich deaktiviere die Auslösung per Request und stelle auf einen System-Cron mit festen Intervallen um. Danach reduziere ich Frequenzen, entferne alte Jobs und verteile schwere Prozesse in ruhigere Zeiten. Häufig lösen Plugins zu enge Zeitpläne aus, die die Seite im Tagesbetrieb bremsen. Wer tiefer einsteigen will, liest zu ungleichmäßige CPU-Last durch WP-Cron und setzt gezielt Limits, um Long-Runner zu vermeiden.
Bot-Traffic und Angriffe: Schutz vor unnötiger PHP-Ausführung
Brute-Force-Versuche, Scraper und schädliche Bots zünden auf jeder Anfrage PHP und treiben die Last, obwohl kein echter Nutzer davon profitiert. Ich setze eine WAF, Rate-Limits und Captchas auf Login- und Formularrouten, damit Anfragen früh stoppen. Fail2ban-Regeln und IP-Filter sperren aggressive Muster, bevor WordPress überhaupt lädt. Zusätzlich cache ich 404-Seiten kurz und schütze xmlrpc.php, damit bekannte Vektoren weniger Chancen haben. So bleibt die Serverlast kalkulierbar und legitimer Traffic fühlt sich schneller an.
Externe Dienste und API-Calls: I/O blockiert PHP-Worker
Marketing-Skripte, Social-Feeds oder Payment-Integrationen warten auf entfernte APIs und blockieren so die Worker. Ich setze Timeouts knapp, cache Ergebnisse und verschiebe Abfragen auf die Serverseite mit Intervallen. Wo möglich, lade ich Daten asynchron im Browser, damit der PHP-Request schneller antwortet. Eine Queue für Webhooks und Importe verhindert, dass Frontend-Requests schwere Arbeit übernehmen. Das Ergebnis sind kürzere Laufzeiten pro Request und mehr freie Worker in Peaks.
PHP-Version, Single-Thread-Charakter und Worker-Setup
Moderne PHP-8-Versionen liefern mehr Leistung pro Kern, während alte Interpreter sichtbar langsamer arbeiten. Da Requests single-threaded laufen, zählt die Geschwindigkeit je Worker enorm. Ich beachte außerdem, wie viele gleichzeitige Prozesse der Server tragen kann, ohne in Swap oder I/O-Wartezeiten zu rutschen. Für das tiefere Verständnis der Single-Core-Geschwindigkeit verweise ich auf die Single-Thread-Leistung, die bei WordPress besonders relevant bleibt. Erst mit einem aktuellen Stack und einer durchdachten Worker-Anzahl schöpfe ich die CPU effizient aus.
Hosting-Architektur: Caching-Proxy, PHP-FPM und dedizierte Datenbank
Statt nur mehr Kerne zu buchen, trenne ich Rollen: Reverse Proxy für Cache, separate PHP-FPM-Ebene und ein eigener Datenbank-Server. Diese Aufteilung verhindert, dass sich CPU-Spitzen gegenseitig verstärken. Ein CDN entlastet den Ursprung von Assets und bringt die Antwort näher an den Nutzer. Mit Edge-Caching für ganze Seiten spare ich viele PHP-Aufrufe bei wiederkehrenden Besuchen. Auf dieser Basis wirken Code-Optimierungen stärker, weil die Infrastruktur Last sauber verteilt.
Wann ich einen Hoster-Wechsel einplane
Ich ziehe einen Wechsel in Betracht, wenn die PHP-Version alt ist, Object Cache fehlt oder harte Limits die Workerzahl einengen. Auch starre I/O-Limits und fehlende Caching-Schichten bremsen optimierte Sites unverhältnismäßig aus. In solchen Fällen bringt ein moderner Stack sofort spürbare Verbesserungen, sofern Plugins und Datenbank bereits entrümpelt sind. Ich achte zudem auf NVMe-Speicher und sinnvolle CPU-Taktfrequenzen pro Kern. Erst mit diesen Bausteinen nutzt WordPress die Ressourcen wirklich effizient.
Der PHP-Bottleneck: Profiling statt Rätselraten
Ich löse CPU-Probleme nicht mit Bauchgefühl, sondern mit Profiling auf Funktions- und Query-Ebene. Query Monitor, Logfiles und Server-Profiler zeigen mir genau, welche Hooks und Funktionen am längsten laufen. Danach entferne ich doppelte Arbeit, cache teure Ergebnisse und reduziere Schleifen über große Mengen. Häufig genügen kleine Codeänderungen wie lokale Caches in Funktionen, um viele Millisekunden zu sparen. So schrumpft die Gesamtzeit pro Request, ohne Features zu opfern.
Monitoring und Reihenfolge der Maßnahmen
Ich starte mit Metriken: CPU, RAM, I/O, Response-Zeiten und Request-Rate liefern die Basis für Entscheidungen. Dann prüfe ich Plugins und Themes, entferne Dubletten und teste schwere Kandidaten isoliert. Als Nächstes aktiviere ich Page- und Object-Cache, sichere den Opcode Cache und überprüfe Cache-Hitrate und TTLs. Danach räume ich die Datenbank auf, setze Indizes und verschiebe wp-cron auf einen echten Systemdienst. Zum Schluss optimiere ich PHP-FPM-Parameter, arbeite Engpässe aus dem Code und teste die Skalierung unter Last.
PHP-Workers richtig dimensionieren
Zu wenige Worker erzeugen Warteschlangen, zu viele Worker führen zu Kontextwechseln und I/O-Druck. Ich messe die typische Parallelität, den Anteil an Cache-Hits und die durchschnittliche PHP-Zeit pro Request. Danach wähle ich eine Worker-Zahl, die Spitzen abfängt, aber den RAM nicht ausreizt. Ich setze auch Max Requests und Timeouts, damit „leaky“ Prozesse sich regelmäßig neu starten. Gute Hintergründe liefert der Artikel zu PHP-Worker Flaschenhals, der die Balance zwischen Durchsatz und Stabilität detailliert beschreibt.
Autoload-Optionen und Transients: Versteckte CPU-Kosten in wp_options
Ein oft übersehener Bremsklotz sind autoloadete Einträge in wp_options. Alles mit autoload = yes wird bei jedem Request geladen – unabhängig davon, ob es gebraucht wird. Wachsen hier Marketing-Transients, Debug-Flags oder Konfigurationsblöcke auf zig Megabyte, kostet schon das Einlesen CPU und Speicher. Ich senke die Last, indem ich große Daten auf autoload = no setze, Transients regelmäßig aufräume und Option-Gruppen sinnvoll entzerre. Bei Plugins, die viele get_option()-Aufrufe machen, setze ich lokale, kurzlebige In-Request-Caches ein und fasse Mehrfachzugriffe zu einem einzigen Read zusammen. Ergebnis: weniger Funktionsaufrufe, weniger Serde-Aufwand und spürbar kürzere Antwortzeiten.
Fragment- und Edge-Caching: Dynamik gezielt einkapseln
Nicht jede Seite lässt sich komplett cachen, aber Teilbereiche schon. Ich trenne statische und dynamische Fragmente: Navigation, Footer und Content landen im Page Cache, während Cart-Badges, personalisierte Boxen oder Formular-Tokens per Ajax nachgeladen werden. Alternativ setze ich Fragment-Caching im Theme oder in Plugins ein, um Berechnungskosten für wiederkehrende Blöcke zu sparen. Wichtig ist die saubere Cache-Invalidierung: Ich variiere nach relevanten Cookies, User-Rollen oder Query-Parametern, ohne die Varianz unnötig aufzublähen. Mit kurzen TTLs für sensible Bereiche und langen TTLs für stabile Inhalte erreiche ich hohe Hitraten und halte die CPU von PHP-Interpretationen fern.
admin-ajax, REST und Heartbeat: Die leise Dauerlast
Viele Sites erzeugen eine stetige Grundlast durch admin-ajax.php, REST-Endpunkte und den Heartbeat. Ich senke die Frequenz, schränke den Einsatz im Frontend ein und bündele wiederkehrende Polling-Aufgaben. Teure Admin-Listen filtere ich serverseitig effizienter, statt ungezielt große Datenmengen zu liefern. Für Live-Features setze ich enge Timeouts, Response-Caching und Debouncing. Auf diese Weise erreichen mich deutlich weniger Requests pro Minute, und die verbleibenden brauchen weniger CPU-Zeit.
Media-Pipeline: Bildverarbeitung ohne CPU-Peaks
Das Generieren vieler Thumbnails oder der Wechsel auf moderne Formate kann beim Upload CPU-Spitzen produzieren. Ich begrenze die gleichzeitige Bildverarbeitung, setze sinnvolle Maximalmaße und reduziere überflüssige Bildgrößen. Für Stapelverarbeitung verschiebe ich die Arbeit in Hintergrundjobs mit kontrollierter Parallelität. Zudem stelle ich sicher, dass Bibliotheken wie Imagick ressourcenschonend konfiguriert sind. Werden Medien an ein CDN oder Object Storage ausgelagert, entlaste ich nicht nur I/O, sondern verringere auch PHP-Workload durch direkt servierte, vorkomprimierte Assets.
PHP-FPM-Feintuning und Webserver-Zusammenspiel
Die CPU-Effizienz hängt stark am Prozessmanager: Ich wähle für PHP-FPM ein passendes pm-Modell (dynamic/ondemand), setze realistische pm.max_children gemäß RAM und typische Requestdauer und verwende pm.max_requests, um Memory-Leaks zu begegnen. Keep-Alive zwischen Webserver und FPM senkt Verbindungs-Overhead, während eine klare Trennung von statischen Assets (vom Webserver oder CDN ausgeliefert) die PHP-Worker schützt. Kompression kalkuliere ich bewusst: Statische Vorab-Komprimierung reduziert die pro-Request-CPU gegenüber On-the-fly-Kompression, während Brotli auf hohen Stufen teurer sein kann als nötig. Ziel bleibt eine niedrige TTFB ohne unnötige Rechenarbeit.
Datenbank jenseits der Indizes: Speicher und Pläne im Griff
Neben Indizes zählt die Größe des InnoDB-Pufferpools, saubere Kollationen und die Vermeidung großer temporärer Tabellen. Ich aktiviere das Slow-Query-Log, prüfe Ausführungspläne und stelle sicher, dass häufige Joins selektiv sind. Queries, die unpräzise LIKE-Suchen über große Textfelder fahren, bremsen die CPU und befüllen den I/O-Pfad. Ich ersetze sie durch präzisere Filter, Caches oder voraggregierte Tabellen. Für Berichte, Exporte und komplexe Filter verschiebe ich auf nächtliche Jobs oder eine separate Reporting-Instanz, damit Frontend-Requests schlank bleiben.
WooCommerce und andere dynamische Shops
Shops bringen besondere Dynamik: Warenkorb-Fragmente, Session-Handling und personalisierte Preise umgehen oft Page Caches. Ich deaktiviere unnötige Fragment-Refreshes auf statischen Seiten, cache Produktlisten mit klarer Invalidierung und vermeide teure Preisfilter, die komplette Tabellen scannen. Produktsuchen optimiere ich mit selektiven Queries und nutze Object Caches für wiederkehrende Katalogseiten. Für Bestandsabgleiche und Exporte setze ich Warteschlangen statt synchrone Abläufe ein. So reduziert sich die pro-Request-Arbeit und die CPU bleibt verfügbar für echte Käufer.
Cache-Invalidierung, Warmup und Hitraten
Ein guter Cache steht und fällt mit korrekter Invalidierung. Ich triggere gezielte Purges bei Post-Updates, Taxonomie-Änderungen und Menü-Edits, ohne den gesamten Cache zu leeren. Nach Deploys und großen Content-Aktualisierungen wärme ich zentrale Seiten an – Start, Kategorien, Topseller, Evergreen-Artikel. Kennzahlen wie Hitrate, Byte-Hitrate, durchschnittliche TTL und Miss-Ketten zeigen mir, ob Regeln greifen oder zu aggressiv sind. Ziel ist ein stabiler Sweet Spot: hohe Hitrate, kurze Miss-Pfade und minimale CPU-Zeit für dynamische Routen.
APM, Slowlogs und Sampling: Das richtige Mess-Setup
Ohne Messung bleibt Optimierung Zufall. Ich kombiniere Application-Logs, DB-Slowlogs und Sampling-Profiler, um Hotspots über Zeit zu erkennen. Wichtige Metriken: 95. und 99. Perzentil der PHP-Zeit, Query-Verteilung, Anteil Cache-Hits, Hintergrundjob-Dauer, sowie Fehler- und Timeout-Quoten. Anhand dieser Daten entscheide ich, ob Code refaktoriert, ein weiterer Cache eingeführt oder die Infrastruktur skaliert wird. Ich dokumentiere außerdem die Wirkung jeder Maßnahme, damit Erfolge replizierbar bleiben und Rückschritte früh auffallen.
Skalierungstests und Kapazitätsplanung
Bevor Traffic-Peaks kommen, teste ich Laststufen realistisch: zuerst warm mit Cache, dann kalt mit bewusst geleerten Schichten. Ich messe Durchsatz (Requests/s), Fehlerraten, TTFB und CPU-Auslastung je Ebene. Erkenntnis: Nicht die absolute Peak-Zahl zählt, sondern wie lange das System nahe der Sättigung stabil bleibt. Anhand der Ergebnisse plane ich Worker, Puffergrößen, Timeouts und Reservekapazitäten. Wer so vorgeht, kann Marketing-Aktionen, Sale-Starts oder TV-Erwähnungen souverän abfedern, ohne dass die CPU kollabiert.
Praxisnahe Checkpunkte, die ich selten auslasse
- Autoload-Aufräumen: große Optionsblöcke auf autoload = no, Transients begrenzen.
- Fragmentierung reduzieren: konsistente Cache-Keys, wenige Vary-Faktoren.
- Admin- und Ajax-Last: Heartbeat drosseln, Polling bündeln, Timeouts setzen.
- Bildgrößen ausmisten, Hintergrund-Resizes mit Limits ausführen.
- FPM sauber dimensionieren, Slowlog aktivieren, statische Assets nicht durch PHP.
- Datenbank: Slow-Queries fixen, Puffergrößen prüfen, temporäre Tabellen vermeiden.
- Shops: Cart-Fragmente nur wo nötig, Katalogseiten cachen, Exporte in Queues.
- Cache-Warmup nach Deploys/Flush, Hitraten und TTLs regelmäßig prüfen.
- Security: WAF/Rate-Limits, 404 kurz cachen, bekannte Angriffsflächen absichern.
- APIs: serverseitig cachen, enge Timeouts, asynchron laden, Webhooks in Queues.
Meine Zusammenfassung: So bringe ich WordPress von CPU-bound zu schnell
WordPress wird CPU-bound, weil dynamische Logik, viele Hooks, Datenbank-Ballast und fehlende Caches jeden Request aufblähen. Ich setze zuerst auf Page- und Object-Cache, räume die Datenbank auf und entschärfe WP-Cron, damit die PHP-Pipeline weniger Arbeit hat. Danach reduziere ich Plugin-Last, entschärfe API-Calls durch Timeouts und asynchrone Ladung und blocke Bots früh. Ein moderner PHP-Stack mit hoher Single-Core-Leistung, sinnvoller Worker-Anzahl und klarer Architektur trägt den Rest. Wer diese Schritte strukturiert umsetzt, senkt die Antwortzeiten messbar und hält die CPU-Last dauerhaft im Griff.

