Cache Stampede in Magento 2: come progettare e ottimizzare eCommerce ad alto traffico

Quando si parla di performance in Magento 2, l’attenzione si concentra spesso su Redis, Varnish, database, OpenSearch e tempi di risposta PHP.
Nei progetti ad alto traffico, però, le performance non dipendono soltanto dalla velocità con cui il sistema risponde in condizioni normali. Un aspetto altrettanto importante è come l’infrastruttura reagisce quando una cache scade o viene invalidata mentre centinaia o migliaia di richieste stanno raggiungendo contemporaneamente lo stesso contenuto.
È il problema noto come Cache Stampede, chiamato anche Thundering Herd Problem.
In questo articolo vediamo come questo fenomeno si applica a Magento 2 e Adobe Commerce e quali strategie utilizziamo in Devlogica per progettare piattaforme eCommerce capaci di sostenere traffico elevato mantenendo tempi di risposta prevedibili.
Perché la cache è fondamentale in Magento 2
Magento dispone di un’architettura di caching multilivello.
In una tipica installazione production possiamo avere:
Browser
│
▼
CDN
│
▼
Varnish / Fastly
│
▼
Nginx
│
▼
PHP-FPM
│
▼
Magento
│
├── Redis / Valkey
├── OpenSearch
└── MySQL
Adobe Commerce utilizza diversi tipi di cache applicativa per configurazione, layout, HTML block, collection e Full Page Cache. Per gli ambienti production on-premises Adobe raccomanda Varnish come Full Page Cache, mentre Adobe Commerce Cloud utilizza Fastly.
Quando tutte queste cache sono “calde”, una piattaforma Magento correttamente progettata può gestire volumi di traffico molto elevati.
Il problema nasce durante le transizioni:
CACHE HIT
↓
CACHE INVALIDATION
↓
CACHE MISS
↓
CACHE REBUILD
↓
CACHE HIT
È proprio il periodo tra invalidation e rebuild che può diventare critico.
Cos’è una Cache Stampede
Immaginiamo una pagina prodotto molto visitata.
La pagina è presente nella Full Page Cache:
GET /prodotto-x
│
▼
Varnish
│
▼
CACHE HIT
│
▼
Response
Magento non viene praticamente coinvolto.
Supponiamo però che il prodotto venga modificato e che la relativa cache venga invalidata.
La richiesta successiva diventa:
GET /prodotto-x
│
▼
Varnish
│
▼
CACHE MISS
│
▼
Magento
│
├── PHP
├── Cache
├── OpenSearch
└── MySQL
Fin qui non c’è nulla di particolarmente problematico.
Ma cosa succede se quella pagina riceve 1.000 richieste quasi contemporaneamente?
Potenzialmente:
CACHE INVALIDATED
│
▼
1000 requests
│
▼
CACHE MISS
│
┌───────────┼───────────┐
▼ ▼ ▼
Magento Magento Magento
│ │ │
PHP PHP PHP
│ │ │
MySQL MySQL MySQL
Molte richieste cercano contemporaneamente di ricostruire informazioni che pochi millisecondi prima erano disponibili direttamente dalla cache.
Questo è il Cache Stampede.
Adobe stessa evidenzia che l’invalidazione della cache può aumentare i tempi di risposta perché, in assenza del dato cached, Commerce deve recuperare informazioni dal database, elaborarle e ricostruire la cache utilizzando maggiori risorse.
Perché il problema è particolarmente importante negli eCommerce
Il traffico di un eCommerce raramente è distribuito uniformemente.
Normalmente una piccola parte del catalogo genera una percentuale molto elevata delle richieste.
Pensiamo a:
- un prodotto appena lanciato;
- una promozione particolarmente aggressiva;
- una categoria durante Black Friday;
- un prodotto mostrato durante una campagna televisiva;
- una landing page utilizzata da una campagna advertising;
- prodotti diventati improvvisamente virali.
In questi casi abbiamo delle hot key, ovvero contenuti che ricevono una quantità di richieste enormemente superiore alla media.
Finché il dato è cached:
10.000 requests
│
▼
CACHE
│
▼
10.000 responses
Il carico sull’application layer rimane minimo.
Quando la cache scompare improvvisamente, però, lo scenario può diventare:
10.000 requests
│
▼
CACHE MISS
│
▼
Magento application layer
│
▼
Database / OpenSearch / APIs
Il problema quindi non è necessariamente la capacità media del sistema.
È la capacità di assorbire improvvisi picchi di cache regeneration.
Strategia 1: Full Page Cache con Varnish
Il primo livello di protezione per un Magento ad alto traffico è evitare che richieste inutili raggiungano Magento.
Per installazioni on-premises, Adobe raccomanda esplicitamente Varnish per gli ambienti production perché la Full Page Cache integrata è significativamente meno performante.
L’architettura diventa:
Internet
│
▼
CDN
│
▼
Varnish
│
┌───────┴───────┐
│ │
CACHE HIT CACHE MISS
│ │
▼ ▼
Response Magento
L’obiettivo è semplice:
Magento dovrebbe elaborare soltanto le richieste che hanno realmente bisogno di Magento.
Su piattaforme ad alto traffico questo principio ha un impatto enorme sulla capacità complessiva del sistema.
Strategia 2: Stale-While-Revalidate
Una delle strategie più efficaci contro i Cache Stampede consiste nel non considerare immediatamente inutilizzabile un contenuto nel momento esatto in cui supera il TTL.
Supponiamo:
TTL = 5 minuti
Nell’approccio più semplice:
0 -------------------- 300s
CACHE HIT
↓
EXPIRED
↓
CACHE MISS
Con un approccio stale-while-revalidate, invece:
0 ---------------- 300 ----------- 360
FRESH STALE
Tra 300 e 360 secondi il contenuto non è più considerato fresco, ma può ancora essere utilizzato temporaneamente mentre viene generata una nuova versione.
Il comportamento diventa:
Request
│
▼
Cache expired?
│
YES
│
▼
Serve stale content
│
└──────────────► regenerate cache
L’utente continua quindi a ricevere una risposta veloce mentre il sistema aggiorna il contenuto.
Varnish supporta questo modello tramite la Grace Mode. Adobe documenta che Varnish può servire temporaneamente un oggetto stale oltre il TTL mentre recupera una nuova versione dal backend, riducendo i tempi di caricamento e il traffico verso Commerce.
Per molte tipologie di contenuto eCommerce, qualche secondo di potenziale staleness è un compromesso molto migliore rispetto a sovraccaricare improvvisamente l’application layer.
Strategia 3: Request Coalescing
Un’altra tecnica estremamente importante è il Request Coalescing, chiamato anche single-flight.
L’idea è semplice.
Se 500 richieste richiedono contemporaneamente lo stesso dato non presente in cache, non è necessario che tutte e 500 lo rigenerino.
È sufficiente che lo faccia una sola richiesta.
500 requests
│
▼
CACHE MISS
│
▼
regeneration lock
│
├── Request #1 → regenerate
│
├── Request #2 ─┐
├── Request #3 │
├── Request #4 │ wait / stale
│ │
└── Request #500┘
Quando la prima richiesta termina:
Request #1
│
▼
expensive operation
│
▼
CACHE SET
│
▼
499 requests → CACHE HIT
In questo modo il backend esegue una sola operazione costosa anziché centinaia di operazioni identiche.
Questa tecnica diventa particolarmente interessante per servizi applicativi, integrazioni, API, resolver GraphQL e dati aggregati costosi da generare.
Strategia 4: Soft TTL e Hard TTL
Non tutte le cache devono necessariamente avere un solo momento di scadenza.
Per alcuni dati utilizziamo concettualmente due soglie:
Soft TTL Hard TTL
│ │
───────────────┼────────────────────┼────────
FRESH │ STALE │ INVALID
───────────────┴────────────────────┴────────
Il comportamento può quindi essere:
FRESH
↓
return immediately
STALE
↓
return cached data
+
trigger refresh
INVALID
↓
force regeneration
Questa strategia evita che il sistema passi istantaneamente da:
100% CACHE HIT
a:
100% CACHE MISS
durante un picco di traffico.
Strategia 5: TTL Jitter
Un problema meno evidente si verifica quando molte cache vengono create contemporaneamente utilizzando lo stesso TTL.
Supponiamo di generare 50.000 elementi con:
TTL = 3600 secondi
Dopo esattamente un’ora potremmo avere:
50.000 cache entries
│
▼
EXPIRE
│
▼
massive regeneration
Un approccio più robusto consiste nell’introdurre una piccola variazione casuale nel TTL:
TTL base = 3600
jitter = ±300
ottenendo scadenze distribuite nel tempo:
55 min
57 min
59 min
61 min
63 min
65 min
Questo semplice accorgimento può ridurre significativamente i picchi di rigenerazione delle cache applicative.
Strategia 6: caching multilivello
Un’architettura Magento moderna non dovrebbe considerare la cache come un singolo componente.
La cache è una gerarchia:
Browser Cache
│
▼
CDN
│
▼
Varnish / Fastly
│
▼
Local application cache
│
▼
Redis / Valkey
│
▼
Database
Ogni livello deve intercettare le richieste prima che raggiungano quello più costoso.
Adobe Commerce supporta inoltre il caching L2 (two-level), nel quale ogni web node dispone di una cache locale mantenendo Redis o Valkey come cache remota condivisa.
Il principio è:
Redis / Valkey
│
┌───────────┴───────────┐
│ │
PHP #1 PHP #2
│ │
Local Cache Local Cache
Questo riduce i round-trip verso il sistema di cache remoto.
La documentazione Adobe indica che una normale istanza Commerce può trasferire circa 300 KB di dati cache per richiesta e che, aumentando il numero di richieste, il traffico verso lo storage remoto può diventare significativo.
Per Adobe Commerce 2.4.9+, inoltre, Adobe introduce la moderna implementazione L2 basata su Symfony Cache e indica Valkey come backend per questa configurazione.
Strategia 7: ridurre le invalidazioni inutili
Una strategia spesso sottovalutata consiste nel non concentrarsi esclusivamente sulla velocità con cui ricostruiamo una cache.
Dobbiamo anche chiederci:
Perché la stiamo invalidando?
Una piattaforma può avere una cache estremamente veloce ma invalidarla troppo frequentemente.
In Magento è quindi importante analizzare:
UPDATE
│
▼
Cache Tags
│
▼
Invalidation
│
▼
Varnish Purge
│
▼
Regeneration
Quando Commerce esegue operazioni di clean, flush o refresh, anche gli oggetti interessati presenti in Varnish possono essere eliminati.
Su cataloghi molto grandi o siti con frequenti aggiornamenti di prodotto, prezzo e disponibilità, il design della strategia di invalidazione diventa quindi importante quanto il caching stesso.
Il vero obiettivo: proteggere il backend
Tutte queste strategie hanno in realtà lo stesso obiettivo.
Non si tratta semplicemente di ottenere:
Response time = 50 ms
invece di:
Response time = 100 ms
L’obiettivo è costruire un sistema nel quale un improvviso aumento del traffico non provochi questa catena:
Traffic spike
↓
Cache misses
↓
PHP saturation
↓
Database saturation
↓
Increasing latency
↓
More concurrent requests
↓
Further saturation
↓
OUTAGE
Questa dinamica può generare un effetto a cascata.
Una piattaforma progettata correttamente cerca invece di ottenere:
Traffic spike
↓
CDN / Varnish
↓
Cache protection
↓
Controlled regeneration
↓
Stable application layer
↓
Stable database
Non ottimizziamo solo la media: P95 e P99
Un altro errore comune nell’analisi delle performance consiste nel guardare esclusivamente il tempo medio di risposta.
Immaginiamo:
Average response: 120 ms
Può sembrare un risultato eccellente.
Ma potremmo avere:
P50 80 ms
P95 450 ms
P99 3200 ms
Il problema è quindi nascosto nella coda della distribuzione.
Gli utenti che arrivano durante una cache regeneration possono avere un’esperienza completamente diversa dagli altri.
Per questo nelle nostre analisi consideriamo anche:
Cache Hit Ratio
P50
P95
P99
Cache Miss Rate
Backend Response Time
PHP-FPM saturation
Database connections
Redis / Valkey latency
OpenSearch latency
Cache regeneration time
Le performance di un eCommerce ad alto traffico sono prima di tutto un problema di stabilità sotto carico, non soltanto di velocità.
Come Devlogica ottimizza Magento per siti ad alto traffico
In Devlogica affrontiamo l’ottimizzazione Magento partendo dall’architettura complessiva e non da singole micro-ottimizzazioni.
Un tipico processo di analisi considera diversi livelli.
1. Traffic analysis
Identifichiamo:
Hot Products
Hot Categories
Landing Pages
Traffic Peaks
API Traffic
GraphQL Traffic
Bot Traffic
L’obiettivo è capire dove viene realmente generato il carico.
2. Cache architecture
Analizziamo l’intera catena:
Browser
↓
CDN
↓
Varnish / Fastly
↓
Magento FPC
↓
Application Cache
↓
Redis / Valkey
Misuriamo cache hit ratio, TTL, invalidazioni e pattern di purge.
3. Application profiling
Individuiamo le operazioni Magento più costose:
Controllers
GraphQL resolvers
Plugins
Observers
Repositories
Collections
Database queries
External APIs
Una cache efficace non può compensare indefinitamente codice applicativo inefficiente.
4. Database analysis
Analizziamo:
slow queries
indexes
locks
connection saturation
query volume
read/write patterns
L’obiettivo è ridurre il numero di operazioni che raggiungono MySQL e rendere efficienti quelle inevitabili.
5. Cache invalidation analysis
Verifichiamo quali operazioni generano invalidazioni e quanto è ampio il loro impatto.
Cerchiamo situazioni come:
small data update
↓
large cache invalidation
↓
massive regeneration
che possono essere particolarmente costose durante i periodi di traffico elevato.
6. Load testing
Infine simuliamo condizioni realistiche:
Normal traffic
Traffic spike
Cold cache
Warm cache
Cache invalidation
Concurrent requests
High API traffic
Perché un sistema apparentemente veloce con cache completamente calda può comportarsi in maniera completamente diversa pochi secondi dopo un’invalidazione.
Performance Engineering, non semplicemente “Magento tuning”
Per noi l’ottimizzazione di Magento non significa modificare qualche parametro PHP o aumentare indiscriminatamente CPU e RAM.
Significa progettare il sistema affinché:
meno richieste
raggiungano Magento
meno richieste Magento
raggiungano il database
meno operazioni
vengano ripetute inutilmente
le cache
non scadano tutte contemporaneamente
le invalidazioni
abbiano un impatto controllato
i picchi di traffico
non diventino picchi infrastrutturali
L’obiettivo finale è ottenere un’architettura nella quale il costo di una richiesta diminuisce progressivamente man mano che aumenta il traffico servito dalla cache.
Conclusioni
Magento 2 e Adobe Commerce dispongono già di strumenti molto potenti per costruire piattaforme ad alte prestazioni: Full Page Cache, Varnish, Fastly, Redis/Valkey e caching L2.
La differenza tra una configurazione standard e una piattaforma realmente progettata per l’alto traffico, però, sta spesso nel modo in cui questi strumenti vengono utilizzati insieme.
Tecniche come:
- stale-while-revalidate;
- grace period;
- request coalescing;
- soft e hard TTL;
- TTL jitter;
- caching multilivello;
- controllo delle invalidazioni;
- profiling e load testing;
permettono di affrontare uno dei problemi più insidiosi dei sistemi distribuiti ad alto traffico: evitare che la perdita temporanea della cache trasferisca improvvisamente tutto il carico sull’application layer e sul database.
La domanda corretta quindi non è soltanto:
Quanto è veloce Magento quando la cache funziona?
Ma soprattutto:
Cosa succede alla piattaforma quando la cache viene invalidata mentre migliaia di utenti stanno effettuando richieste?
È proprio in questi scenari che una corretta attività di Performance Engineering fa la differenza tra un eCommerce semplicemente veloce e un eCommerce realmente scalabile.
Devlogica — Magento Performance & Scalability
Devlogica progetta, analizza e ottimizza piattaforme Magento 2 e Adobe Commerce ad alto traffico, intervenendo sull’intera architettura applicativa: caching, Varnish/Fastly, Redis/Valkey, PHP, MySQL, OpenSearch, GraphQL, integrazioni e infrastruttura.
Il nostro approccio parte dalla misurazione del comportamento reale della piattaforma, individua i colli di bottiglia e definisce una strategia di ottimizzazione orientata non soltanto alla velocità, ma soprattutto a scalabilità, stabilità e prevedibilità sotto carico.
Perché un eCommerce performante non deve essere veloce soltanto quando tutto funziona nelle condizioni ideali.
Deve continuare a esserlo quando arriva il traffico. Contattaci per una consulenza
