Più del 20% dei siti web al mondo sono sviluppati con tecnologia WordPress. Il nostro amato CMS, come tutti gli altri del suo settore, richiede però elaborazioni non indifferenti.
Ogni volta che una pagina viene richiesta, infatti, numerose sono le query SQL che CMS e plugin effettuano per scaricare le configurazioni e realizzare il codice HTML da fornire al browser. I più curiosi possono vederlo utilizzando il plugin Query Monitor.
Tutte queste query unite all’elaborazione del codice PHP rallentano il tempo di caricamento della pagina, con impatti negativi sulle prestazioni.
Per sopperire a questo problema viene solitamente utilizzato il plugin WP Super Cache di Automattic. Questo ottimo plugin, utilizzato per l’appunto come cache HTML, salva le copie delle pagine sul disco fisso.
Fintanto che si usano dischi SSD o si risiede su hosting condivisi, questo plugin rimane un’ottima scelta. Ma quando ci si trova a lavorare su un server virtuale o dedicato, allora è possibile ottenere prestazioni più elevate effettuando caching HTML in RAM.
Abbiamo già visto come aumentare del 150% le performance utilizzando FastCGI Cache di Nginx. Oggi vedremo insieme una tecnica di ottimizzazione in grado di velocizzare il sito web utilizzando il famoso Memcached, un key-store value solitamente utilizzato per limitare gli accessi al database, salvando in memoria il risultato di alcune query.
Memcached può essere utilizzato per memorizzare in memoria RAM qualsiasi tipo di contenuto, anche codice HTML. Per raggiungere l’obiettivo utilizzeremo il plugin gratuito Batcache.
Alla fine del processo le pagine del sito web saranno completamente caricate in RAM con tempi di risposta molto più rapidi. Se sei un amante di Redis potrebbe interessarti la guida su come velocizzare WordPress con Redis Cache.
Indice dei contenuti
Come primo passo occorre installare memcached. Su sistemi debian-based come Ubuntu, basta avviare il seguente comando che consentirà di installare memcached ed il modulo per PHP:
$ sudo apt-get install memcached php-memcached
Terminata l’installazione, verificare che memcached sia installato ed attivo. Per farlo controlliamo i servizi di rete in ascolto:
$ sudo netstat -ntapd Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 11464/nginx -g daem tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 1055/mysqld tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN 17644/memcached
Se tra i servizi è presente memcached, che di default è in ascolto in localhost sulla porta 11211, allora tutto è andato a buon fine. Naturalmente come qualsiasi altro tipo di servizio è possibile stopparlo, avviarlo o riavviarlo:
sudo service memcached restart
Il file di configurazione di memcached si trova di default su /etc/memcached.conf. Dal file di configurazione è possibile cambiare la quantità di memoria RAM da dedicare al servizio (di default 64 MegaByte), la porta ed il numero di connessioni simultanee (di default 1024).
Queste impostazioni vanno configurate a seconda delle caratteristiche hardware del server.
# Start with a cap of 64 megs of memory. It's reasonable, and the daemon default # Note that the daemon will grow to this size, but does not start out holding this much # memory -m 64 # Default connection port is 11211 -p 11211 # Limit the number of simultaneous incoming connections. The daemon default is 1024 # -c 1024
Ogni qual volta si effettua una modifica al file di configurazione di memcached, occorre riavviare il servizio.
A questo punto non rimane che riavviare il demone PHP per interfacciarlo con memcached. Su Nginx basta riavviare PHP-FPM:
sudo service php7.1-fpm restart
Su Apache occorre riavviare l’intero server web:
sudo service apache2 restart
Adesso occorre verificare la corretta installazione del modulo PHP. Per farlo basta creare un file sulla root del sito web, ad esempio phpinfo.php, ed inserire al suo interno il seguente codice:
<?php phpinfo(); ?>
Salvare e aprire tale file con il browser. Se memcached è stato installato correttamente, vedrete tra le varie configurazioni pure quelle che lo riguardano:
Batcache può essere installato direttamente dallo stesso WordPress oppure può essere scaricato dal repository ufficiale.
Una volta installato ed attivato, copiare su wp-content il file advanced-cache.php presente all’interno della directory del plugin wp-content/plugins/batcache.
Fatto questo, scaricare sempre su wp-content il file http://svn.wp-plugins.org/memcached/trunk/object-cache.php, che altro non sarebbe che il plugin Memcached Object Cache.
Modificare wp-config.php ed inserire le seguenti righe
global $batcache; $batcache = array('max_age' => 3600 ); define('WP_CACHE_KEY_SALT', 'test.example.com'); define('WP_CACHE', true);
Il primo parametro dell’array batcache, max_age, indica il tempo di vita della cache in secondi. In questo caso sono 3600, l’equivalente di 1 ora oltre la quale la cache viene svuotata.
Con la costante WP_CACHE_KEY_SALT settata sul nome del sito evitiamo race condition con eventuali altri siti ospitati sullo stesso server e che utilizzano la medesima configurazione.
Fatto questo, salvare wp-config.php e visitare una pagina del sito, avendo l’accortezza di caricarla due volte per permettere alla cache di avere effetto. Se tutto è andato a buon fine, in fondo al codice sorgente della pagina vedrete un commento HTML simile al seguente:
<!-- generated in 0.116 seconds 50610 bytes batcached for 3600 seconds -->
Quando si effettua qualsiasi tipo di testing occorre utilizzare diversi tool esterni ed analizzarne le metriche. I tool esterni sono molto affidabili in quanto preservano quasi sempre la connettività e non hanno cali di rendimento hardware, cosa che invece potrebbe capitare con i personal computer e connessioni ADSL casalinghe.
Al termine del test noterete come le performance del Time To First Byte medio sono aumentate del 93.5%!
TTFB senza Memcached
TTFB con Memcached
Nella versione di default, memcached utilizza i socket TCP per interfacciarsi con le applicazioni. È possibile aumentare la velocità di risposta di circa il 33% utilizzando al suo posto i socket Unix, che operando ad un livello inferiore del modello OSI sono più veloci.
Come prima cosa aggiungere l’utente memcache al gruppo www-data:
sudo usermod -g www-data memcache
Dopodiché modificare /etc/memcached.conf, commentare le righe che fanno riferimento all’indirizzo IP e alla porta e aggiungere le righe di configurazione che consentono di utilizzare i socket unix e di settare il giusto permesso:
#-p 11211 #-l 127.0.0.1
# Set unix socket which we put in the folder /var/run/memcached and made memcache user the owner -s /tmp/memcached.sock # Set permissions for the memcached socket so memcache user and www-data group can execute -a 775
Di seguito il file di configurazione di default completo di modifiche per i socket unix:
# memcached default config file # 2003 - Jay Bonci <[email protected]> # This configuration file is read by the start-memcached script provided as # part of the Debian GNU/Linux distribution. # Run memcached as a daemon. This command is implied, and is not needed for the # daemon to run. See the README.Debian that comes with this package for more # information. -d # Log memcached's output to /var/log/memcached logfile /var/log/memcached.log # Be verbose # -v # Be even more verbose (print client commands as well) # -vv # Start with a cap of 64 megs of memory. It's reasonable, and the daemon default # Note that the daemon will grow to this size, but does not start out holding this much # memory -m 64 # Default connection port is 11211 #-p 11211 # Run the daemon as root. The start-memcached will default to running as root if no # -u command is present in this config file -u memcache # Specify which IP address to listen on. The default is to listen on all IP addresses # This parameter is one of the only security measures that memcached has, so make sure # it's listening on a firewalled interface. #-l 127.0.0.1 # Limit the number of simultaneous incoming connections. The daemon default is 1024 # -c 1024 # Lock down all paged memory. Consult with the README and homepage before you do this # -k # Return error when memory is exhausted (rather than removing items) # -M # Maximize core file limit # -r # Set unix socket which we put in the folder /var/run/memcached and made memcache user the owner -s /tmp/memcached.sock # Set permissions for the memcached socket so memcache user and www-data group can execute -a 775
Salvare il file e riavviare memcached:
sudo service memcached restart
A questo punto verificare l’avvenuta creazione del descrittore del socket unix all’interno di /tmp:
$ ls /tmp/ memcached.sock
Una volta sicuri che il socket unix sia stato creato correttamente, modificare wp-config.php e aggiungere dopo global $batcache; la seguente riga:
$memcached_servers = array('unix:///tmp/memcached.sock');
Ecco la configurazione completa:
global $batcache; $memcached_servers = array('unix:///tmp/memcached.sock'); $batcache = array('max_age' => 3600 ); define('WP_CACHE_KEY_SALT', 'test.example.com'); define('WP_CACHE', true);
Salvare e verificare, come sempre caricando una pagina due volte, che la cache stia funzionando correttamente.
Memcached come page caching viene utilizzato da Salvatore Aranzulla per ottenere bassi tempi di Time To First Byte. Naturalmente non è questa sola configurazione a rendere il sito molto veloce.
Il sito di Salvatore, infatti, ha alle spalle una solida infrastruttura server. L’applicazione web, inoltre, è configurata per diminuire al massimo il sovraccarico del browser, ottimizzando il percorso di rendering critico.
Unita ad altre best practice di performance e ad una scrupolosa ottimizzazione del template, Salvatore presenta un sito semplice e molto rapido, che risponde benissimo alle esigenze dei suoi lettori ed al modello di business.
Abbiamo visto come utilizzare Memcached non solo per sopperire al continuo utilizzo di query SQL bensì come storage per cache HTML del nostro sito WordPress.
Naturalmente questa parte di ottimizzazione riguarda la parte server, mentre per la parte client, ovvero la più critica, occorrerà sempre richiedere una consulenza per ottimizzare il percorso di rendering critico ed ottenere così tempi di caricamento prossimi al secondo.