Warum WordPress ohne Opcode Cache kaum performant betrieben werden kann

Opcode Cache WordPress entscheidet, ob deine Site PHP bei jedem Aufruf neu übersetzt oder direkt aus dem RAM startet. Ich zeige, warum fehlender OPcache die CPU belastet, die TTFB erhöht und Skalierung stark begrenzt.

Zentrale Punkte

Bevor ich ins Detail gehe, fasse ich die wichtigsten Erkenntnisse kurz und klar zusammen, damit du direkt die Leistungshebel kennst. Ohne OPcache kompiliert PHP bei jedem Request erneut, was Wartezeit und Ressourcen verschwendet und Seiten reaktionsarm macht. Mit aktiviertem OPcache laufen Bytecode und Codepfade aus dem Speicher, wodurch Anfragen schneller zurückkehren und Lastspitzen seltener eskalieren. In Kombination mit Page- und Object‑Caching steigert OPcache die Effizienz und bringt die nötige Ruhe im Unterbau. Richtig konfiguriert, erhöht OPcache die tragbare Nutzerzahl pro Serverkern spürbar und senkt die Fehlerquote bei Peaks. Diese Punkte steuern den Unterschied zwischen einem zähen System und einer schnellen Installation mit verlässlicher Performance.

  • OPcache spart Kompilierzeit und stabilisiert TTFB.
  • CPU-Last sinkt, Kapazität pro Kern steigt.
  • Skalierung gelingt, Peaks bleiben beherrschbar.
  • PHP 8+ bringt zusätzliche Leistung.
  • Monitoring hält Hit‑Rate und Speicher im Blick.

Warum WordPress ohne Opcode Cache bremst

WordPress lädt bei jedem Seitenaufruf viele PHP‑Dateien, die ohne OPcache jedes Mal geparst, in einen Syntaxbaum überführt und neu zu Bytecode kompiliert werden, was die Rechenzeit unnötig verlängert. Ich sehe in Audits regelmäßig doppelte bis dreifache Ausführungszeiten, weil die gleichen Routinen pro Request komplett von vorn starten und damit Wärmelast auf der CPU erzeugen. Diese Wiederholung blockiert FPM‑Worker, verschiebt Antworten nach hinten und lässt TTFB sprunghaft steigen. Unter gleichzeitigen Zugriffen fällt die Durchsatzrate ab, während die Fehlerquote (502/504) in Peaks hochgeht. Je mehr Plugins und heavy Themes beteiligt sind, desto stärker spürt man die Kosten jedes einzelnen Uncaches.

So arbeitet OPcache im Detail

OPcache speichert den kompilierten PHP‑Bytecode im gemeinsamen Speicher und liefert bei unveränderten Timestamps denselben Code direkt aus dem RAM, wodurch Disk-Zugriffe und erneutes Kompilieren entfallen. Ich profitiere davon, dass Parser und Compiler‑Schritte wegfallen und die Engine nur noch ausführen muss, was bereits als Bytecode vorliegt. Das Verhalten reduziert Systemaufruhr pro Request erheblich und stabilisiert Antwortzeiten auch unter Last. Bei WordPress installiere ich OPcache deshalb als erste Maßnahme, bevor ich an Objekt‑ oder Seiten‑Caching gehe. Die Einsparung fällt über viele kleine Dateien hinweg zusammen und macht den Unterschied zwischen knapper und entspannter Serverlast.

Messbare Effekte: TTFB, CPU und Kapazität

Mit aktiviertem OPcache sehe ich oft bis zu dreifach kürzere Ausführungszeiten für wiederholte Requests, was die TTFB spürbar drückt und das Zeitbudget für Rendering erhöht. Gleichzeitig sinkt die CPU‑Nutzung in typischen WordPress‑Workloads um 50–80 %, weil Kompilierarbeit entfällt und Worker schneller frei werden. Das Ergebnis ist eine höhere Zahl bedienbarer paralleler Nutzer bei identischer Hardware und weniger Ausreißer im P95/P99‑Bereich. Für Marketing‑Aktionen oder saisonale Peaks bedeutet das: weniger Abbrüche, mehr abgeschlossene Warenkörbe und stabilere Rankings. Diese Effekte addieren sich, sobald auch Page‑ und Objekt‑Caching eingebunden sind, doch ohne OPcache bleibt die Basis ineffizient und die darüberliegenden Schichten geraten schneller ins Wanken.

