Redis ha fatto miracoli: da oltre 2 secondi a 320 ms con Laravel

Un caso reale di performance engineering: il problema non era solo la query, ma dove stavano cache e sessioni.

A volte ottimizzi una query e guadagni qualche millisecondo. Altre volte cambi il posto in cui salvi cache e sessioni e ti chiedi perché non l'hai fatto prima.

Nel mio caso Redis ha cambiato radicalmente il profilo delle prestazioni di un'applicazione Laravel. Non perché il database fosse “lento” in senso assoluto, ma perché stavo usando un database remoto anche per operazioni che devono essere estremamente frequenti e a bassissima latenza.

Il problema non era PHP

La prima cosa importante è stata misurare. Il bootstrap dell'applicazione richiedeva poche decine di millisecondi. Il tempo veniva consumato soprattutto dalle operazioni sul database.

Questo è un dettaglio importante: senza profiling avrei potuto iniziare a ottimizzare controller, componenti React, middleware o codice PHP ottenendo miglioramenti quasi irrilevanti.

Il vero costo era altrove.

Quando anche una query veloce diventa lenta

Un database può eseguire una query in pochissimo tempo e restituire comunque una risposta lenta all'applicazione.

Se applicazione e database sono separati dalla rete, ogni operazione paga anche latenza di connessione e round trip. Il problema diventa evidente quando una singola richiesta HTTP esegue molte query.

Sessioni e cache aggravavano ulteriormente la situazione: leggere una sessione, controllare una chiave di cache e aggiornare nuovamente la sessione significava coinvolgere il database anche su endpoint quasi vuoti.

Un endpoint minimale raccontava già tutto

Ho confrontato lo stesso endpoint con cache e sessioni sul database e con uno storage veloce separato.

Con cache e sessioni sul database servivano operazioni per:

  • leggere la sessione;

  • leggere la cache;

  • registrare la visita;

  • aggiornare la sessione.

Spostando cache e sessioni fuori dal database, rimaneva soltanto la query realmente legata alla logica applicativa.

Questo è stato il segnale definitivo: il database stava facendo un lavoro che non avrebbe dovuto fare.

Entra Redis

Avevo già Redis disponibile vicino all'applicazione, quindi la scelta naturale è stata usarlo per ciò che sa fare molto bene: accessi rapidissimi a dati temporanei.

In Laravel il passaggio concettuale è semplice:

CACHE_STORE=redis
SESSION_DRIVER=redis

Naturalmente la configurazione reale richiede anche connessione, isolamento delle chiavi e una corretta gestione dei secret, ma il codice applicativo non deve necessariamente cambiare.

I risultati

Dopo il passaggio a Redis e con la cache calda, la differenza è diventata immediatamente visibile.

  • Home: da circa 1,8 s a circa 0,5 s;

  • Newsletter: da oltre 1 s a circa 0,3 s;

  • Articolo: da oltre 2 s a circa 0,32 s lato server nelle prime misurazioni.

Ancora più interessante è il numero di query. Un articolo, una volta che Redis aveva popolato la cache, poteva arrivare a sole due query sul database.

Un endpoint minimale è passato da più operazioni sul database a una sola query effettivamente necessaria.

Redis non ha reso PostgreSQL più veloce

Questa distinzione è fondamentale.

Redis non ha ottimizzato le query SQL. Ha evitato che PostgreSQL dovesse gestire continuamente dati temporanei che potevano vivere altrove.

È una differenza architetturale:

  • PostgreSQL conserva i dati persistenti e relazionali;

  • Redis gestisce dati temporanei e accessi ad altissima frequenza;

  • Laravel continua a usare le proprie astrazioni per cache e sessioni.

Ogni componente torna quindi a svolgere il lavoro per cui è più adatto.

La cache fredda esiste

I benchmark vanno interpretati correttamente. La prima visita a una pagina può essere più lenta perché la cache deve essere popolata.

È quindi sbagliato misurare una singola richiesta e dichiarare vittoria. Ho ripetuto le richieste distinguendo il comportamento a cache fredda da quello a cache calda.

È proprio dal secondo passaggio che il vantaggio di Redis è diventato evidente.

Un'altra lezione: conta il numero di query

Ottimizzare SQL rimane importante, ma in presenza di latenza di rete il numero di round trip può contare più del tempo di esecuzione della singola query.

Una query da 1 ms non costa realmente 1 ms se per raggiungere il database bisogna attraversare la rete.

Dieci query perfettamente indicizzate possono quindi essere peggiori di due query leggermente più complesse.

Non spostare tutto su Redis alla cieca

Redis non è una bacchetta magica. Prima di cambiare driver bisogna capire quali dati si stanno spostando.

Per esempio, cambiare improvvisamente backend delle code mentre esistono job ancora nel vecchio storage può creare problemi operativi. Cache e sessioni sono state quindi migrate separatamente, verificando prima la raggiungibilità del servizio e poi effettuando il deploy.

Un altro aspetto importante è il fallback operativo: se Redis diventa una dipendenza per sessioni e cache e non è raggiungibile, l'applicazione può smettere di funzionare correttamente. Monitoraggio e configurazione della rete contano quanto la scelta tecnologica.

Cosa resta da ottimizzare

Redis ha eliminato una grande quantità di lavoro inutile, ma il profiling ha evidenziato anche il collo di bottiglia successivo: quando una pagina deve comunque aprire una nuova connessione verso un database remoto per una singola operazione, il costo della connessione può diventare più importante della query stessa.

È il bello dell'ottimizzazione basata sui dati: risolto il problema più grande, quello successivo diventa finalmente visibile.

La lezione più importante

Non partire dalla tecnologia. Parti dai tempi.

Prima di questa analisi avrei potuto dire genericamente che “il sito è lento”. Dopo il profiling potevo invece dire quante query venivano eseguite, quanto tempo trascorrevano sul database e quali operazioni non avevano motivo di arrivarci.

Redis ha fatto miracoli, sì. Ma il vero salto di qualità è arrivato dal capire perché poteva farli.

Quando un'applicazione Laravel è lenta, quindi, prima di riscrivere codice o aumentare le risorse del server conviene farsi una domanda molto più semplice: quanto lavoro sto chiedendo al database che potrei evitare completamente?

Condividi: