...

WordPress Opcache: Häufige Fehlkonfigurationen und ihre Lösungen

wordpress opcache wird oft aktiviert, aber selten richtig eingestellt: Zu wenig Speicher, zu enge Dateigrenzen und falsche Timestamp-Prüfung führen direkt zu Cache-Misses und spürbaren Ladezeiten. In diesem Leitfaden zeige ich typische Fehlkonfigurationen, nenne belastbare Richtwerte und erkläre, wie du siehst, ob dein Cache arbeitet oder gerade deine CPU beschäftigt.

Zentrale Punkte

Die folgenden Kernaspekte helfen dir, Fehlkonfigurationen schnell zu erkennen und gezielt zu beheben.

  • Speicher: opcache.memory_consumption realistisch dimensionieren
  • Dateien: opcache.max_accelerated_files zur Codebasis passend setzen
  • Strings: opcache.interned_strings_buffer für WordPress erhöhen
  • Timestamps: validate_timestamps und revalidate_freq sinnvoll wählen
  • Monitoring: Hit-Rate, Restarts und Keys regelmäßig prüfen

Warum fehlerhafte Opcache-Settings WordPress ausbremsen

Mit Opcache kompiliert PHP deinen Code einmal und liefert dann Bytecode direkt aus dem Arbeitsspeicher, doch falsche Werte lassen diesen Vorteil verpuffen. Ist der Cache zu klein, überschreibt er ständig Einträge, was zu häufigen Re-Kompilierungen und Lastspitzen führt. Auch zu wenige „accelerated files“ verhindern, dass alle benötigten PHP-Dateien im Cache landen, wodurch vermeidbare Cache-Misses auftreten. Werden interned strings zu knapp bemessen, verliert WordPress bei wiederkehrenden Zeichenketten Effizienz, was besonders bei vielen Plugins ins Gewicht fällt. Ich prüfe solche Effekte über die Hit-Rate, die Anzahl gecachter Keys und über Restarts – diese drei Kennzahlen verraten sehr schnell, ob die Konfiguration trägt.

Speicher richtig dimensionieren: opcache.memory_consumption

Ich setze opcache.memory_consumption nicht blind auf 32 oder 64 MB, weil moderne WordPress-Installationen das schnell sprengen. Für kleinere Blogs starte ich mit 128 MB, für umfangreiche Seiten plane ich 256–512 MB ein, damit nicht fortlaufend Einträge verdrängt werden. Wächst die Seite, prüfe ich den freien Opcache-Speicher sowie die Restart-Zähler; steigen Restarts oder sinkt die Hit-Rate, erhöhe ich den Wert schrittweise. Ein kurzer Lasttest nach Plugin-Updates zeigt, ob der Cache ausreichend Luft hat oder bereits am Limit arbeitet. Wer neu aufsetzt, findet in dieser kompakten OPcache-Konfiguration zusätzliche Orientierungswerte, die ich dann an die tatsächliche Dateimenge anpasse.

Dateiindex korrekt ansetzen: opcache.max_accelerated_files

Mit opcache.max_accelerated_files definiere ich, wie viele PHP-Dateien der Cache verwalten darf, und setze den Wert immer oberhalb der realen Dateizahl. Die Anzahl ermittle ich serverseitig, etwa über „find . -iname „*.php“ | wc -l“, und addiere 20–30 Prozent Puffer, damit WordPress nach Updates nicht gegen diese Grenze läuft. Bleibt der Standard bei ungefähr 3000, verpasse ich Caching-Potenzial und erzeuge instabile Performance bei Last. Bei umfangreichen Installationen lande ich häufig in Bereichen wie 10.000 bis 32.500, abhängig von Plugins, Theme und Must-Use-Modulen. Ich verifiziere das Ergebnis, indem ich die Anzahl gecachter Keys mit dem Grenzwert vergleiche und die Hit-Rate unter realen Zugriffen beobachte.

Der Interned-Strings-Puffer als versteckter Flaschenhals

Den opcache.interned_strings_buffer übersehen viele, obwohl gerade WordPress stark von interned strings profitiert. Werte von 16–32 MB funktionieren in der Praxis gut, weil Themes und Plugins zahlreiche wiederkehrende Strings nutzen, die ich so effizient im Speicher halte. Bei besonders großen Setups gehe ich in Stufen auf 64 MB, wenn die Memory-Auslastung und die Strings-Statistiken darauf hindeuten. Ein zu kleiner Puffer verschenkt Validierungen, die sonst viele gleichartige Zeichenketten auf einen Speicherort zusammenführen würden. Ich kontrolliere nach der Anpassung, ob Restarts abnehmen und die allgemeine Antwortzeit bei identischem Traffic stabiler bleibt.