OPcache und andere Caches im Zusammenspiel

Damit du die Rollen klar trennst, stelle ich die Ebenen gegenüber und zeige, wie sie sich ergänzen, aber nicht ersetzen: OPcache beschleunigt Codeausführung, während Page/Object Caches Inhalte und Datenzugriffe entschärfen; erst zusammen erreichen Sites ihr volles Tempo. Ich beginne mit OPcache, weil es jeden PHP‑Pfad beschleunigt und den Druck von der CPU nimmt. Danach nutze ich Page‑Caching, um wiederkehrende Seiten direkt auszuliefern, und Object‑Caching, um Abfragen gegen die Datenbank zu reduzieren. Fehlt die untere Schicht, können die oberen Ebenen Lastsprünge nicht ausreichend kompensieren. Die folgende Tabelle gibt eine schnelle Orientierung für Auswahl und Erwartung.

Caching‑Typ Wo gespeichert Nutzen für WordPress Typischer Gewinn
OPcache Server‑RAM Speichert PHP‑Bytecode, spart Parsing/Kompilieren bis zu 3× kürzere Ausführungszeit
Object Cache Redis/Memcached Hält Ergebnismengen von DB‑Abfragen spürbar weniger DB‑Last
Page Cache Disk/Proxy/CDN Liefert fertiges HTML für Gäste nahezu sofortige Responses

Optimale OPcache‑Einstellungen für WordPress

Ich setze OPcache grundsätzlich auf enable=1, dimensioniere den Speicher großzügig (128–512 MB je nach Plugin‑Landschaft) und erhöhe max_accelerated_files, damit der Index vollständig bleibt und die Trefferquote nicht verschlechtert. In Produktion deaktiviere ich automatische Timestamp‑Prüfungen oder senke die Frequenz, damit der Cache nicht unnötig invalidiert, und plane kontrollierte Clears ein. Für große Sites zahlt sich ein dedicated Memory‑Pool aus, der keine Out‑of‑Memory‑Events produziert und so die JIT‑Leistung nicht beeinträchtigt. Ich prüfe regelmäßig die Hit‑Rate (>95 %), den freien Shared‑Memory und verwaiste Einträge, damit der Cache gesund bleibt. Für Details zur systematischen Einrichtung lohnt ein Blick in meine OPcache-Konfiguration, die in wenigen Schritten zu stabilen Zeiten führt und die Konstanz der Responses stärkt.

Preloading und JIT: Nutzen und Grenzen

PHP unterstützt seit 7.4 das Preloading, bei dem ausgewählte Dateien bereits im Master‑Prozess geladen und in den Speicher gelegt werden. In klassischen WordPress‑Setups bringt das jedoch nur überschaubaren Mehrwert, weil Core und viele Plugins stark dynamisch laden und die Codepfade je nach Route variieren. Sinnvoll ist Preloading vor allem in homogenen, frameworklastigen Projekten mit klaren Hot‑Paths. Falls du es testen möchtest, halte die Preload‑Liste klein, stabil und versionsfest und beachte, dass ein FPM‑Reload das Preload‑Set neu aufbaut.

Beim JIT beobachte ich in Content‑Workloads keinen spürbaren Vorteil. Viele WordPress‑Anfragen sind I/O‑ und Template‑getrieben, nicht numerisch schwer. Ein aggressiver JIT‑Modus verbraucht Shared‑Memory, der dem OPcache fehlt. Ich fahre in Produktion konservativ: JIT aus oder auf moderatem Level, damit der Bytecode‑Cache maximalen Raum hat.

; Auszug php.ini – konservative, WP‑taugliche Einstellungen
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=100000
opcache.validate_timestamps=0
opcache.revalidate_freq=60
opcache.save_comments=1

