Realpath-Cache in PHP optimieren: weniger Stat-Calls, schnellere Includes
AI generated
<?php
8.4
PHP · Realpath Cache · Dateisystem · Performance
Realpath-Cache in PHP optimieren
Weniger Stat-Calls, spürbar schnellere Includes

Jeder require, jedes include und jede Autoloader-Auflösung durchläuft in PHP eine Pfadauflösung, die ohne ausreichend dimensionierten Realpath-Cache bei jedem einzelnen Request erneut Dateisystemzugriffe erzeugt. Gerade bei Projekten mit tausenden Klassen und tiefen Verzeichnisbäumen summiert sich das zu einem Overhead, der sich mit wenigen Zeilen Konfiguration fast vollständig eliminieren lässt.

13 Min. Lesezeit realpath_cache_size · realpath_cache_ttl PHP 8.x

1. Was der Realpath-Cache ist und welches Problem er löst

Der Realpath-Cache ist ein interner Cache der Zend Engine, der aufgelöste, absolute Dateipfade zusammen mit Informationen über Existenz, Typ und Zieldatei hinter Symlinks speichert. Immer wenn PHP einen relativen Pfad, einen Pfad mit ..-Segmenten oder einen Symlink in einen kanonischen, absoluten Pfad umwandeln muss, etwa bei jedem require, include oder jeder Autoloader-Auflösung, prüft die Engine zuerst diesen Cache, bevor sie das Dateisystem tatsächlich befragt.

Ohne diesen Cache müsste PHP bei jeder einzelnen Pfadauflösung einen oder mehrere stat()-Systemaufrufe an das Betriebssystem schicken, und zwar für jedes Segment eines Verzeichnispfads einzeln, um dessen Existenz und Typ zu prüfen. Bei einem tief verschachtelten Namespace-Pfad wie vendor/magento/module-catalog/Model/ResourceModel/Product.php bedeutet das potenziell sieben oder acht einzelne Systemaufrufe für eine einzige Klassendatei, und das bei jedem Request erneut, wenn der Realpath-Cache zu klein dimensioniert ist oder zu früh verfällt.

Der Realpath-Cache setzt genau hier an: Ist ein Pfad einmal aufgelöst und im Cache abgelegt, liefert PHP das Ergebnis bei jeder weiteren Anfrage innerhalb der konfigurierten Gültigkeitsdauer direkt aus dem Speicher zurück, ohne erneuten Kontakt zum Dateisystem. Bei Projekten mit vielen Klassen und tiefen Verzeichnisstrukturen, wie sie in Magento oder Symfony typisch sind, macht ein korrekt dimensionierter Realpath-Cache den Unterschied zwischen tausenden unnötigen Systemaufrufen pro Request und praktisch keinem.

2. Wie PHP Dateipfade ohne ausreichenden Cache auflöst

Um zu verstehen, warum der Realpath-Cache so wirkungsvoll ist, hilft ein Blick auf den Ablauf ohne ihn. Für jeden Pfad, der aufgelöst werden muss, arbeitet PHP das Dateisystem Segment für Segment ab: Für /var/www/html/vendor/foo/bar/Baz.php wird zunächst geprüft, ob /var/www existiert und ein Verzeichnis ist, dann /var/www/html, dann /var/www/html/vendor, und so weiter, bis der vollständige Pfad aufgelöst ist. Jede dieser Prüfungen ist ein separater Systemaufruf mit einem Kontextwechsel zwischen PHP-Prozess und Betriebssystemkern.

Symlinks verkomplizieren diesen Ablauf zusätzlich, weil jeder Symlink im Pfad selbst aufgelöst werden muss, was theoretisch weitere Dateisystemzugriffe für das Ziel des Symlinks nach sich zieht. In containerisierten Umgebungen mit gemounteten Volumes oder Overlay-Dateisystemen sind diese Systemaufrufe zusätzlich oft langsamer als auf einem lokalen Dateisystem ohne Virtualisierungsschicht, was den Effekt eines fehlenden oder zu kleinen Realpath-Cache in Docker-Umgebungen besonders spürbar macht.


