Mar 082012
 

Questo è un mio articolo, originariamente pubblicato su Wazi

WordPress, il popolare sistema di gestione contenuti (CMS), è facile da configurare e utilizzare, e ben supportato sia dalla sua comunità che da consulenti professionali. WordPress dipende per il suo funzionamento da uno stack completo che comprende un sistema operativo, database, server web e PHP. Se è possibile ottimizzare questo stack, è possibile migliorare le prestazioni del vostro sito. Ecco alcuni trucchi e best practice per una configurazione in grado di migliorare le prestazioni senza forzare ad un aggiornamento hardware.

Nella prima parte di questa guida abbiamo visto cosa verificare e modificare nel sistema operativo e sul database server (mysql), oggi vedremo come impostare il server http (Nginx per l’esattezza) e PHP.


il mio server HTTP preferito per questo lavoro è Nginx, in un articolo recente ho parlato di alcuni vantaggi derivanti dall’utilizzo di questo server HTTP con PHP5 in modalità FPM contro Apache e il suo modulo mod_php. Se avete già aggiunto il repository EPEL, eseguite yum install nginx per installare nginx-0.8.54 1.el6. Mentre l’ultima release stabile di nginx è superiore alla 1.0.X, l’installazione di un pacchetto da un repository ufficiale offre una versione più stabile anche se più vecchia.

Adesso diamo uno sguardo ai parametri presenti nel file di configurazione /etc/nginx/nginx.conf.

worker_processes controlla – sorpresa – il numero di processi worker da far partire. Un worker è simile a un processo figlio di Apache. Nginx ha la capacità di mettere i worker process, da utilizzare, su più processori su macchine SMP multiprocessore, diminuendo così la latenza quando i worker sono bloccati da operazioni I/O su disco, o di limitare il numero di connessioni al processo quando le opzioni select () o poll () sono utilizzate. La regola generale del pollice è quella di impostare il numero di lavoratori di Nginx a due, o al numero di CPU che il server ha. Se avete intenzione di ospitare siti con un sacco di contenuti statici, aggiungete più worker – fino a uno per disco.

Se il sottosistema disco è scarsa o il carico è troppo alto, i worker process di nginx vengono bloccati sulle operazioni di I/O e quindi non sono in grado di servire altre richieste. Esegui ps ax ed esaminarne il risultato, i worker che sono in stato “D” sono bloccati. Aumentate il numero di worker process fino a quando un ps ax restituisca un numero di worker process non bloccati uguale al numero di CPU presenti nel sistema. È anche possibile aggiungere un po’ di memoria per la cache su disco per risolvere questo problema.

Insieme al parametro worker_proceses, worker_connections permette di calcolare un valore per max_clients:
max_clients = worker_processes * worker_connections
Io suggerisco di tenere questo valore non troppo alto. Se l’output del vostro ulimit -n è qualcosa del tipo 1024, allora il vostro valore di worker_connection dovrebbe essere impostato a 1024 o meno (forse anche 768), è abbastanza improbabile che abbiate “worker_processes x 1024” connessioni simultanee.

Valori di timeout specificano la quantità di tempo in secondi che Nginx attenderà il client per completare l’azione specificata.

client_body_timeout N è il timeout per la lettura del corpo della richiesta dal client. Se dopo questo tempo il client non invia nulla, Nginx restituisce l’errore “Richiesta fuori tempo” (408).

client_header_timeout N è il timeout per la lettura dell’header della richiesta del cliente. Se dopo questo tempo il cliente non invia niente, nginx restituisce l’errore “Richiesta fuori tempo” (408).

keepalive_timeout N N – il primo valore è per la connessione keep-alive con il cliente. Il secondo parametro assegna il valore “Keep-Alive: timeout = tempo” nell’intestazione della risposta.

Riguardo a questi valori io di solito tengo 30 secondi per il timeout verso il client e non più di 10 secondi per il keepalive. È possibile ridurre il keepalive, a 3 forse, se si ha un sito occupato e vi accorgete che avete un sacco di connessione aperte. Altri suggeriscono di tenere questa impostazione a 0, facendo così riaprire al cliente la connessione ogni volta.

sendfile on|off Usate sendfile quando il server Nginx può effettivamente ignorare il contenuto del file che sta inviando. Se è posto ad on, utilizza il supporto del sendfile() presente nel kernel invece delle proprie risorse sulle richieste.

tcp_nopush on|off Abilita o disabilita le opzioni di socket TCP_NOPUSH (FreeBSD) o TCP_CORK (Linux). Notare che questa opzione si applica solo se la direttiva sendfile è abilitata. Se tcp_nopush è impostato su on, Nginx cercherà di trasmettere l’intera intestazione di risposta HTTP in un singolo pacchetto TCP. La maggior parte delle fonti suggeriscono di impostarlo ad off.

