7.6. Il problema dei file descriptor

I sistemi UNIX® utilizzano i descrittori di files per leggere e scrivere su disco i files ed i socket di rete, un file descriptor identifica quindi un file o un socket che viene aperto da una connessione di rete o da un processo locale. Ogni volta che un processo di sistema apre un file o un socket viene allocato un descrittore di file, quando questo viene chiuso il relativo file descriptor verrà liberato. Per gestire l'accesso ai file e ai socket, Squid utilizza una tabella di processo che contiene l'elenco di tutti i file descriptor aperti. La dimensione di questa tabella é statica e viene impostata al momento dell'esecuzione del comando ./configure. I diversi Sistemi Operativi oggi sul mercato utilizzano uno schema proprietario nella gestione dei processi e può accadere che il valore dei file descriptor predefinito nel Kernel del Sistema sia troppo piccolo per garantire il funzionamento di alcuni apparati di webcache la cui peculiarietà è quella di gestire dei carichi di traffico molto elevati. Può quindi rendersi necessario aumentare il valore dei file descriptor prima di eseguire il comando ./configure. Per determinare un valore adeguato si deve tenere conto dei seguenti fattori

  1. la singola richiesta HTTP utilizza contemporaneamente sino a 3 file descriptor

    connessione HTTP lato client, connessione HTTP lato server e la scrittura o la lettura della cache su disco (scrivere nella cache un MISS o leggere nella cache un HIT)

  2. la scrittura delle informazioni nei file di log utilizza contemporaneamente sino a 4 file descriptor

    Squid utilizza solitamente quattro file di log principali (access.log, cache.log, store.log e swap.state) e nel momento in cui accede a detti file apre un file descriptor

  3. le comunicazioni tra Squid ed i processi esterni utilizzano mediamente sino a 20 file descriptors

    gli autenticatori, i redirectors e le porte in ascolto, mantengono sempre un certo numero di file descriptors attivi, il valore medio dipende molto dal numero degli helpers utilizzati e dal numero dei socket che vengono aperti da Squid (porte HTTP, ICP, SNMP ed altro).

  4. un browser web esegue mediamente 2 o 3 richieste HTTP persistenti (idle time)

    ciò significa che per ogni browser web, volendo fare un dimensionamento pessimistico, si deve prevedere un utilizzo di circa 8 file descriptor.

7.6.1. Determinare il numero corretto di file descriptor

Quando Squid è fermo in attesa di richieste utilizza in media 24 descrittori di files (file di log e comunicazioni tra processi), ogni singola richiesta HTTP determina l'apertura di una media di 8 file descriptor (singola richiesta e connessioni persistenti).

file descriptor medi

utenti concorrenti

connessioni persistenti

totale file descriptor

24

20

20*8

160+24=184

24

50

50*8

400+24=424

24

100

100*8

800+24=824

24

200

200*8

1600+24=1624

24

400

400*8

3200+24=2324

24

500

500*8

4000+24=4024



Nell'ipotesi più pessimistica con la quale si prevede l'apertura di 10 o più file descriptors per connessione persistente, con 400 client concorrenti saranno necessari almeno 4096 file descriptor. Una buona configurazione può prevedere 1024 file descriptor, tale impostazione può andare bene se si prevede un traffico medio. La tabella riportata in calce può essere utilizzata per dimensionare al meglio il nostro sistema di webcache, se desideriamo verificare il numero di file descriptor configurati per una versione pacchettizzata e preinstallata di Squid, possiamo determinare questo valore ricavandolo dal file cache.log

2004/04/03 13:08:29| With 1024 file descriptors available
   

Squid può presentare dei problemi con i file descriptor nel momento in cui viene eseguito, anche in questo caso l'avviso potrà essere rilevato dal file cache.log

2004/04/12 21:33:22| WARNING! Your cache is running out of file descriptors
   

nel caso si dovesse presentare questo avviso di warning è necessario accrescere il limite dei file descriptor, la modalità con cui è possibile variare il numero di file descriptor, come abbiamo visto precedentemente, é specifica per ogni Sistema Operativo.

Il Cache Manager è un ottimo strumento per verificare l'allocazione dei processi attivi per file descriptor