declare(strict_types=1);

// Without an effective realpath cache, resolving this path repeatedly
// triggers multiple filesystem stat() calls per request
$path = __DIR__ . '/../../vendor/magento/module-catalog/Model/Product.php';

$start = hrtime(true);
$resolved = realpath($path);
$elapsed = (hrtime(true) - $start) / 1_000_000;

printf("Resolved: %s (%.4f ms)\n", $resolved, $elapsed);

// Inspect current cache usage right after resolution
$info = realpath_cache_size();
printf("Realpath cache currently uses %d bytes\n", $info);

3. realpath_cache_size und realpath_cache_ttl konfigurieren

Zwei Direktiven in der php.ini steuern den Realpath-Cache direkt: realpath_cache_size legt fest, wie viel Speicher für gecachte Pfadeinträge insgesamt zur Verfügung steht, standardmäßig oft nur 4096K, also vier Megabyte. Bei umfangreichen Projekten mit vielen tausend Dateien reicht dieser Standardwert häufig nicht aus, der Cache läuft voll, ältere Einträge werden verdrängt, und die eigentlich vermiedenen Dateisystemzugriffe treten wieder auf.

realpath_cache_ttl bestimmt, wie lange ein einmal aufgelöster Pfad im Cache gültig bleibt, bevor er erneut gegen das Dateisystem geprüft wird, standardmäßig 120 Sekunden. Für produktive Umgebungen mit stabilem Deployment-Prozess, bei dem sich Dateipfade zwischen Deployments nicht während der Laufzeit ändern, lohnt sich eine deutliche Anhebung dieses Werts, weil ein häufiges Verfallen des Caches in Produktion keinen praktischen Nutzen bringt, aber unnötige Systemaufrufe verursacht.


; php.ini — realpath cache tuning for a large, stable production project
; Default is often only 4096K, far too small for projects with
; thousands of classes across deep vendor/ directory trees
realpath_cache_size = 16M

; Default TTL is 120 seconds — for stable production deployments
; where paths never change between deploys, a longer TTL avoids
; unnecessary re-validation against the filesystem
realpath_cache_ttl = 600

; Combine with an aggressive OPcache configuration for maximum effect
opcache.validate_timestamps = 0

Ein Wert von 16M für realpath_cache_size genügt für die allermeisten Projekte, selbst mit mehreren zehntausend Dateien im Vendor-Verzeichnis. Wichtig: Der Wert wird als Zeichenkette mit Einheit angegeben, 16M für Megabyte, eine reine Zahl wird als Bytes interpretiert, was ein häufiger Konfigurationsfehler ist und den Realpath-Cache faktisch wirkungslos macht.

4. Zusammenspiel mit OPcache und Composer-Autoloading

Der Realpath-Cache arbeitet eng mit OPcache zusammen, löst aber ein anderes Problem: OPcache cacht kompilierten Bytecode für eine Datei, sobald deren Pfad bekannt ist, während der Realpath-Cache genau diese Pfadauflösung selbst beschleunigt, bevor OPcache überhaupt greifen kann. Ist opcache.validate_timestamps deaktiviert, verlässt sich OPcache vollständig auf einmal aufgelöste Pfade, wodurch ein ausreichend dimensionierter Realpath-Cache noch wichtiger wird, weil er als erste Stufe der Pfadauflösung fungiert.

Composer-Autoloading profitiert besonders stark vom Realpath-Cache, weil der generierte Klassen-Autoloader bei jeder unbekannten Klasse eine Pfadauflösung durchführt, entweder direkt über die Classmap oder über die PSR-4-Präfix-Auflösung mit anschließendem file_exists()-Check. Bei einem typischen Magento- oder Symfony-Request, der hunderte Klassen lädt, summieren sich diese Auflösungen schnell zu einer dreistelligen Zahl an Pfadprüfungen, die mit einem funktionierenden Realpath-Cache fast vollständig aus dem Speicher bedient werden, statt das Dateisystem zu belasten.


