Dopo oltre 5 anni passati ad amministrare server web basati su Apache HTTP Server (httpd) ho imparato che ci sono un pugno di settings semplicissimi da impostare, ma che hanno un impatto enorme sulle prestazioni del server, sui tempi di risposta e sul volume di traffico che è possibile sostenere a parità di risorse hardware. Questo articolo vuole esserne una "guida rapida", scritta innanzitutto per tener traccia delle mie esperienze e, contestualmente, per aprire uno spazio di discussione per ascoltare altre esperienze

med

Dove modificare questi valori

I valori segnalati di seguito devono essere inseriti nel file di configurazione di Apache. Sulle distribuzioni derivate da Red Hat Enterprise Linux (come CentOS o Fedora), è posizionato in /etc/httpd/conf/httpd.conf.

Il percorso è differente sotto Ubuntu, nel quale qui si trova in /etc/apache2/apache2.conf.

In caso di dubbio, potete localizzarlo rapidamente con il comando find / -name httpd*.conf

med

HostnameLookups off

La direttiva HostnameLookups fa sì che, per ogni richiesta, Apache perda tempo con una richiesta al server DNS per risolvere (alla rovescia) l'indirizzo IP nel corrispondente nome a dominio.

È completamente inutile perché è possibile svolgere la risoluzione anche in seguito, nell'improbabile caso in cui ve ne fosse necessità. Di conseguenza, assicuratevi che si legga HostnameLookups off nel vostro file di configurazione.

KeepAlive On, KeepAliveRequests 500, KeepAliveTimeout 2

La direttiva KeepAlive fa sì che un singolo client possa riutilizzare la connessione HTTP al webserver per richiedere molteplici elementi (la pagine HTML stessa, le immagini, i fogli di stile eccetera).

Sulla carta, evita che si perda tempo ad aprire e chiudere una nuova connessione per ogni elemento, ma può essere anche molto pericolosa: in momenti di forte carico, infatti, si rischia di perdere tempo in attesa che il client faccia una nuova richiesta invece che esaudire quante più richieste il più velocemente possibile. Questo può allungare la coda di lavoro fino ad una situazione di stallo.

È quindi importante utilizzarla, ma farlo con prudenza, ovvero configurando il webserver affinché gestisca richieste sulla stessa connessione solo per breve tempo.

  • KeepAlive On: attiva la funzione

  • KeepAliveRequests 500: serve fino a 500 richieste sulla stessa connessione (questo limite è praticamente impossibile da raggiungere se abbinato ad un timeout breve come quello proposto di seguito)

  • KeepAliveTimeout 2: la connessione è riutilizzabile per al massimo due secondi da quando viene creata. Le richieste successive verranno servite su una nuova connessione, anch'essa riutilizzabile per due secondi al più

MaxClients X, MaxRequestWorkers X, ServerLimit X, StartServers X, MaxSpareServers X, MinSpareServers X

La grande flessibilità di Apache fa sì che un valore cruciale per il corretto funzionamento del webserver sia esprimibile con diversi parametri. Formalmente, MaxClients (chiamato MaxRequestWorkers nelle versioni recenti), ServerLimit, StartServers, MaxSpareServers e MinSpareServers hanno significati diversi, ma, nella pratica, possono tranquillamente essere settati tutti allo stesso valore, ovvero il numero di processi di httpd che devono coesistere contemporaneamente.

Se avete fretta e volete un numero, il valore ottimale che ho calcolato con il procedimento espresso di seguito è il seguente:

  • Se il server ha 1 GB di RAM: 2
  • Se il server ha 2 GB di RAM: 8
  • Se il server ha 4 GB di RAM: 22
  • Se il server ha 8 GB di RAM: 48
  • Se il server ha 16 GB di RAM: 102
  • Se il server ha 32 GB di RAM: 208

Per un server con 2 GB di RAM imposteremo nella sezione <IfModule prefork.c> i seguenti:

  • MaxClients 8
  • MaxRequestWorkers 8
  • ServerLimit 8
  • StartServers 8
  • MaxSpareServers 8
  • MinSpareServers 8

Ma... come ho calcolato questo valore? perché è importante? Per capirlo, ricordiamo che, nella modalità classica, ogni processo di Apache serve un visitatore per volta: avere X processi significa soddisfare X client contemporaneamente. Questo numero deve essere scelto in maniera appropriata alle risorse hardware a disposizione.

Scegliere X troppo basso fa sì che, in caso il numero di visitatori contemporanei sia superiore, molti rimarranno in coda (in attesa che un processo si liberi e sia disponibile per servirli) anche quando il server sarebbe in grado di rispondere immediatamente.

Al contrario, un X più grande di quanto l'hardware consenta fa sì che vengano creati troppi processi concorrenti senza che vi sia lo spazio in memoria per farli lavorare. Il risultato è che il sistema operativo inizia a parcheggiarli su disco fisso (swap): nel caso meno pessimistico, la conseguenza è che le attese salgano a decine di secondi se non minuti. Nel peggiore, il server si blocca del tutto ed è necessario un reset forzato.

Quindi... come scegliere X in modo appropriato? Molto semplice: basta utilizzare la formula (MemoriaTotale - MemoriaUtilizzataDaLinuxEccetera) / DimensioneMediaProcessoApache.

Per prima cosa, scoprite quanta RAM è installata sul server impartendo cat /proc/meminfo (è il valore corrispondente alla dicitura MemTotal)

med

Nota: il numero è espresso in kilobyte, quindi vorrete dividerlo per 1.024 di modo da ragionare in megabyte.

A questo numero, dovete sottrarre la quantità di RAM riservata dal sistema operativo e da tutti gli altri applicativi. Per approssimare, considerate 500 MB per Linux, quindi lanciate top e cercate la riga corrispondente a mysqld: il numero di nostro interesse è quello indicato nella colonna RES.

med

Riassumendo: ipotizzando che sul server siano presenti 2 GB di RAM (2.000 MB), faremo: 2000 MB - 500 MB di Linux - 200 MB di MySQL = 1300 MB di RAM disponibile.

Ora dovete scoprire quante istanze di Apache possano stare in questo spazio. Lanciate nuovamente top, individuate una delle varie righe relative ad httpd e guardate il numero riportato nella colonna RES

med

Dividete la quantità di RAM disponibile per questo numero, arrotondate per difetto e avete trovato la vostra X. Continuando con l'esempio precedente, calcoleremo 1300 MB di RAM disponibile / 150 MB di ogni processo di Apache = 8,6 = 8.

MaxConnectionsPerChild 5000

Il parametro MaxConnectionsPerChild impone che ogni istanza di Apache venga definitivamente uccisa (e sostituita da uno nuovo) dopo aver servito X richieste. L'operazione di morte e rinascita richiede un po' di tempo, quindi non deve essere svolta inutilmente troppo spesso, ma evita che i processi vivano talmente a lungo da allocare in maniera esclusiva quantità di RAM eccessive.

Una via di mezzo accettabile può essere attorno a 5.000: nella sezione <IfModule prefork.c> inseriremo quindi MaxConnectionsPerChild 5000.

Altri suggerimenti?

Quelle elencate fino a qui sono le impostazioni che utilizzo abitualmente, anche qui su TurboLab.it. Sono particolarmente interessato a leggere le esperienze degli altri colleghi smanettoni: i commenti qui sotto sono a disposizione per qualsiasi ulteriore spunto.