TCP_NODELAY on|off disabilita l’algoritmo di buffering Nagle. Si può usare quando il server non richiede una risposta da parte del cliente. Nell’utilizzo web generico si ha bisogno di una risposta, quindi questo dovrebbe essere messo ad off, a meno che non abbiate bisogno di inviare piccoli pezzi di informazioni, come nel controllo dei movimenti del mouse.

multi_accept on|off tenta di accept() tutte le connessioni possibili dopo che nginx riceve la notifica di una nuova connessione.

Si dovrebbero anche consentire tutte le opzioni di compressione di nginx. Inserire nel file nginx.conf queste opzioni:

   worker_processes      2;
   events {
    worker_connections   768;
    use epoll;
   }
   sendfile              on;
   tcp_nopush            off;
   client_body_timeout   30;
   client_header_timeout 30;
   keepalive_timeout     10 10;
   tcp_nodelay           off;
   multi_accept          on;
   gzip on;
   gzip_proxied any;
   gzip_comp_level 2;
   gzip_disable "MSIE [1-6].(?!.*SV1)";
   gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

Queste sono le opzioni generali. È anche possibile regolare le opzioni specifiche per il sito WordPress. Per fare questo, modificare il file specifico del Virtuahost. Io di solito uso il nome del sito – per esempio, se ho il sito www.example.com – metto le sue configurazione nel file /etc/httpd/conf.d/www.example.com.conf . Qui di seguito ci sono alcune opzioni suggerite se si utilizza php5-FPM.

.....
location ~ .php$ {
      fastcgi_split_path_info ^(.+.php)(.*)$;
      fastcgi_pass   backend;
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME  /var/www/$fastcgi_script_name;
		fastcgi_connect_timeout 60;
		fastcgi_send_timeout 180;
		fastcgi_read_timeout 180;
		fastcgi_buffer_size 128k;
		fastcgi_buffers 4 256k;
		fastcgi_busy_buffers_size 256k;
		fastcgi_temp_file_write_size 256k;
		fastcgi_intercept_errors on;
.....

Con le modifiche e le aggiunte ai file di configurazione di cui sopra, si dovrebbe avere una buona, ottimizzazione di base di nginx.

PHP-FPM

Io uso PHP-FPM, in alternativa alla implementazione PHP FastCGI perché offre alcune funzioni utili per i siti di qualsiasi dimensione, e soprattutto per i siti più frequentati. Alcune delle caratteristiche che trovo particolarmente utili in questa implementazione di PHP sono:

  • avanzata gestione dei processi con arresto ed avvio “graceful”
  • La possibilità di avviare” worker” con differenti uid, gid, chroot, o impostazioni di ambiente e file php.ini diversi (sostituisce safe_mode)
  • Registrazione di stdout e stderr
  • Riavvio di emergenza in caso di distruzione accidentale della cache con il codice operativo
  • Supporto per l’upload accelerato
  • Supporto per un “slowlog”, è possibile registrare tutti gli script lenti.

Purtroppo, PHP-FPM non è disponibile nel repository di default di CentOS, e neanche in EPEL, il repository dei pacchetti extra per la Red Hat Enterprise Linux che abbiamo aggiunto in precedenza, quindi dobbiamo aggiungere un altro repository, questa volta dal IUS Community Project. L’obiettivo di questo progetto è quello di fornire pacchetti aggiornati con una regolare manutenzione dei pacchetti RPM per le ultime versioni upstream di PHP, Python, MySQL, e altro software per Red Hat Enterprise Linux (RHEL).

Per aggiungere IUS  come repository su un sistema a 32 bit, date questo comando come root da un terminale:

rpm -ivh http://dl.iuscommunity.org/pub/ius/stable/Redhat/6/i386/ius-release-1.0-8.ius.el6.noarch.rpm

Se avete un sistema a 64 bit date invece:

rpm -ivh http://dl.iuscommunity.org/pub/ius/stable/Redhat/6/x86_64/ius-release-1.0-8.ius.el6.noarch.rpm

Dopo aver aggiunto il repository, aggiornate la lista dei pacchetti con il comando yum update.

Ora potete installare PHP-FPM, il pacchetto php53u-FPM-5.3.8-3.ius.el6.i686 per l’esattezza, e la corrispondente estensione PHP per parlare con MySQL con il comando:

yum install php53u-fpm php53u-mysql

Le impostazioni predefinite nel file di configurazione generico dell’applicazione, /etc/php-fpm.conf, sono abbastanza buone, ma faremo modifiche al file di configurazione del pool. PHP-FPM può lanciare più pool di processi in ascolto su porte separate per soddisfare le esigenze di ambienti virtuali multi-dominio in hosting. Il file di configurazione del pool si trova in /etc/php-fpm.d/poolname.conf. Il pool di default si chiama www, e questo è l’unico pool che useremo. Le opzioni principali sono:

Pool name  Il valore predefinito è [www].

listen specifica l’indirizzo su cui accettare le richieste. Di solito è impostato su una porta localhost alta; 9000 è il default.

listen.allowed_clients Specifica opzionalmente un elenco di indirizzi IPv4 di client che sono autorizzati a connettersi. Se si ascolta solo su localhost si può tranquillamente saltare questa opzione.

user e group Mettete l’username ed il gruppo con cui gira il vostro server web. Per noi, questo è nginx/nginx.

pm specifica il tipo di gestore di processo. Le opzioni sono statico o dinamico, io uso dinamico in modo da poter avviare e arrestare più processi, se necessario.

pm.max_children imposta il limite al numero di richieste simultanee che verranno servite. Controlla il numero di processi figli da creare quando pm è impostato su “statico”, e il numero massimo di processi figli da creare quando pm è impostato su “dinamico.” E’ equivalente alla direttiva ApacheMaxClients con cui si può avere familiarità se si utilizza mpm_prefork ed Apache. Il miglior valore per questa variabile dipende da quanta RAM avete sul vostro sistema e la quantità di RAM che è stata impostata per ogni processo PHP. Se avete impostato 32MB come limite massimo di RAM per PHP, con un valore di 20 significa che nel nostro caso  è possibile utilizzare fino a 640 MB di RAM per tutti i processi PHP-FPM.

pm.start_servers definisce il numero di processi figli creati all’avvio.

pm.min_spare_servers è il numero minimo desiderato di processi server inattivi. Si vogliono usualmente alcuni processi server di riserva pronti a rispondere ai client, ma non troppi.

pm.max_spare_servers è il numero massimo di processi server inattivi.

pm.max_requests controlla il numero di richieste che ogni processo figlio deve eseguire prima di ripartire (respawn).Questa direttiva può essere utile per ovviare a perdite di memoria con librerie di terze parti. Di default non è attivata.

request_terminate_timeout specifica il timeout in secondi per servire una singola richiesta, dopo di che un processo worker sarà ucciso. Di default non è impostato, ma suggerisco di mettere un valore qui. A seconda del contenuto del vostro sito potrebbe essere qualsiasi cosa, da 30 a 300, un sito veloce con WordPress dovrebbe essere in grado di servire tutte le richieste entro 30 secondi.

request_slowlog_timeout specifica un valore in secondi (o minuti) che indica un timeout per servire una singola richiesta, dopo di che un backtrace del codice PHP è  scaricato nel file slowlog. Impostare questo a 1 o 2 secondi meno del vostro request_terminate_timeout per vedere quali processi PHP sono lenti e quindi sono terminati, fino a quando anche la precedente direttiva è attivata.

slowlog definisce il percorso del file di log dove si possono vedere le richieste lente.

Di default PHP-FPM utilizza tutti i valori definiti nel file /etc/php.ini, ma si possono mettere in questo file ulteriori definizioni  php.ini che saranno specifiche per questo gruppo di workers.Queste definizioni  sostituiscono i valori già definiti nel file php.ini. Una impostazione utile per WordPress è php_admin_value[memory_limit], che specifica la quantità massima di memoria che PHP può utilizzare in megabyte. A seconda della RAM totale disponibile sul server, questo valore può variare da 32 a 512.

Qui ci sono alcune impostazioni di configurazione di esempio che servono come buoni punti di partenza per server con dimensioni di memoria differenti, che abbiano in esecuzione sia MySQL che un server web sulla stessa macchina.

Server con 512MB RAM:

[www]
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
user = nginx
group = nginx
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500
request_terminate_timeout = 30
request_slowlog_timeout = 28
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[memory_limit] = 32M

Server con 1GB RAM:

[www]
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
user = nginx
group = nginx
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
request_terminate_timeout = 45
request_slowlog_timeout = 40
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[memory_limit] = 48M

Server con 2GB RAM:

[www]
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
user = nginx
group = nginx
pm = dynamic
pm.max_children = 40
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
request_terminate_timeout = 60
request_slowlog_timeout = 40
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[memory_limit] = 64M

Una volta che il sito è in funzione è possibile ottenere ulteriori informazioni per perfezionare la vostra configurazione. I vostri script terminano perché raggiungono memory_limit? Aumentare il valore un po’. Il vostro sistema va in crash, perché mangia tutta la memoria? Abbassate il parametro pm.max_children e/o il memory_limit. Controllare anche i log di nginx e php-fpm e le slowlog, possono dare molte informazioni.

Enhanced by Zemanta

 

Popular Posts:

Flattr this!

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

*