Se chiami file_exists($path) e $path punta a un bucket Amazon S3, non stai interrogando un disco locale: stai effettuando una richiesta di rete. Quel controllo su una singola riga diventa un viaggio di andata e ritorno verso S3 che può aggiungere decine di millisecondi a ogni richiesta.
PHP nasconde lo storage remoto dietro gli stream wrapper. Funzioni come fopen(), file_exists(), is_dir(), unlink() e file_put_contents() passano attraverso questi wrapper, che traducono le chiamate in operazioni API di S3. La mappatura è diretta:
file_exists()→ HeadObjectis_dir()→ ListObjectsunlink()→ DeleteObjectfile_put_contents()→ PutObject
Ogni chiamata comporta la stessa latenza della corrispondente richiesta API di S3. Quando uno script controlla decine di file, crea un pattern di tipo N+1: un salto di rete per ogni singolo controllo.
Perché è importante ora
In un tipico ambiente di sviluppo, il file system risiede sulla stessa macchina, quindi il controllo ritorna quasi istantaneamente. In produzione, dove gli asset si trovano su S3, lo stesso codice crea un crollo delle prestazioni. L'AWS SDK memorizza alcuni risultati in memoria, facendo apparire veloci i controlli ripetuti all'interno di un singolo processo PHP. Tuttavia, la maggior parte delle implementazioni PHP avvia un nuovo processo per ogni richiesta web, svuotando la cache ogni volta. Il risultato: un intero viaggio di andata e ritorno sulla rete per ogni percorso distinto in ogni richiesta.
Un sito WordPress una volta impiegava dieci secondi per renderizzare la sua homepage. Le query al database erano veloci, ma la pagina innescava 73 chiamate S3 individuali solo per assemblare il contenuto. Ogni chiamata era una richiesta "a freddo", trasformando un file_exists() apparentemente innocuo in un ritardo evidente.
Strategie di mitigazione
- Persistere la cache tra le richieste – Sposta la cache del processo in uno store condiviso come Redis. Quando una richiesta scopre che una chiave esiste su S3, le richieste successive leggono il risultato memorizzato nella cache invece di contattare nuovamente S3.
- Adottare un workflow "local-first" – Scrivi i file su un disco locale, quindi sincronizzali su S3 in modo asincrono. Il percorso principale della richiesta tocca solo il file system locale; il costo di rete viene spostato su un job in background.
- Audit del codice – Cerca sistematicamente le funzioni del file system che potrebbero risolvere in un wrapper remoto. Segnala quelle che appaiono all'interno di cicli stretti o percorsi critici per la richiesta.
- Ispezionare i dati APM – Se i tempi di risposta aumentano improvvisamente mentre le metriche del database rimangono stabili, approfondisci i tempi dell'SDK di storage. Un improvviso aumento della latenza dell'SDK spesso indica chiamate S3 nascoste.
Il punto fondamentale: una funzione che sembra un controllo locale da un microsecondo può nascondere decine di millisecondi di latenza di rete. Tratta file_exists() su S3 come una chiamata esterna, memorizza il suo risultato nella cache e sposta il lavoro pesante fuori dal percorso della richiesta. Altrimenti, la latenza nascosta continuerà a rallentare il tuo sito, una richiesta di rete invisibile alla volta.