; JIT reduziert oder deaktiviert
opcache.jit=0
; Alternativ moderat:
; opcache.jit=1205

; Optionales Preloading (nur wenn kuratiert)
; opcache.preload=/var/www/preload.php
; opcache.preload_user=www-data

Fehlkonfigurationen erkennen und beheben

Viele Installationen leiden unter einem zu kleinen Memory‑Pool, zu wenigen accelerated_files oder aggressiver Timestamp‑Validierung, was die Wirkung von OPcache deutlich schmälert. Ich analysiere phpinfo(), beobachte Statistiken der Caching‑Engine und gleiche sie mit realen Deployments ab, um Lecks und Thrash‑Verhalten zu finden. Wachsen Plugin‑Sets oder Themes, muss der Cache mitziehen, sonst kippt die Hit‑Rate und Ausführungszeiten driften nach oben. Ich nutze klare Grenzwerte: kein OOM im Tagesverlauf, Hit‑Rate nah 100 %, revalidate_freq im Sekunden‑ statt Millisekunden‑Bereich. Eine strukturierte Checkliste findest du in meiner Anleitung Fehlkonfigurationen optimieren, die typische Stolpersteine entschärft und die Stabilität sichert.

Invalidierungen und Deployments ohne Leistungseinbruch

Ein häufiger Fehler ist das vollständige Leeren des Caches nach jedem kleinen Update, wodurch Ladezeiten kurzfristig explodieren und die User Verzögerungen spüren. Ich plane daher kontrollierte Invalidierungen auf Dateiebene, rolle Releases in Randzeiten aus und lasse Warm‑Up‑Prozesse laufen. Für CI/CD setze ich Preloading‑Skripte ein, die kritische Routen vorab ausführen und Bytecode in den Speicher laden, bevor Traffic ankommt. So vermeide ich Performance‑Spitzen und halte die Page‑Speed‑Metriken über Deployments stabil. Die wichtigsten Taktiken fasse ich in meinem Beitrag zur OPcache-Invalidierung zusammen, damit Releases sanft und ohne Kollateralschäden ablaufen.

Dateisystem, Pfade und Realpath‑Cache

Viele Probleme entstehen nicht im OPcache selbst, sondern im Zusammenspiel mit dem Dateisystem. Unterschiedliche Pfade auf dieselbe Datei (z. B. via Symlinks, Chroots oder mehrere Mount‑Punkte) können Duplikate erzeugen und den Index aufblähen. Ich achte deshalb auf konsistente Include‑Pfade und nutze die Defaults opcache.use_cwd=1 und revalidate_path=0, damit Dateien eindeutig bleiben. In Multi‑Tenant‑Umgebungen sichere ich die Isolation zusätzlich mit validate_permission=1 und validate_root=1 ab, sodass keine Quersicht auf fremde Pfade entsteht. Auf NFS‑Shares reduziere ich die Prüffrequenz und deploye atomar (Release‑Symlink), damit Timestamp‑Drift keine Thrash‑Invalidierungen auslöst.

Eine oft vergessene Stellschraube ist der Realpath‑Cache von PHP. Er speichert die Auflösung von Pfaden und reduziert teure stat‑Aufrufe pro Request. Für größere WP‑Installationen stelle ich ihn höher ein, damit häufige Pfade nicht ständig neu berechnet werden.

; Pfad‑Auflösung beschleunigen
realpath_cache_size=1M
realpath_cache_ttl=600

Multisite, MU‑Plugins und Composer‑Strukturen