declare(strict_types=1);

// Simulate a Composer-style classmap lookup with realpath caching in effect
final class ClassResolutionBenchmark
{
    /**
     * Resolve a batch of class file paths and report cache effectiveness.
     *
     * @param array<int, string> $relativePaths
     * @return void
     */
    public static function run(array $relativePaths): void
    {
        $before = realpath_cache_size();

        foreach ($relativePaths as $path) {
            realpath($path); // triggers cache lookup or filesystem stat
        }

        $after = realpath_cache_size();
        printf("Cache grew by %d bytes for %d paths\n", $after - $before, count($relativePaths));
    }
}

5. Cache-Auslastung selbst messen und beobachten

PHP stellt zwei Funktionen bereit, um den aktuellen Zustand des Realpath-Cache direkt zu inspizieren: realpath_cache_size() liefert die aktuell belegte Speichermenge in Bytes, realpath_cache_get() liefert ein Array mit allen aktuell gecachten Pfaden inklusive ihrer aufgelösten Zielpfade und dem Zeitpunkt der letzten Aktualisierung. Diese Funktionen eignen sich hervorragend, um während der Entwicklung zu prüfen, ob der konfigurierte realpath_cache_size-Wert für das eigene Projekt tatsächlich ausreicht.

Ein praktischer Test: Nähert sich realpath_cache_size() am Ende eines typischen, komplexen Requests dem konfigurierten Maximum an, ist der Cache zu klein dimensioniert und sollte erhöht werden. Bleibt die belegte Größe deutlich unter dem Maximum, ist die Konfiguration ausreichend, und eine weitere Erhöhung bringt keinen zusätzlichen Nutzen mehr, kostet aber unnötig Arbeitsspeicher pro PHP-Worker-Prozess, was bei vielen parallelen Workern durchaus relevant werden kann.

Für kontinuierliches Monitoring in Produktion eignet sich ein einfacher Health-Check-Endpunkt, der periodisch realpath_cache_size() gegen den konfigurierten Grenzwert prüft und bei nahezu voller Auslastung eine Warnung auslöst, bevor tatsächlich Performance-Probleme durch Cache-Verdrängung auftreten.

6. Docker, Symlinks und Container-Besonderheiten

In containerisierten Umgebungen mit gemounteten Bind-Mounts oder Overlay-Dateisystemen, wie sie beim lokalen Entwickeln mit Docker häufig vorkommen, sind Dateisystemzugriffe grundsätzlich langsamer als auf einem nativen Dateisystem, weil jeder Zugriff zusätzlich durch die Virtualisierungsschicht des Hosts läuft. Genau in diesem Szenario zeigt ein korrekt dimensionierter Realpath-Cache besonders deutliche Effekte, weil jeder vermiedene Dateisystemzugriff überproportional viel Zeit spart im Vergleich zu einem nativen Linux-Dateisystem.

Symlinks, wie sie Composer für manche Paketinstallationen oder Entwickler für lokale Paket-Overrides via path-Repository nutzen, erhöhen die Zahl der notwendigen Auflösungsschritte zusätzlich, weil jeder Symlink selbst aufgelöst werden muss, bevor der eigentliche Zielpfad feststeht. Der Realpath-Cache speichert dabei sowohl den Symlink-Pfad als auch den aufgelösten Zielpfad, sodass wiederholte Zugriffe über denselben Symlink ebenfalls beschleunigt werden, sobald der erste Zugriff die vollständige Kette einmal aufgelöst hat.

7. Deployment-Strategien ohne Cache-Invalidierungsprobleme

