Created on 19 Aug 2012 ;    Modified on 29 Sep 2013

Vi è mai capitato?

Di avere un piccolo server WEB. Magari virtuale. Con soli 256 MB di RAM. Il servizio http é implementato con il processo httpd di Apache

Vi avete ospitato siti statici senza problemi. Naturalmente il traffico generato da questi siti non era granché. Pochi hit al minuto, se non all'ora.

Dopo di che decidete di provare il brivido del CMS.

Fate qualche prova di Wordpress sul vostro PC di casa: tutto ok. Bene, decidete di provare online. Installate e cominciate a scrivere qualche articolo. Quasi tutto bene. Dopo un po' di tempo Wordpress rallenta spaventosamente. Se riavviate il servizio httpd Wordpress diviene nuovamente reattivo, salvo sbracarsi dopo qualche (breve) tempo.

La relativa ricerca in Internet vi indirizza ad analizzare i componenti aggiuntivi di Wordpress.

Purtroppo voi di componenti aggiuntivi ne avete messi davvero pochi (dopo tutto state provando), e comunque, anche disabilitandoli non cambia nulla.

Wordpress troppo pesante per un sistema cosí piccolo? Probabilmente.

Archiviate il tutto e decidete di dare una occhiata a Drupal. Qui il codice php è pochino, e, almeno all'inizio, alla larga dai componenti aggiuntivi!

Anche in questo caso, installate, cominciate ad usarlo, e dopo un po' rallenta.

Allora, ormai è ufficiale: i CMS ce l'hanno con voi. O forse è Apache?

Tirate fuori gli strumenti del sistemista (top, ps, ...) e vi mettete a ragionare. L'uso di cpu indicato da top non è sconvolgente. Ma non avevate mai visto girate contemporaneamente tanti processi httpd! Nuovo controllo con top, ci siamo: la memoria swap aumenta via via che i processi httpd salgono di numero. E' questo il problema: il servizio WEB è andato, almeno in parte, in memoria swap. Cosa assolutamente da evitare, come insegna Apache Foundation.

Evidentemente sia Drupal che Wordpress, mentre lavorano, lanciano raffiche di richieste al server WEB. Questo, per non mettere le richieste in attesa, continua ad aprire nuovi processi (fino a 256 nella configurazione standard di Apache). E quando la RAM fisica finisce, il server impegna lo swap, che va su disco rigido. Da questo momento, se una richiesta al vostro server viene dirottata da Apache ad uno dei processi in swap, potete aspettare anche 40 secondi prima che il server riesca a liberare abbastanza RAM fisica per dare il via al processo richiesto.

Come rimediare?

Comprando un server con maggiore RAM, direte voi. Avete ragione. Ma per siti hobbistici, con una quantità di traffico praticamente inesistente mi sembra proprio uno spreco.

Basiamoci sul fatto che le richieste a regime sono pochissime. Di conseguenza la probabilità di dover servire piú richieste contemporaneamente è molto bassa. Quindi decidiamo di strangolare la configurazione di Apache in modo che non possa avviare molti processi.

Come si fa?

E' necessario modificare alcuni parametri nell'apposito file di configurazione di Apache: httpd.conf.

Fate riferimento alla documentazione di Apache Foundation per localizzarlo.

Se, come me, lavorate in CentoOS (o Red Hat, o Fedora) lo trovate in /etc/httpd/conf/httpd.conf.

In quale sezione andare a mettere le mani? Dipende da come il vostro servizio httpd è stato compilato per gestire le richieste parallele. Esistono versioni di Apache che utilizzano il solo multiprocesso, e altre che utilizzano contemporaneamente il multithreading e il multiprocesso.

Se il vpstro servizio usa il solo multiprocesso, cercate la sezione <ifmodule prefork.c> ... </ifmodule>.

Altrimenti dovrete lavorare nella sezione <ifmodule worker.c> ... </ifmodule>.

Come si capisce che tipo di servizio si sta utilizzando? Provate il comando httpd -V.

Se nella risposta trovate una riga del tipo: Server MPM: Prefork, allora state lavorando in multiprocessing puro. In caso contrario avete a che fare con un servizio in multithreading, oltre che multiprocesso.

Se avete un servizio multithreading+multiprocesso, controllate la relativa documentazione di Apache per capire il significato dei diversi parametri di configurazione.

Per un multiprocesso puro, in Linux il caso piú diffuso, almeno alla data in cui scrivo, capire quali parametri modificare, e come, è piuttosto semplice. Vediamo.

StartServersè il numero di processi iniziali avviati. Abbassatelo.

Subito dopo controlliamo MaxClients, il massimo numero di richieste servite in parallelo. Abbassate anche queste.

ServerLimitè un parametro che ha senso soprattutto per il multithread. In questo caso coincide con il numero massimo di processi aperti contemporaneamente da Apache. Impostatelo allo stesso valore che avete dato a MaxClients.

MaxSpareServersè il massimo numero di processi httpd in idle, ovvero che non stanno servendo richieste: tenetelo basso, ma comunque superiore a 1.

MinSpareServersinvece è il numero minimo di processi httpd in idle. Se Apache osserva un numero di processi httpd in idle inferiore a questo numero, comincia a creare nuovi processi (nel nostro caso: orrore!). Mettetelo a 1.

Infine abbiamo MaxRequestsPerChild. Questo numero è il massimo numero di richieste che un processo httpd servirà. Quando viene superato, il processo viene ucciso. Di fatto questo numero indica la frequenza con cui cambia lo scenario dei processi httpd. Piú è grande, piú lentamente può variare il numero di processi httpd gestiti, e viceversa. D'altro canto numeri piccoli tenderanno a sovraccaricare il sistema imponendo un frequente ricambio dei processi httpd.

Nel mio caso ho impostato i parametri in questione come segue:

<IfModule prefork.c>
    StartServers 3
    MinSpareServers 1
    MaxSpareServers 3
    ServerLimit 6
    MaxClients 6
    MaxRequestsPerChild 500
</IfModule>

Per ora sta funzionando senza grossi squilibri.

Naturalmente, se avete un server con maggiore RAM (512 MB, o piú), sarà il caso di aggiustare i parametri in questione verso l'alto. Soprattutto: MaxClientse ServerLimit, tirandosi dietro MaxSpareServers.

Riferimenti

Apache: tuning delle performance

Apache: direttive MPM comuni

Apache: MPM modulo worker

Apache: MPM modulo prefork

Drupal

Wordpress