WordPress‑Multisite, umfangreiche MU‑Plugins und Composer‑basierte Setups bringen viele kleine Dateien ins Spiel. Damit der Index vollständig bleibt, erhöhe ich max_accelerated_files frühzeitig (80–200 k, je nach Umfang) und gebe dem Shared‑Memory Reserven. Achte darauf, dass identische Dateien nicht über verschiedene Pfade eingebunden werden (z. B. wechselnde Symlink‑Basen), sonst landet derselbe Bytecode mehrfach im Cache. Dynamisch generierte PHP‑Dateien meide ich in Produktion; wenn sie unvermeidbar sind, schirme ich sie mit stabilen Timestamps oder Blacklists ab, damit kein permanentes Re‑Kompilieren ausgelöst wird. Composer‑Autoloads sind unkritisch, aber zahlreich – hier zahlt ein großzügiger Index direkt auf die Hit‑Rate ein.

Hosting‑Einfluss: PHP‑Version, FPM‑Worker und RAM

Mit PHP 8.0+ bekomme ich bereits einen spürbaren Schub gegenüber 7.4, und neuere Versionen wie 8.5 legen nochmals deutlich zu, wodurch die Baseline für OPcache‑Gewinne steigt. Ich aktiviere ausreichend FPM‑Worker, aber nicht mehr als der Server real bedienen kann, damit Kontextwechsel und Swap‑Risiken gering bleiben. Der Shared‑Memory für OPcache braucht Reserven, die Wachstum abfedern und keinen ständigen Eviction‑Druck erzeugen. Auf Shared‑Plänen mit guter Grundeinstellung läuft WordPress oft flüssiger als auf ungetunten VPS‑Instanzen, weil der Bytecode‑Cache sauber dimensioniert ist. Entscheidend ist ein harmonisches Set‑up aus Version, Prozessanzahl und RAM, das zur tatsächlichen Last passt.

CLI, WP‑Cron und Hintergrundjobs

Neben FPM laufen viele WordPress‑Aufgaben über CLI: WP‑Cron, Indexer, Bildverarbeitung, Imports oder WP‑CLI‑Befehle. Standardmäßig ist OPcache für CLI deaktiviert, wodurch wiederkehrende Jobs jedes Mal neu kompilieren. Auf Servern mit häufigen CLI‑Runs aktiviere ich OPcache für die CLI und ergänze eine File‑Cache‑Ablage. So können Bytecode‑Artefakte zwischen CLI‑Aufrufen wiederverwendet werden und wiederholte Tasks beschleunigen spürbar.

; OPcache auch für CLI‑Jobs sinnvoll nutzen
opcache.enable_cli=1
opcache.file_cache=/var/cache/php/opcache
opcache.file_cache_only=0
opcache.file_cache_consistency_checks=1

Wichtig: Der CLI‑Cache ist getrennt vom FPM‑Cache – er entlastet Hintergrundjobs, ersetzt aber kein Warm‑up des FPM‑Pools. Für stark belegte Cron‑Fenster plane ich zusätzlich kurze Warm‑Up‑Skripte, damit FPM‑Worker mit heißem Bytecode in die Schicht starten und Spitze‑an‑Spitze‑Effekte ausbleiben.

Container, Orchestrierung und Rolling‑Deploys

In Docker‑ und Kubernetes‑Umgebungen werden Pods häufig neu gestartet oder horizontal skaliert. Jeder neue FPM‑Master startet mit leerem SHM‑Segment – ohne Warm‑up führen erste Live‑Requests dann den Kaltstart durch. Ich nutze deshalb Init‑Container oder PreStart‑Hooks, die kritische Routen und Admin‑Flows einmal „vorklicken“. Readiness‑Probes schalte ich erst scharf, wenn die Hot‑Paths im OPcache liegen. Bei Rolling‑Deploys mit Symlink‑Releases invaldiere ich selektiv, lasse den alten Pool kontrolliert auslaufen und leite Traffic erst dann auf die neue Revision, wenn Warm‑up und Health‑Checks grün sind. In kurzlebigen Containern kann zusätzlich ein opcache.file_cache die Cold‑Start‑Zeiten weiter drücken.

Praxisbeispiele und gesunde Richtwerte

