Indice dei contenuti dell'articolo:
La memorizzazione nella cache può dare l’impressione di essere il “Santo Graal” per tutti i problemi di prestazioni. Non sorprende che le persone sollevino un sopracciglio quando dico “Smetti di usare la memorizzazione nella cache” nelle mie presentazioni o consulenze.
Tuttavia, come abbiamo sempre spiegato dappertutto, gran parte del nostro successo come azienda di Hosting orientata alle Performance Web, è dovuto a meccanismi e tecnologie di Cache, che spaziano da Cache PHP come Zend Opcache fino a Full Page Cache di fascia enterprise come Varnish Cache.
Non è difficile, pertanto, rischiare in alcuni contesti di essere accusati di ipocrisia con lamentele del tipo: “Ma come, non hai detto che la cache migliora le performance e risolve i problemi?”
Quindi, è tempo di chiarire cosa intendo veramente di questo argomento, quando e per cosa dovrebbe essere usato. E forse la cosa più importante, quando non utilizzare la memorizzazione nella cache e cercare soluzioni alternative direttamente lato sviluppo.
Noi, come azienda di Hosting e sistemistica risolviamo i problemi lato sistemistico senza addentrarci lato sviluppo (se non per singole query, o piccolissimi bug) sui siti dei clienti che lamentano problemi di performance e velocità, per cui è normale che tecniche di caching possano nascondere le problematiche lato applicativo, esattamente come si nasconde la polvere sotto al tappeto.
Il problema rimane, ma di fatto non crea problemi tangibili ed il cliente ed i loro visitatori sono contenti di visualizzare siti o fare acquisti su siti che non vanno offline. Tuttavia, abbiamo sempre gradito un approccio degli sviluppatori adeguato ed orientato alle performance.
Quando dovresti usare la memorizzazione nella cache a pagina intera?
Cominciamo con il più grande di tutti. La Full Page Cache o semplicemente caching della pagina è una tecnica in cui memorizzi temporaneamente una versione pre-generata di una pagina per fornire lo stesso identico codice (HTML) ai visitatori in un intervallo di tempo limitato. Ecco come funziona la cache a pagina intera:
- Il visitatore A visita abc.com/page. Questa pagina non è nella cache, raggiunge PHP e viene generata dal database. Prima di essere servito al Visitatore A, viene anche memorizzato nella cache a pagina intera con una scadenza di 10 minuti.
- Il visitatore B visita abc.com/page 2 minuti dopo il visitatore A e viene quindi servito con la stessa pagina, ma questa volta direttamente dalla cache. Le pagine servite al Visitatore A e B sono identiche.
- Il visitatore C visita abc.com/page 15 minuti dopo il visitatore A e poiché la versione della pagina memorizzata nella cache è scaduta, la richiesta raggiunge nuovamente PHP e la pagina viene rigenerata proprio come per il visitatore A.
Poiché tutti coloro che visitano questa pagina nell’intervallo di tempo in cui esiste una pagina memorizzata nella cache valida, la pagina può essere consegnata molto rapidamente.
Quasi nessuna risorsa viene utilizzata per fornire una pagina memorizzata nella cache e quindi la memorizzazione nella cache di tutta la pagina può migliorare le prestazioni e, soprattutto, la scalabilità. Può sembrare molto interessante, ma la memorizzazione nella cache a pagina intera presenta anche alcuni grossi svantaggi.
- Se desideri fornire contenuti dinamici, personalizzati o in altro modo contenuti diversi a utenti diversi, questo deve essere risolto con javascript (ajax) che viene eseguito dopo che il documento HTML è stato consegnato al visitatore. Questo può funzionare bene, ma richiede un’altra richiesta aggiuntiva al server. Se usi la memorizzazione nella cache per evitare di scrivere codice veloce, continuerai a riscontrare problemi di performance con le tue richieste ajax dinamiche.
- Solo perché qualcosa funziona velocemente per te, non significa che sia veloce per tutti. I siti Web non hanno un unico punto di accesso e i visitatori giungono al tuo sito attraverso una varietà di pagine. Ciò è particolarmente vero per WooCommerce, dove i visitatori utilizzano Google e passano attraverso le pagine dei prodotti. Oppure, se esegui Google Shopping sul catalogo completo con link direttamente alle pagine dei prodotti. Per risolvere questo problema, alcune persone provano persino a risolverlo “adescando” la cache della pagina intera utilizzando gli spider per indicizzare l’intero sito con lo scopo di assicurarsi che ogni pagina sia memorizzata nella cache in anticipo. In pratica, questo non funziona bene. È vulnerabile, difficile da impostare e configurare correttamente, difficile da mantenere e richiede tempo e completamente non necessario.
- Perdi il controllo delle prestazioni reali del tuo sito Web e di come funziona il codice (o non funziona come dovrebbe). Se utilizzi la memorizzazione nella cache a pagina intera, perdi il senso di quale sia il tempo di risposta reale del tuo sito e di quanto sia buono il tuo codice. L’esperienza mostra che la mancanza di attenzione alle prestazioni reali è il motivo principale per cui i siti si bloccano in giorni come il Black Friday o quando si distribuiscono grandi campagne.
Che dire dei plugin di memorizzazione nella cache come W3 Total Cache?
I plugin di WordPress come W3 Total Cache funzionano come tutte le altre pagine di cache. Memorizzano una versione di una pagina pregenerata nel file system o nella memoria e la offrono agli utenti fino alla scadenza. W3 Total Cache è utilizzato da 1 milione di siti Web, ma ciò non significa che sia una buona idea. Soprattutto se utilizzi l’hosting veloce.
W3 Total Cache è un plug-in molto grande e, per la maggior parte dei siti, aggiunge solo un sacco di codice non necessario al sito Web. Più codice, significa che più cose possono andare storte. Se dovessi davvero fare la cache a pagina intera, questo non dovrebbe essere fatto nella parte PHP della tua applicazione perché PHP è lento. La memorizzazione nella cache della pagina intera dovrebbe essere eseguita il più vicino possibile all’utente nel server Web (NGINX nel nostro caso).
W3 Total Cache parla di caricare le pagine in meno di 2 secondi mostrando un tema come TwentySixteen. Per chiarire, un test simile sui nostri server verrà consegnato in circa 150 millisecondi senza l’uso della memorizzazione nella cache, non secondi.
Quindi, quando dovresti usare la memorizzazione nella cache a pagina intera e perché?
La memorizzazione nella cache dell’intera pagina è stata creata per ridimensionare i siti Web con molto traffico per gestire più facilmente i picchi di traffico. La memorizzazione nella cache della pagina intera è stata inventata quando le persone utilizzavano il Web principalmente per leggere articoli di notizie. Generare contenuti unici per ogni visitatore non è sensato per i giornali, perché le loro pagine sono per lo più statiche con aggiornamenti rari. Per questo scenario, la memorizzazione nella cache di pagina intera è assolutamente giusta, ma solo per siti che non richiedono utenti loggati o contenuti personalizzati, difatti i siti Web di oggi sono più simili alle applicazioni.
I siti web contemporanei sono più complessi, dinamici e sempre più personalizzati. Il codice è sempre più complesso e aggiungere meccanismi ancora più complessi (leggi tecniche di memorizzazione nella cache) su codice già complesso non è sempre una buona idea. In pratica, si aggiungerà quindi un altro livello di tecnologia che introduce nuovi single point of failure, necessita di manutenzione dedicata, aggiornamenti e operazioni. Renderà i bug più difficili da risolvere e lo sviluppo generale più difficile (più costoso). Se basi le tue prestazioni sulla memorizzazione nella cache della pagina intera, posso chiudere per garantire che la soluzione collasserà se la memorizzazione nella cache smette di funzionare.
La risposta alla domanda è quindi scrivere codice e query di buona qualità e tenere presente che la soluzione deve essere scalabile. È corretto utilizzare la memorizzazione nella cache di pagina intera per gestire picchi di traffico improvvisi, proprio come facevano i giornali e continuano a farlo.
Dovrebbe essere possibile disattivare la memorizzazione nella cache della pagina intera in un giorno normale, con traffico normale, senza innervosirsi. E se fai le cose per bene, dovresti essere in grado di disattivare la memorizzazione nella cache della pagina intera anche nei giorni con molto traffico, senza mandare in crash il tuo sito web.
Su Managed Server, la maggior parte dei negozi funziona senza la memorizzazione nella cache della pagina intera, anche nei giorni ad alto traffico come il Black Friday.
WordPress Object Cache: lo usi senza saperlo
Molte persone non sanno che la cache degli oggetti di WordPress è in uso in quasi tutti i siti WordPress. E sì, Object Cache è efficace anche se non utilizzi una Object Cache esterna, come MemCached o REDIS.
Come funziona la cache degli oggetti di WordPress?
- Si effettua una richiesta per cioè i valori postmeta utilizzando
get_post_meta()
- WordPress esegue la richiesta e ottiene il risultato dal database e memorizza automaticamente il risultato nella cache degli oggetti (memoria, RAM)
- Ottieni il risultato e lo usi da qualche parte nel tuo codice
- Più avanti nel tuo codice, fai un’altra
get_post_meta()
richiesta per gli stessi dati - WordPress lo ha già nella cache degli oggetti e lo restituisce direttamente senza eseguire nuovamente la query sul database
- La pagina viene consegnata al visitatore e la cache degli oggetti viene svuotata (memoria liberata)
Non tutte le funzioni di WordPress salvano i loro risultati nella cache degli oggetti, ma get_post_meta()
lo fanno. Questo perché la tabella _postmeta nel database può diventare molto grande e le richieste possono diventare costose (utilizzare molte risorse di elaborazione).
In qualità di sviluppatore, puoi aggiungere tu stesso risultati alla Object Cache , in modo che il riutilizzo degli stessi dati in un secondo momento possa essere più veloce. Se scrivi le tue query con ad esempio WP_Query, dovrai memorizzare tu stesso i risultati nella cache degli oggetti. È importante ricordare, tuttavia, che, come con tutta la memorizzazione nella cache, non puoi fidarti. Quindi assicurati di non scrivere codice che presuppone che i tuoi risultati siano nella cache degli oggetti.
È possibile verificare le prestazioni della cache degli oggetti e il numero di query al database installando un plug-in come Query Monitor.
Nei nostri test con un WooCommerce normale, un normale tasso di successo di Object Cache è compreso tra il 95% e il 98%.
Come utilizzare la cache degli oggetti di WordPress per le tue query
$result = wp_cache_get( 'some_unique_name' ); if ( false === $result ) { $result = $wpdb->get_results( $query ); wp_cache_set( 'some_unique_name', $result ); } // Do something with $result;
Quello che fa questo esempio di codice è prima provare a ottenere un $result
, quindi controllare se c’è davvero un $result. wp_cache_get()
restituisce false
se non esiste. Se non ci sono dati, eseguiamo la query per i nostri dati e quindi li archiviamo con in wp_cache_set()
modo che siano disponibili per richieste future.
Che dire delle cache di oggetti esterne come MemCached e REDIS?
Una cache degli oggetti esterna può fornire quella che più specificamente viene chiamata “cache degli oggetti persistente”. Questa è una cache degli oggetti che non viene scaricata tra le visualizzazioni di pagina; quindi, conserva i suoi dati in diverse visualizzazioni di pagina. Idea intelligente, vero? Ma come al solito con la memorizzazione nella cache, non è così semplice.
- Il potenziale guadagno in termini di prestazioni dall’utilizzo di una Object Cache persistente è limitato ai colpi che non riescono a Object Cache. Usando il tasso di accesso predefinito della cache non persistente del 95%-98%, il potenziale di miglioramento delle prestazioni è compreso tra il 2% e il 5% della richiesta. Inoltre, una cache di oggetti esterna aggiungerà una latenza aggiuntiva perché è un’applicazione esterna, quindi rallenterà il 95-98% che prima era servito direttamente in PHP. Il guadagno netto dalla latenza aggiunta + il guadagno in termini di prestazioni dalla cache degli oggetti esterna spesso diventa negativo per i negozi di e-commerce.
- Anche se utilizzi una Object Cache esterna, non puoi fidarti dell’esistenza delle informazioni durante la scrittura del codice.
- Se dipendi da una Object Cache esterna per caricare le pagine a una velocità decente, significa che il tuo codice non è valido, che le query del database sono troppo pesanti o che ce ne sono troppe. Il vero problema è nel tuo codice, non nella velocità di risposta del database. Ecco perché non dovresti usare il cerotto MemCached o Redis.
- Se si utilizza un database veloce, ottimizzato e che utilizza gli indici correttamente, non è necessaria una Object Cache esterna.
Se non hai bisogno di una Object Cache esterna, può essere dannoso usarne una
Questo vale davvero per tutta la tecnologia che includi nel tuo stack web, di cui non hai bisogno. Se ce l’hai, la possibilità di renderti dipendente da esso è grande, anche se non ne hai davvero bisogno. Se ne dipendi, aumenti le possibilità che qualcosa vada storto. Inoltre, ogni tecnologia aggiunta nello stack richiede installazione, configurazione, manutenzione, aggiornamenti di sicurezza e introduce un altro singolo punto di errore.
I transient possono essere buoni, ma anche danneggiare il tuo sito
I transient sono utilizzati da WordPress e da una varietà di plugin e il concetto è abbastanza semplice. Si effettua una richiesta e si salva il risultato, o parti di esso, nel database per un successivo riutilizzo. A differenza dell’Object Cache, non è necessaria alcuna tecnologia aggiuntiva per rendere questo persistente tra le visualizzazioni di pagina, perché i dati sono archiviati nel database. I transient possono avere un tempo di scadenza o meno: è una tua scelta.
Personalmente non mi piace l’uso eccessivo dei transient, e ci sono molte ragioni per questo
- I transient vengono salvati nella tabella _options di WordPress. Questa tabella è già molto utilizzata e la scrittura eccessiva in _options può introdurre problemi di blocco (coda).
- L’uso eccessivo di transient risulterà in una grande tabella _options. Ogni singola visualizzazione di pagina dipende da questa tabella e una tabella di opzioni di grandi dimensioni può ridurre le prestazioni su tutte le visualizzazioni di pagina.
- I transient che non scadono verranno interrogati a ogni caricamento della pagina (caricamento automatico) tramite wp_load_alloptions(). Ciò ridurrà le prestazioni su tutte le visualizzazioni di pagina.
Ma, detto questo, i transient possono essere ottimi per le prestazioni se usati correttamente. Se si esegue una query per i dati che vengono utilizzati spesso e che vengono modificati di rado, può essere una buona idea memorizzare il risultato in transient. È molto più facile per WordPress recuperare il valore dalla chiave X nella tabella delle opzioni, piuttosto che eseguire selezioni su altre tabelle. Ma, se usi i transient, assicurati di tenere d’occhio la tabella _options per assicurarti che non cresca selvaggiamente e assicurati di implementare la pulizia per i transient che non usi più o che sono scaduti. E non utilizzare mai i transient per i dati che richiedono aggiornamenti frequenti, in quanto si riducono le prestazioni.
La memorizzazione nella cache dei fragments è buona se usata correttamente
Fragment Cache è un tipo di memorizzazione nella cache in cui si memorizza un elemento, parte di una pagina o qualcos’altro la cui generazione è costosa in termini di risorse e/o viene utilizzata spesso. Molti hanno scelto di implementare la funzione di Mark Jaquith per eseguire il Fragment Caching in WordPress.
Fragment Caching significa memorizzare un risultato (output HTML) in modo che possa essere consegnato molto più velocemente in seguito. L’idea è tanto semplice quanto sorprendente. Puoi scegliere quali elementi memorizzare nella cache e non è necessario memorizzare nella cache l’intero output, come la memorizzazione nella cache della pagina intera.
Il modo in cui lo fai in WordPress è equivalente a Object Caching, perché non ci sono limiti ai dati che puoi memorizzare nella cache. Pertanto, si applicano gli stessi principi; non fidarti mai che qualcosa sia memorizzato nella cache, assicurati di non dipendere da esso e concentrati sul tuo codice piuttosto che prendere la scorciatoia della cache dei fragments.
Molti implementano la memorizzazione nella cache dei fragments basata sulla memoria. Ma affinché ciò abbia effetto, è necessaria una Object Cache esterna per rendere gli elementi disponibili nelle visualizzazioni di pagina (vedi sopra). Raccomando un uso delicato della memorizzazione nella cache dei fragments e la memorizzazione dei dati nei transient. In pratica, ciò ti darà gli stessi risultati in termini di prestazioni, senza aggiungere tecnologia aggiuntiva al tuo stack.
Ecco come salvare i transient
$output = get_transient('some_unique_key'); if( $output === false ){ $output = 'Some data'; set_transient('some_unique_key', $output, 3600); } // Do something with $output
In questo esempio di codice leggiamo $output
da un transient e testiamo se $output esiste. Se get_transient()
restituisce false
, generiamo i dati e li memorizziamo in un transient per un uso successivo.
Quale tecnica di cache dovrei usare e quando?
Usa la memorizzazione nella Full Page Cache per il ridimensionamento, ecco per cosa è fatto: non è fatto per aumentare le prestazioni. Assicurati di non renderti dipendente da questo. Dovresti essere in grado di disattivare la memorizzazione nella cache dell’intera pagina senza ottenere alcun calo significativo delle prestazioni.
Usa la Object Cache il più possibile, specialmente se usi WooCommerce, ma evita le Object Cache esterne, introdurranno ogni tipo di nuovo problema. Le cache esterne sposteranno la tua attenzione sulle parti sbagliate della tua applicazione. Un trucco migliore è ottenere un hosting più veloce, con database ad alte prestazioni come il nostro.
Dovresti usare i transient per le query frequenti che non cambiano molto. Assicurati di impostare una data di scadenza adeguata in base alla frequenza con cui i dati devono essere aggiornati.
Assicurati anche di eliminare i transient scaduti. Utilizzare la cache dei fragments nei transient per gli elementi che richiedono un uso intensivo di risorse e che vengono utilizzati frequentemente.