Timestamps verstehen: validate_timestamps und revalidate_freq

Mit opcache.validate_timestamps steuere ich, ob Opcache Dateiänderungen automatisch erkennt, was in produktiven Umgebungen mit Updates wichtig bleibt. Ich lasse validate_timestamps auf 1 und setze revalidate_freq meist auf 60 Sekunden, damit geänderte Plugins zeitnah live gehen, ohne dauernd die Festplatte zu prüfen. In Deployment-Skripten plane ich einen gezielten PHP-FPM-Reload ein, falls ich kritische Änderungen unmittelbar aktivieren möchte, um Missverständnisse zu vermeiden. Wer bei aktiven Redakteuren timestamps abschaltet, riskiert alte Artefakte und schwer zuzuordnende Fehler im Frontend. Für tiefergehende Praxisfragen zur Aussteuerung hilft mir ein Blick auf eine saubere Cache-Invalidierung, die ich pro Release wiederholbar anwende.

Monitoring, das zählt: Hit-Rate, Keys, Restarts

Ich messe den Erfolg von Opcache mit opcache_get_status(), weil Zahlen falsche Annahmen sofort entlarven. Eine Hit-Rate von mindestens 99 Prozent zeigt, dass die meisten Requests auf Bytecode treffen und nicht neu kompilieren. Steigen Restarts oder liegt die Anzahl gecachter Keys am Limit, justiere ich Speicher oder den accelerated-files-Wert. Zusätzlich beobachte ich die Memory-Fragmente, denn fragmentierter Cache-Speicher kann zu plötzlichen Leistungseinbrüchen führen. Nach Plugin-Updates prüfe ich die Kennzahlen erneut, damit der Cache konsistent performant bleibt und nicht erst unter Last aussteigt.

opcache_get_status in der Praxis: Kennzahlen lesen

Um schnell ein Gefühl für die Konfiguration zu bekommen, lese ich die wichtigsten Felder aus und vergleiche sie mit meinen Zielen:

  • opcache_statistics.hits/misses: Verhältnis bestimmt die Hit-Rate. Ziel: ≥ 99 % unter Realtraffic.
  • opcache_statistics.num_cached_scripts: Muss deutlich unterhalb opcache.max_accelerated_files bleiben.
  • memory_usage.used_memory/free_memory/wasted_memory: Zeigt, ob Speicher knapp ist oder fragmentiert.
  • opcache_statistics.oom_restarts und hash_restarts: Steigen diese, skaliere ich Speicher oder Files hoch.
  • interned_strings_usage.buffer_size/used_memory: Gibt Hinweise, ob der Strings-Puffer ausreichend dimensioniert ist.

Nützlich sind kleine Helfer, die ich auf der Shell oder in einer Admin-Route ausführe:

php -r 'var_export(opcache_get_status(false));'
php -i | grep -i opcache
php -r 'echo count(array_filter(get_included_files(), fn($f) => substr($f,-4)===".php"));'

Auf Basis dieser Zahlen entscheide ich, ob ich Speicher erhöhe, den Datei-Index erweitere oder die Revalidate-Frequenz neu takte.

Empfohlene Opcache-Werte nach Szenario

Statt pauschaler Empfehlungen passe ich Richtwerte an die Codebasis an und halte die Varianten vergleichbar. Kleine bis mittlere Seiten benötigen spürbar weniger Ressourcen als Shops mit vielen Erweiterungen. Entwicklungsumgebungen setze ich so, dass Änderungen ohne Verzögerung sichtbar werden, während ich in Produktion die Dateiprüfungen takte. Die folgende Tabelle fasst übliche Startwerte zusammen, die ich danach im Monitoring feinjustiere. Wer Wachstum plant, kalkuliert besser mit Puffer, damit Releases nicht sofort eine Neuplanung erzwingen.

Szenario opcache.memory_consumption opcache.max_accelerated_files opcache.interned_strings_buffer opcache.validate_timestamps opcache.revalidate_freq opcache.enable_cli
Klein/Mittel 128 MB 10000 16 MB 1 60 0
Groß 256–512 MB 32500 64 MB 1 60 0
Entwicklung 128–256 MB 10000–20000 16–32 MB 1 0 0

OPcache im Kontext von CLI, FPM und WP-CLI