Auf einer mittleren WooCommerce‑Site mit vielen Shortcodes halbierte OPcache die CPU‑Spitzen und verdoppelte die tragbare Anzahl gleichzeitiger Sessions, was spürbar mehr Umsatz in Peak‑Phasen ermöglichte. Ein Content‑Portal mit Page‑Cache, aber ohne OPcache, zeigte weiterhin hohe TTFB, bis der Bytecode‑Cache die Parse‑Last beseitigte. Blogs mit Block‑Editor profitieren ähnlich, da viele kleine PHP‑Dateien beteiligt sind und der Memory‑Index die Wiederholungsarbeit eliminiert. Realistisch plane ich für kleine Sites 128–192 MB und für große Set‑ups 256–512 MB Shared‑Memory, je nach Anzahl Dateien. Wer diese Richtwerte beachtet und die Statistiken prüft, hält Antwortzeiten verlässlich niedrig und senkt Risiko und Kosten.

Monitoring und Verifizierung im Alltag

Ich verlasse mich nicht auf Bauchgefühl, sondern prüfe regelmäßig die OPcache‑Metriken und setze sie in Bezug zu realen Latenzen. Neben der Hit‑Rate interessieren mich used_memory, free_memory, wasted_memory sowie die Nutzung der interned_strings. Bleiben free_memory und die Anzahl freier Hash‑Slots konstant hoch, ist das Set‑up gesund. Steigt wasted_memory dauerhaft, räume ich auf (geplante Resets) oder erhöhe den Pool.

<?php
$status = opcache_get_status(false);
$mem = $status['memory_usage'];
$stats = $status['opcache_statistics'];
printf(
  "Hit-Rate: %.2f%%\nUsed: %.1f MB, Free: %.1f MB, Wasted: %.1f MB\nCached Scripts: %d\n",
  $stats['opcache_hit_rate'],
  $mem['used_memory']/1048576,
  $mem['free_memory']/1048576,
  $mem['wasted_memory']/1048576,
  $stats['num_cached_scripts']
);
?>

Parallel messe ich TTFB, P95/P99 und Apdex getrennt für Gäste und eingeloggte Nutzer. Wenn OPcache korrekt arbeitet, stabilisieren sich die Kurven nach einem Warm‑up, während Peaks deutlich flacher ausfallen. Weichen Metriken und OPcache‑Status voneinander ab (z. B. hohe Hit‑Rate, aber schlechte TTFB), suche ich als Nächstes bei DB‑Abfragen, Netzwerk, Storage oder blockierenden externen Diensten.

Schritt‑für‑Schritt zur schnellen WP‑Instanz

Ich starte mit einem Upgrade auf PHP 8.x, aktiviere OPcache und stelle sicher, dass memory_consumption und max_accelerated_files zum Projekt passen und keine OOM‑Einträge auftauchen. Danach kalibriere ich validate_timestamps und revalidate_freq passend zur Deployment‑Praxis, um unnötige Invalidierungen zu vermeiden und den Durchsatz zu sichern. Im Anschluss messe ich TTFB, Apdex und P95‑Latenzen im eingeloggten und Gast‑Kontext, um echte Fortschritte zu belegen. Erst dann ergänze ich Object‑Cache (z. B. Redis) und Page‑Cache, damit Datenbank und HTML‑Auslieferung entlastet werden. Mit diesem Fahrplan setze ich eine solide Baseline und hebe darauf die restliche Performance an.

Kurz zusammengefasst

Ohne OPcache zwingt WordPress jeden Request, den Code neu zu parsen und zu kompilieren, wodurch TTFB steigt, Worker blockieren und die Kapazität schrumpft. Mit aktivem Bytecode‑Cache spare ich genau diese Arbeit, senke CPU‑Last deutlich und gewinne Reserven für Peaks. In Tests beschleunigt OPcache wiederholte Aufrufe bis um den Faktor drei, während PHP 8.x zusätzlich Tempo bringt und die Grundlast senkt. Mit sauberer Konfiguration, sorgfältiger Invalidierung und Monitoring bleibt die Hit‑Rate hoch und der Shared‑Memory frei von Engpässen. Wer diese Schritte konsequent geht, betreibt WordPress spürbar schneller, stabiler und wirtschaftlicher.

Aktuelle Artikel