Ein lang gültiger Realpath-Cache mit hohem realpath_cache_ttl kann bei bestimmten Deployment-Strategien zu Problemen führen, insbesondere bei symlink-basierten Deployments, bei denen ein current-Symlink nach jedem Release auf ein neues Release-Verzeichnis umgebogen wird. Verbleibt der alte, aufgelöste Pfad im Realpath-Cache eines bereits laufenden PHP-FPM-Worker-Prozesses, liefert dieser Worker unter Umständen noch für die Dauer des konfigurierten TTL Code aus dem alten Release, während neue Worker bereits das neue Release verwenden.

Die zuverlässige Lösung dafür ist ein vollständiger PHP-FPM-Reload nach jedem Deployment, der alle Worker-Prozesse neu startet und damit auch deren Realpath-Cache und OPcache vollständig zurücksetzt. Ein reiner Cache-Flush über Signale reicht bei symlink-basierten Deployments oft nicht aus, weil der Realpath-Cache selbst kein explizites Flush-Kommando kennt und ausschließlich über TTL-Ablauf oder Prozessneustart geleert wird.

8. Typische Fallstricke und Fehlkonfigurationen

Der häufigste Fehler ist, den Realpath-Cache schlicht auf dem viel zu niedrigen Standardwert zu belassen, obwohl das eigene Projekt tausende Dateien im Vendor-Verzeichnis hat. Ein zu kleiner Cache verdrängt ältere Einträge, sobald neue Pfade hinzukommen, was bei zyklischen Zugriffsmustern zu ständigem Neuaufbau führt, der Cache also praktisch wirkungslos bleibt, obwohl er aktiv konfiguriert ist.


#!/usr/bin/env bash
# Quick diagnostic: check the currently configured realpath cache settings
php -i | grep -i realpath

# realpath_cache_size => 4096K => 4096K    (too small for large projects)
# realpath_cache_ttl => 120 => 120         (fine for dev, low for stable prod)

# Verify actual usage from within a running application context
php -r 'var_dump(realpath_cache_size());'

Ein zweiter Fallstrick betrifft Entwicklungsumgebungen: Ein sehr hoher realpath_cache_ttl-Wert in der lokalen Entwicklung führt dazu, dass neu angelegte Dateien nicht sofort gefunden werden, weil ein zuvor als nicht existent gecachtes Ergebnis noch gültig ist. Für die lokale Entwicklung sollte der Standardwert von 120 Sekunden beibehalten oder sogar reduziert werden, die Erhöhung lohnt sich ausschließlich für stabile Produktionsumgebungen mit unveränderlichem Deployment.

9. Konfigurationen im direkten Vergleich

Ein direkter Vergleich typischer Konfigurationen zeigt, welche Einstellungen für welches Szenario passen.

Szenario realpath_cache_size realpath_cache_ttl Empfehlung
Standard-Installation 4096K 120 Zu klein für große Projekte
Lokale Entwicklung 8M 120 Neue Dateien schnell sichtbar
Stabile Produktion 16M 600 Maximale Wiederverwendung
Docker mit Bind-Mount 16M 600 Besonders wirksam wegen Overlay-FS

Der Vergleich zeigt: Für Produktionsumgebungen lohnt sich fast immer eine deutliche Erhöhung beider Werte gegenüber dem Standard, während in der lokalen Entwicklung ein moderater Kompromiss zwischen Performance und sofortiger Sichtbarkeit neuer Dateien sinnvoller ist.

Mironsoft

PHP Performance-Tuning, OPcache und Realpath-Cache-Konfiguration

Unnötige Dateisystemzugriffe in eurer PHP-Anwendung finden?

Wir analysieren Autoloading- und Include-Verhalten in großen Codebasen, dimensionieren Realpath-Cache und OPcache passend zur Projektgröße und richten stabile Deployment-Prozesse ohne Cache-Invalidierungsprobleme ein.

Cache-Dimensionierung

realpath_cache_size und realpath_cache_ttl passend zur Projektgröße messen und setzen