Nicht jede Umgebung nutzt OPcache gleich, daher achte ich auf Unterschiede zwischen FPM, Apache mod_php und CLI. Für WP-CLI-Aufgaben bringt Opcache oft keinen Vorteil, weshalb ich enable_cli typischerweise auf 0 lasse. In produktiven Stacks nutze ich PHP-FPM und plane Reloads gezielt ein, damit caliente Deployments den Cache nicht unkontrolliert leeren. Cronjobs, die PHP-Skripte per CLI starten, profitieren eher von optimiertem PHP-Code und I/O, weniger vom Opcache selbst. Ich dokumentiere diese Pfade, damit Admins wissen, an welcher Stelle der Opcache greift und wo nicht.

Warmup nach Deployments: Kaltstarts vermeiden

Nach einem Release ist der Cache kalt – genau dann brechen viele Setups kurz ein. Ich plane daher ein gezieltes Warmlaufen ein:

  • Nach dem FPM-Reload rufe ich kritische Routen (Home, Produkt-/Beitragsseiten, Such-/Shop-Flows) automatisiert ab.
  • Ich nutze Sitemaps oder vordefinierte URL-Listen, um in Wellen 100–500 Seiten zu primen, statt alles auf einmal zu fluten.
  • Ich verteile Warmup-Requests über 1–2 Minuten, damit CPU-Spitzen ausbleiben und der Bytecode konsistent geladen wird.

So vermeide ich, dass echte Nutzer die Kompilierungsarbeit bezahlen. Besonders bei Shops reduziert dieser Schritt Antwortzeitspitzen unmittelbar nach Deployments.

JIT, Preloading und File Cache: Einordnung für WordPress

Weil die Begriffe oft fallen, ordne ich sie für WordPress ein:

  • JIT (opcache.jit): Für typische WP-Workloads (viel I/O, wenig numerische Hotloops) liefert JIT meist keinen messbaren Gewinn. Ich lasse JIT in Produktion bei WordPress in der Regel aus.
  • Preloading (opcache.preload): Funktioniert gut mit klaren, stabilen Frameworks. WordPress lädt Plugins und Themes dynamisch – hier ist Preloading fehleranfällig und pflegeintensiv. Ich setze es nur ein, wenn ich die Autoload-Ketten genau kontrolliere.
  • Datei-Cache (opcache.file_cache): Kann CLI-Jobs oder kurzfristige Restarts entschärfen, weil Bytecode auf Disk landet. Für FPM-first-Stacks priorisiere ich jedoch den Shared-Memory-Cache; der File-Cache ist eher eine Ergänzung für Tools und Cronjobs.

Blacklist, Sicherheit und Kontrolle

Ich halte meine Opcache-Konfiguration auch aus Sicherheits- und Stabilitätsgründen sauber:

  • opcache.restrict_api: Begrenzt, wer Opcache-Funktionen (z. B. Reset) aufrufen darf. Ich setze hier einen Pfad, unter dem nur Admin-Skripte liegen.
  • opcache.blacklist_filename: Exkludiere Dateien/Verzeichnisse, die häufig neu geschrieben werden (z. B. Code-Generatoren), um Thrashing zu verhindern.
  • opcache.save_comments=1: Muss aktiv sein, weil WP/Plugins häufig auf Docblocks/Annotations setzen. Ohne Kommentare gehen Metadaten verloren.
  • opcache.consistency_checks: Nur in Staging aktivieren, um Hash-Kollisionen oder Inkonsistenzen aufzuspüren; in Produktion kostet das merklich Leistung.
; Beispiel
opcache.restrict_api=/var/www/html/opcache-admin
opcache.blacklist_filename=/etc/php/opcache-blacklist.txt
opcache.save_comments=1

Multi-Site, mehrere Projekte und PHP-FPM-Pools

Teilen sich mehrere Sites einen FPM-Pool, „konkurrieren“ sie um denselben Opcache. Ich trenne deshalb ressourcenintensive Projekte in eigene Pools:

  • Pro Pool eigene INI-Werte; so dimensioniere ich memory_consumption exakt nach Site-Größe.
  • Kein gegenseitiges Verdrängen von Bytecode; Updates einer Site spülen nicht den Cache der anderen.
  • Bessere Fehlereingrenzung: Restarts und Hit-Rate sind pro Anwendung interpretierbar.

In Multi-Site-Setups beobachte ich zusätzlich, ob bestimmte Subsites extrem viele Dateien einbringen (Builder, WooCommerce, Page-Builder). Entsprechend passe ich den Datei-Index an und plane mehr Puffer ein.

Speicherfragmentierung im Griff behalten