Active file descriptors:
File Type   Tout Nread  * Nwrite * Remote Address        Description
---- ------ ---- -------- -------- --------------- ------------------------------
   3 Log       0       0        0                  /usr/local/squid/var/logs/cache.log
   4 Socket    0       0        0  .0              DNS Socket
   5 File      0       0     1177                  /usr/local/squid/var/logs/access.log
   6 Pipe      0       0        0                  unlinkd -> squid
   7 File      0       0     1609                  /usr/local/squid/var/logs/store.log
   8 File      0       0        0                  /home/var/spool/squid/swap.state
   9 Pipe      0       0        0                  squid -> unlinkd
  10 Socket 1440      70*       0  127.0.0.1.51740 cache_object://127.0.0.1/filedescriptors
  11 Socket    0       0*       0  .0              HTTP Socket
  12 Socket    0       0*       0  .0              ICP Socket
  13 Socket    0       0*       0  .0              HTCP Socket
  14 Socket    0       0*       0  .0              SNMP Port
   

7.6.2. File descriptor con Linux

Il valore dei files descriptors impostato come default per ogni distribuzione Linux è generalmente pari a 1024, gestire questo tipo di impostazione non è affatto semplice. Infatti prima di configurare Squid è necessario verificare il numero di file descriptors attualmente configurati utilizzando il comando ulimit(8), si tratta di un comando che fa parte della shell. Il primo passo da compiere è quello di verificare il numero di file descriptor disponibili sulla nostra piattaforma

% ulimit -n
1024
   

a questo punto dovremmo editare uno dei file di system include del kernel, in particolare si tratta del file /usr/include/bits/tipes.h oppure del file /usr/include/bits/typesizes.h modificando il valore __FD_SETSIZE

% vi /usr/include/bits/typesizes.h
#define __FD_SETSIZE 4096
   

il valore __FD_SETSIZE viene controllato durante l'esecuzione dello script di ./configure. Squid è particolarmente vorace di file descriptors che sono una risorsa finita ma regolabile del sistema operativo, oltre che molto preziosa, visto che sono i canali di comunicazione che vengono utilizzati dai vari processi per parlare con il mondo esterno e fra di loro. Per verificare quanti file descriptors il sistema metta a disposizione con la configurazione standard si può digitare il seguente comando

% cat /proc/sys/fs/file-max
104857
   

è opportuno che questo numero sia piuttosto alto, in linea di massima può andare bene se maggiore di 65000. Qualora il numero dovesse essere più basso, si consiglia di editare (come root) il file /etc/sysctl.conf aggiungendo la riga

fs.file-max = 102400
   

e poi lanciare (sempre come root) il comando

% sysctl -p
   

che legge le impostazioni dal file /etc/sysctl.conf (viene di norma eseguito automaticamente al reboot, quindi le impostazioni non andranno perse). Se per caso la nostra distribuzione linux non utilizzasse il sistema sysctl, si può in alternativa aggiungere la riga

echo 102400 > /proc/sys/fs/file-max
   

al file rc.local, e lanciarla anche dalla riga di comando (come root) per attivarla anche immediatamente. queste impostazioni vanno aggiunte su tutti i sistemi su cui Squid verrà installato, non solo su quelli dove viene compilato. A questo punto incrementiamo il limite massimo dei processi di file descriptors. Dovremmo utilizzare la stessa shell (bash, sh, tsh...) con la quale successivamente configureremo e compileremo Squid

% ulimit -Hn 4096
% ulimit -n 4096
   

dove 4096 è il valore di file descriptors che si intendono utilizzare con Squid, eseguiamo un make clean prima di avviare lo script ./config.status che ci consentirà di configurare nuovamente l'ambiente tenendo conto delle nuove impostazioni del kernel

% make clean
% ./config.status --recheck
...
checking Default FD_SETSIZE value... 4096
checking Maximum number of filedescriptors we can open... 4096
checking Default UDP send buffer size... 65535
checking Default UDP receive buffer size... 65535
checking Default TCP send buffer size... 16384
checking Default TCP receive buffer size... 87380
Limiting receive buffer size to 64K
checking if sys_errlist is already defined... (cached) no
checking for libresolv _dns_ttl_ hack... no
checking if inet_ntoa() actually works... yes
checking for working statvfs() interface... yes
checking for _res.nsaddr_list... (cached) yes
creating ./config.status
...
   

ora compiliamo ed installiamo nuovamente Squid

% make
% make install
   

non abbiamo ancora finito, impostare il valore corretto di file descriptors con linux non riguarda solo la compilazione e l'installazione di Squid ma anche il suo avviamento

