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

L'immagine descrive come ottimizziamo gli ecommerce magento 2 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