Deployment-Absicherung

PHP-FPM-Reload-Strategien gegen veraltete Realpath-Cache-Einträge nach Releases

Docker-Optimierung

Realpath-Cache und OPcache für Bind-Mount- und Overlay-Dateisysteme abstimmen

10. Zusammenfassung

Der Realpath-Cache ist ein unscheinbarer, aber wirkungsvoller Baustein der PHP-Performance, der Pfadauflösungen für require, include und Autoloading beschleunigt, indem er wiederholte Dateisystemzugriffe vermeidet. realpath_cache_size und realpath_cache_ttl sind die beiden entscheidenden Stellschrauben, wobei der Standardwert von vier Megabyte für größere Projekte fast immer zu klein ist. In Kombination mit OPcache und deaktivierter Timestamp-Validierung entfaltet der Realpath-Cache seine volle Wirkung.

Besonders in Docker-Umgebungen mit Bind-Mounts und bei Projekten mit tiefen Verzeichnisstrukturen wie Magento oder Symfony lohnt sich eine bewusste Konfiguration deutlich über dem Standardwert. Wichtig bleibt dabei, Deployment-Prozesse so zu gestalten, dass ein PHP-FPM-Reload nach jedem Release den Realpath-Cache vollständig zurücksetzt, um veraltete Pfade nach symlink-basierten Deployments zu vermeiden.

Realpath-Cache in PHP, das Wichtigste auf einen Blick

Standardwert fast immer zu klein

4096K reicht bei großen Projekten nicht aus, 16M ist für die meisten Fälle ausreichend dimensioniert.

TTL an Deployment-Stabilität anpassen

Kurzer TTL für lokale Entwicklung, deutlich längerer TTL für stabile Produktionsumgebungen.

Auslastung messen statt raten

realpath_cache_size() und realpath_cache_get() zeigen, ob die konfigurierte Größe tatsächlich ausreicht.

PHP-FPM-Reload nach Deployment

Verhindert, dass Worker mit langem TTL noch Pfade aus einem alten Release im Cache halten.

11. FAQ: Realpath-Cache in PHP optimieren

1Was ist der Realpath-Cache?
Speichert aufgelöste Dateipfade, damit require, include und Autoloading nicht jedes Mal das Dateisystem befragen müssen.
2Wie groß sollte realpath_cache_size sein?
16M genügt für die meisten großen Projekte, der Standard von 4096K ist meist zu klein.
3Was bewirkt realpath_cache_ttl?
Bestimmt die Gültigkeitsdauer eines gecachten Pfads, Standard sind 120 Sekunden.
4Wie erkenne ich einen zu kleinen Cache?
realpath_cache_size() zeigt die aktuelle Auslastung, nahe am Maximum bedeutet zu klein dimensioniert.
5Warum ist er in Docker wichtig?
Bind-Mounts und Overlay-Dateisysteme machen Dateizugriffe langsamer, der Cache vermeidet diese teuren Zugriffe.
6Wie hängt er mit OPcache zusammen?
Er löst Pfade auf, bevor OPcache anhand des Pfads Bytecode nachschlägt, besonders wichtig bei deaktivierter Timestamp-Prüfung.
7Kann ein langer TTL Deployments stören?
Ja, bei symlink-basierten Deployments hilft ein PHP-FPM-Reload nach jedem Release gegen veraltete Cache-Einträge.
8Kann ich den Cache manuell leeren?
Es gibt kein Flush-Kommando, nur TTL-Ablauf oder ein Prozessneustart leeren ihn.
9Sollte ich lokal auch erhöhen?
Größe moderat erhöhen, TTL aber niedrig lassen, damit neue Dateien sofort gefunden werden.
10Bringt eine sehr hohe Größe mehr Nutzen?
Nein, sobald der Cache alle genutzten Pfade fasst, bringt mehr Größe keinen zusätzlichen Vorteil.