ulimit -HSn 4096
   

possiamo inserire questo ultimo comando nello script di avviamento di Squid, in qualsiasi distribuzione Red Hat o Fedora core il file da modificare è /etc/rc.d/init.d/squid

7.6.3. File descriptor con Solaris

Il valore di default è 1024, per impostare il numero di File Descriptor dovremo editare il file /etc/system

set rlim_fd_max = 4096
   

7.6.4. File descriptors con FreeBSD

L'approccio al problema dei file descriptors nei sistemi BSD è totalmente diverso e naturalmente più funzionale se paragonato con i sistemi linux, la voce di configurazione che nel kernel controlla questa impostazione prende il nome di MAXFILES.

Ultimamente questo tipo di approccio è stato leggermente modificato, infatti i nuovi kernel dei sistemi FreeBSD controllano dinamicamente il numero delle tabelle interne che vengono utilizzate dal sistema operativo, tale impostazione viene determinata prendendo come riferimento la quantità di memoria che è stata fisicamente installata sul server di produzione. Il file di configurazione del Kernel di FreeBSD (e di molti alti sistemi BSD) si trova in /usr/src/sys/i386/conf/GENERIC, l'impostazione che determina questa modalità di funzionamento è

maxusers      0
   

7.6.4.1. MAXFILES

se vogliamo impostare manualmente il valore dei descrittori di files dovremmo editare il file di configurazione del kernel, questa modifica vale anche per i sistemi NetBSD ed OpenBSD

options       MAXFILES=8192
    

possiamo verificare il valore dei file descriptors attivi in un dato momento utilizzando il comando sysctl(8), le variabili del kernel di un sistema FreeBSD possono essere visualizzate ed eventualmente modificate utilizzando il comando sysctl

% sysctl -a | grep kern.maxfiles
kern.maxfiles: 4040
kern.maxfilesperproc: 3636
    

come per i sistemi linux per visualizzare il numero di files descriptors attivi possiamo anche utilizzare l'opzione di shell ulimit

% ulimit -n
4040
    

non è dunque necessario ricompilare il kernel per impostare il valore corretto dei file descriptors, sarà sufficente editare il file /etc/sysctl.conf

kern.maxfiles=4040
kern.maxfilesperproc=3636
    

per concludere possiamo dire che modificare manualmente il numero di file descriptors in un sistema BSD ha senso solo se si vuole ottimizzare le prestazioni di un server di rete ad alto traffico.

7.6.4.2. MBUF

Un'altro collo di bottiglia per il kernel di un sistema FreeBSD è rappresentato dalla corretta impostazione del valore di MBUF. MBUF sono dei pezzi di memoria che vengono utilizzati dal kernel per consentire tutte le connessioni di rete. Il numero di MBUF scala in relazione alla impostazione dell'opzione MAXUSERS all'interno del file di configurazione del kernel, anche in questo caso con i nuovi kernel di FreeBSD, questo valore viene impostato in maniera automatica così come avviene per i descrittori di files, anche in questo caso potrebbe rendersi necessario aumentare il valore degli MBUF. L'opzione NMBCLUSTERS controlla il numero di MBUFS creati dal kernel di sistema

% netstat -m
129/320/65536 mbufs in use (current/peak/max):
        129 mbufs allocated to data
128/260/16384 mbuf clusters in use (current/peak/max)
600 Kbytes allocated to network (1% of mb_map in use)
0 requests for memory denied
0 requests for memory delayed
0 calls to protocol drain routines
    

questo sistema FreeBSD dispone di 16384 MBUF, se volessimo aumentare questo valore dovremmo modificare il file di configurazione del Kernel così come segue

options               NMBCLUSTERS=32768
    

questa impostazione vale anche per NetBSD e OpenBSD

7.6.5. File descriptors con Windows

il numero massimo di file descriptor è 2048, questo valore é preimpostato nella libreria dinamica MSVCRT.DLL e non può essere modificato se non ricompilando la DLL stessa.

7.6.6. File handles con OS/2

Se si utilizza il runtime EMX (The UN*X to OS/2-EMX Porting) è possibile definire il numero massimo di file handles modificando il file config.sys

SET EMXOPT=-h#
   

questa impostazione fissa il limite massimo di file handles a #, il valore di # deve essere un numero compreso tra 10 e 65536, l'ultima versione disponibile compilata con il runtime EMX supporta solo 256 file handles.