Wenn Sie file_exists($path) aufrufen und $path auf einen Amazon S3-Bucket verweist, greifen Sie nicht auf eine lokale Festplatte zu – Sie führen eine Netzwerkanfrage aus. Die einzeilige Prüfung wird zu einem Roundtrip zu S3, der bei jeder Anfrage mehrere zehn Millisekunden hinzufügen kann.
PHP verbirgt den Remote-Speicher hinter Stream-Wrappern. Funktionen wie fopen(), file_exists(), is_dir(), unlink() und file_put_contents() werden über diese Wrapper geleitet, die die Aufrufe in S3-API-Operationen übersetzen. Die Zuordnung ist eindeutig:
file_exists()→ HeadObjectis_dir()→ ListObjectsunlink()→ DeleteObjectfile_put_contents()→ PutObject
Jeder Aufruf verursacht die gleiche Latenz wie die entsprechende S3-API-Anfrage. Wenn ein Skript Dutzende von Dateien prüft, entsteht ein Muster im N+1-Stil: ein Netzwerk-Hop für jede einzelne Prüfung.
Warum das jetzt wichtig ist
In einer typischen Entwicklungsumgebung befindet sich das Dateisystem auf demselben Rechner, sodass die Prüfung fast augenblicklich erfolgt. In der Produktion, wo Assets auf S3 liegen, führt derselbe Code zu einem massiven Performance-Einbruch. Das AWS SDK zwischenspeichert einige Ergebnisse im Arbeitsspeicher, wodurch wiederholte Prüfungen in einem einzelnen PHP-Prozess schnell erscheinen. Die meisten PHP-Deployments starten jedoch für jede Webanfrage einen neuen Prozess und leeren dabei jedes Mal den Cache. Das Ergebnis: ein vollständiger Netzwerk-Roundtrip für jeden einzelnen Pfad bei jeder Anfrage.
Eine WordPress-Seite benötigte einmal zehn Sekunden, um ihre Homepage zu rendern. Die Datenbankabfragen waren schnell, aber die Seite löste allein für den Aufbau des Inhalts 73 einzelne S3-Aufrufe aus. Jeder Aufruf war eine Cold Request, wodurch ein scheinbar harmloses file_exists() zu einer spürbaren Verzögerung wurde.
Strategien zur Risikominderung
- Cache über Anfragen hinweg persistieren – Verlagern Sie den In-Process-Cache in einen gemeinsamen Speicher wie Redis. Wenn eine Anfrage feststellt, dass ein Key auf S3 existiert, lesen nachfolgende Anfragen das gecachte Ergebnis, anstatt S3 erneut zu kontaktieren.
- Einen Local-First-Workflow einführen – Schreiben Sie Dateien auf eine lokale Festplatte und synchronisieren Sie diese anschließend asynchron mit S3. Der primäre Anfragepfad greift nur auf das lokale Dateisystem zu; die Netzwerkkosten werden in einen Hintergrundjob ausgelagert.
- Codebase auditieren – Suchen Sie systematisch nach Dateisystem-Funktionen, die auf einen Remote-Wrapper verweisen könnten. Markieren Sie alle, die innerhalb von engen Schleifen oder an anfragekritischen Pfaden auftreten.
- APM-Daten untersuchen – Wenn die Antwortzeiten sprunghaft ansteigen, während die Datenbankmetriken stabil bleiben, analysieren Sie die Timings des Storage-SDKs. Ein plötzlicher Anstieg der SDK-Latenz deutet oft auf versteckte S3-Aufrufe hin.
Das wichtigste Fazit: Eine Funktion, die wie eine mikrosekundenschnelle lokale Prüfung aussieht, kann mehrere zehn Millisekunden an Netzwerklatenz verbergen. Behandeln Sie file_exists() auf S3 wie einen externen Aufruf, cachen Sie das Ergebnis und verlagern Sie die Hauptlast aus dem Anfragepfad. Andernfalls wird die versteckte Latenz Ihre Website weiterhin verlangsamen – eine unsichtbare Netzwerkanfrage nach der anderen.