Auch bei genug Gesamtspeicher kann fragmentierter Cache plötzlich Leistungseinbrüche verursachen. Ich beobachte deshalb:

  • wasted_memory und opcache.max_wasted_percentage: Wird der Schwellenwert überschritten, startet Opcache neu. Häufen sich solche Restarts, erhöhe ich Speicher und prüfe, ob bestimmte Deploys viele kleine Dateien ändern.
  • Code-Layout: Große Plugins, die häufig aktualisiert werden, verursachen mehr Fragmentierung. Ein gebündeltes Release-Fenster statt ständiger Micro-Updates hilft.
  • Huge Code Pages (opcache.huge_code_pages): Falls das System große Seiten unterstützt, kann das Fragmentierung und TLB-Misses reduzieren. Ich setze es nur, wenn die Plattform sauber dafür konfiguriert ist.

Entwicklungs- und Staging-Workflows

In Entwicklung steht Sichtbarkeit von Änderungen über maximaler Performance. Ich arbeite daher mit:

  • validate_timestamps=1 und revalidate_freq=0, damit Änderungen sofort sichtbar sind.
  • Getrennten INI-Files pro Umgebung (DEV/Stage/Prod), um versehentliche Übernahmen zu verhindern.
  • Deaktiviertem JIT und abgeschaltetem enable_cli, damit WP-CLI schnell und deterministisch bleibt.
  • Konsequent deaktivierten Debug-Extensions in Produktion (z. B. Xdebug), weil sie Caching- und Laufzeitverhalten stark verändern.

In Containern achte ich auf die Art des Mounts (z. B. Network/Bind-Mounts), weil häufige Timestamp-Änderungen sonst unnötige Revalidierungen auslösen.

Fehlerbilder sauber einordnen

Typische Symptome haben oft klare Ursachen:

  • Plötzliche 500er nach Updates: Prüfe Restarts, Fragmentierung und ob der FPM-Reload exakt nach dem Code-Swap ausgelöst wurde.
  • Inkonstante Frontends: validate_timestamps falsch oder Revalidierungsfenster zu groß gewählt.
  • Dauerhaft niedrige Hit-Rate: Datei-Index oder Speicher zu klein; gelegentlich deuten zusätzlich viele „misses“ auf sich ständig ändernde Build-Artefakte hin.
  • Langsame CLI-Jobs: enable_cli=0 ist meist korrekt; hier hilft optimierter Code oder der Datei-Cache, nicht der SHM-Opcache.

Quick-Checkliste für die ersten 30 Minuten

  • PHP-Dateien zählen und max_accelerated_files mit 20–30 % Puffer setzen.
  • memory_consumption auf 128–512 MB je nach Site-Größe einstellen; Strings-Puffer auf 16–64 MB.
  • validate_timestamps=1 und revalidate_freq auf 60 in Produktion.
  • Nach Deploy: FPM-Reload, Warmup-Routen anstoßen, dann opcache_get_status() prüfen.
  • Restarts, Hit-Rate und wasted_memory beobachten; bei Auffälligkeiten gezielt nachjustieren.
  • Security: restrict_api setzen, save_comments=1 sicherstellen, problematische Pfade ggf. blacklisten.
  • Optional: Separate FPM-Pools für große Sites, damit sich Caches nicht gegenseitig verdrängen.

Fehlerbehebung mit System: Von Symptomen zu Ursachen

Ich starte die Analyse immer mit Kennzahlen: Sinkt die Hit-Rate, wachsen Restarts oder liegen Keys am Limit, leite ich gezielte Schritte ab. Ist der Cache voll, erhöhe ich memory_consumption, erreiche ich die Dateigrenze, vergrößere ich max_accelerated_files. Sehe ich widersprüchliche Frontend-Stände nach Deployments, kontrolliere ich validate_timestamps und den Zeitpunkt eines FPM-Reloads. Tauchen sporadische 500er auf, prüfe ich fragmentierten Cache und konsumiere Error-Logs, bevor ich an der Konfiguration drehe. Nach jeder Änderung messe ich erneut, bis Kennzahlen und Ladezeiten konsistent zueinander passen.

Knappe Zusammenfassung

Eine starke WordPress-Performance beginnt mit einem ausreichend großen Opcache, passenden Grenzen für accelerated files und einem sinnvoll gewählten interned-strings-Puffer. In Produktion lasse ich timestamps aktiv, takte die Prüfung und setze für Releases kontrollierte Reloads, damit Änderungen rechtzeitig live sind. Ich verlasse mich auf Metriken wie Hit-Rate, Restarts und Keys, weil sie mir objektiv zeigen, welche Stellschraube ich drehen muss. Werte aus einer Tabelle sind Startpunkte, doch das Monitoring entscheidet, wie ich sie pro Site anpasse. Wer diese Disziplin beibehält, holt verlässlich kurze Antwortzeiten aus PHP heraus und hält die CPU auch bei Trafficspitzen entspannt.

Aktuelle Artikel