/dev/random

Ottimizzare Linux per dispositivi mobili e server (1)

Ci sono molti piccoli accorgimenti che si possono adottare per adattare il nostro sistema Linux all'uso che lo aspetta, che si tratti di un sistema desktop o di un server.

Martin Michlmayr ha pubblicato un paio di articoli su come ottimizzare Linux per l'uso su dispositivi embedded (NSLU2 nel caso specifico): per la riduzione della memoria occupata e per il funzionamento su memorie flash.

Ma molti consigli valgono anche in generale per migliorare le prestazioni di Linux, sia su dispositivi portatili che non. Ne traduco qui alcuni e mi permetto di aggiungerne altri che possono tornare utili, con un'occhio all'uso desktop e uno all'uso server.

Accesso al disco

Linux ha un ottimo sistema di gestione dei dischi, ma di default offre funzionalità che migliorano l'affidabilità e la tracciabilità delle operazioni, perfette per un server, ma costose per le prestazioni su un PC desktop, un portatile o un palmare/cellulare.

Atime

Una di queste è l'atime dei file: viene memorizzata su disco la data e ora dell'ultimo accesso al file. Questa funzione è utile in rarissimi casi, pertanto si può disattivare senza problemi, perché causa una scrittura su disco per ogni lettura effettuata. Sui normali dischi si guadagna in prestazioni, mentre sulle memorie flash si guadagna anche in durata del supporto (le scritture sono limitate su questi dispositivi). Per disattivarlo è sufficiente modificare (da utente root) il file /etc/fstab aggiungendo l'opzione “noatime” ai vari mount-point.

Commit time

Sempre in questo file possiamo modificare il tempo di commit di ext3, in modo da effettuare meno scritture su disco, e da scrivere più dati in un colpo solo, migliorando le prestazioni. Di default sono 5 secondi, ma possiamo alzarlo a 2 minuti (120 secondi). In questo caso lo svantaggio è che se salta la corrente quando i dati non sono ancora stati scritti se ne perderanno di più. Il mio consiglio è di avere sempre un UPS (un gruppo di continuità) anche piccolo (500-650 VA sono sufficienti per reggere 5-10 minuti, dipende dal carico del vostro PC) ed evitare sia questo problema che quello delle sovratensioni che si verificano ogni tanto e che bruciano alimentatori.

fstab

Andiamo quindi a vedere come modificare il nostro /etc/fstab

# /etc/fstab: static file system information.#

# <file system> <mount point>   <type>  <options>                     <dump>  <pass>

proc            /proc           proc    defaults                        0       0

/dev/hda1       /               ext3    defaults,errors=remount-ro,noatime,commit=120 0       1
/dev/hda3       /home           ext3    defaults,noatime,commit=120     0       2
/dev/hda4       /usr            ext3    defaults,noatime,commit=120     0       3
/dev/hda2       none            swap    sw                              0       0

syslog

Possiamo anche modificare syslog perché bufferizzi i log prima di scriverli su disco. Sui normali dischi questo può ridurre la frammentazione, oltre a evitare di scrivere continuamente su disco pochi bytes, mentre sulle memorie flash il vantaggio è lo stesso del noatime: si prolunga la vita della flash. Lo svantaggio è che se il computer ha un crash (molto raro, ma può succedere) o se manca la corrente si perdono i dati dei log degli ultimi minuti. Quindi non attivatelo se state testando nuovi kernel instabili, moduli proprietari del kernel o driver per X o per qualsiasi cosa giri coi permessi di root e vi servono log affidabili. Su un server potrebbe essere addirittura conveniente togliere il buffering già presente su alcuni file.

Il file da modificare, in questo caso, è /etc/syslog.conf e basta aggiungere un trattino (il normale “meno”) prima del nome del file di log. Ecco un esempio:

#  /etc/syslog.conf     Configuration file for syslogd.#

# First some standard logfiles.  Log by facility.

#auth,authpriv.*           /var/log/auth.log
*.*;auth,authpriv.none    -/var/log/syslog
#cron.*                    /var/log/cron.log
daemon.*                  -/var/log/daemon.log
kern.*                    -/var/log/kern.log
lpr.*                     -/var/log/lpr.log
mail.*                    -/var/log/mail.log
user.*                    -/var/log/user.log

Questo è un pezzo del file standard della Debian. Come vedete alcuni file hanno già il trattino davanti, e vengono bufferizzati. Si tratta solitamente di log meno importanti, per cui non è necessario avere un riscontro preciso nei file, mentre, ad esempio, il file di log delle autorizzazioni (quello che vi scrive “root ha fatto login alle 02:37:21 del 25 dicembre”) viene scritto direttamente su disco per motivi di sicurezza. Qui tale log è disattivato.

Le prestazioni guadagnate in questo caso non sono granché, quindi questa modifica ha senso solo su dispositivi con flash memory: palmari, cellulari, media-center e simili, dove interessa poco avere log precisi ed aggiornati. Si può invece aggiungere (o decommentare nel caso della Debian) una sezione apposita che vada a scrivere i log su una console non utilizzata. Io uso quella in Alt-F12:

#
# I like to have messages displayed on the console, but only on a virtual
# console I usually leave idle.
#
daemon,mail.*;\
        news.=crit;news.=err;news.=notice;\
        *.=debug;*.=info;\
        *.=notice;*.=warn       /dev/tty12

In questo modo c'è un riscontro diretto in tempo reale con i più importanti servizi di sistema. Su un server si può addirittura lasciare attiva quella console di default, in modo da vedere i messaggi di log semplicemente accendendo il monitor, senza fare login.

Memoria

Nei PC moderni ormai la memoria si spreca. Non è raro avere 1, 2 o addirittura 4 Gb di RAM, soprattutto se il PC è in dual-boot con Windows per giocare.

SWAP

Allora la cosa migliore da fare è usare tale memoria e limitare al minimo l'uso della swap e del disco in generale, molto più lento della RAM. Nei kernel 2.6 c'è un parametro apposta per indicare al sistema quanto deve usare la swap: /proc/sys/vm/swappiness

Basta fare un cat di tale file per vederne l'impostazione, e con un echo regolare la quantità che vogliamo:

~# cat /proc/sys/vm/swappiness
60

Se vogliamo ridurre al minimo l'uso della swap (a scapito dei buffer e delle cache dei file aperti) possiamo metterlo a 0, per esempio su un sistema desktop in cui si passa spesso da un'applicazione all'altra. Se vogliamo che il sistema metta in swap più memoria possibile possiamo metterlo a 100, per esempio su un server dove ci sono alcune applicazioni che vengono lanciate ogni tanto (i backup) e quindi possono essere messe in cache, mentre vogliamo massimizzare i buffer per avere più dati possibili in memoria in ogni momento (per esempio le pagine web da servire ai client). Basterà quindi un:

echo 10 &gt;/proc/sys/vm/swappiness

per abbassare senza esagerare la tendenza allo swap. Possiamo rendere permanente questa modifica aggiungendo al file /etc/sysctl.conf questa riga:

vm/swappiness = 10

In questo file si possono inserire tutte le modifiche da fare al boot a qualsiasi cosa si trovi sotto /proc/sys come vedremo tra poco.

Cache in scrittura

A metà tra l'uso della memoria e quello del disco viene il laptop_mode, un sistema per impostare il sistema per l'uso minimo del disco. Ormai la sintassi per le modifiche è chiara, quindi andiamo a vedere direttamente come modificare sysctl.conf e quali parametri possiamo impostare:

vm/laptop_mode = 5
vm/dirty_writeback_centisecs = 12000
vm/dirty_expire_centisecs = 12000
vm/dirty_ratio = 95
vm/dirty_background_ratio = 20

Il primo parametro indica dopo quanti secondi, dal risveglio del disco causato da una lettura, iniziare una scrittura. Impostato a 0 disattiva il laptop_mode. Impostato troppo basso può rallentare la lettura per effettuare la scrittura. Qui l'abbiamo impostato a 5 secondi. Abbastanza da permettere di finire la lettura, e abbastanza poco da permettere al disco da tornare a dormire presto. Può essere utile, assieme ai parametri successivi, per l'uso con le flash memory per ridurre le scritture al minimo e migliorare le prestazioni, soprattutto se si ha una buona quantità di RAM.

dirty_writeback_centisecs specifica ogni quanto il kernel deve controllare se ci sono dati da scrivere, in centesimi di secondo. dirty_expire_centisecs specifica dopo quanto tempo i dati da scrivere devono fisicamente essere scritti sul disco. Conviene impostare questi due valori con lo stesso numero. Qui il kernel controlla ogni 120 secondi (2 minuti) se ci sono dati da scrivere e, se ci sono, li scrive su disco. Su un notebook, per far dormire il più possibile il disco, si può impostare a 15-20 minuti, stando attenti al livello della batteria.

dirty_ratio specifica quale percentuale della memoria usare per i dati in attesa. Possiamo impostarlo molto alto, in quanto i dati vengono comunque scritti su disco se la memoria serve per altro. dirty_background_ratio specifica la percentuale di memoria occupata dai dati in attesa alla quale il processo di scrittura si può fermare. Col parametro che abbiamo impostato sopra il sistema cercherà di scrivere dati su disco almeno finché questi non occuperanno il 20% o meno della memoria disponibile.

Questi parametri hanno senso su un portatile o su un dispositivo con memoria flash, ma possono aiutare anche a ridurre la frammentazione dei file su dischi con poco spazio libero (mentre su dischi con molto spazio libero il kernel ha un sistema di allocazione che riduce automaticamente la frammentazione man mano che si usa il disco).

Ridurre la memoria occupata

Naturalmente ha poco senso avere 1 Gb di memoria e lanciare decine di daemon in background senza usarli mai. Conviene quindi “spegnerli” ed attivarli solo quando servono. Per questa modifica bisogna capire, almeno a grandi linee, come funziona il sistema di init di Linux.

Al boot il primo software ad essere eseguito, dopo il kernel, è init, che legge il file /etc/inittab e ne lancia i vari script in base alle informazioni che vi trova. Tra questi c'è l'attivazione del runlevel di default, che in Debian è sempre il 2. Il livello 0 significa “spegnimento”, il livello 1 “monoutente”, il livello 6 “riavvio”. I livelli da 3 a 5 sono personalizzabili, ma per i nostri usi li considereremo equivalenti al livello 2. Quindi dovremo impostare i daemon che ci servono perché partano (start, quindi S) ai livelli da 2 a 5, e perché si fermino (kill, quindi K) ai livelli 0, 1 e 6, mentre impostaremo quelli che usiamo poco (apache, MySQL e Postgres, per esempio, se saltuariamente sviluppiamo per il web) perché siano K (kill) a tutti i livelli. Li avvieremo manualmente quando ci servono. In Debian possiamo usare update-rc.d per automatizzare il tutto, e avremo a disposizione anche alcune opzioni che ci semplificano la vita:

update-rc.d -f apache2 remove
update-rc.d -f mysql remove
update-rc.d -f postgresql-8.2 remove

I nomi da usare per i vari servizi li trovate guardando come si chiamano i file in /etc/init.d.

Questa forma (remove) cancella tutti i link di avvio e di stop del servizio, che quindi andrà sia avviato che fermato a mano prima di spegnere il computer. Dobbiamo quindi ripristinare lo spegnimento dei servizi allo shutdown/reboot/single-user:

update-rc.d apache2 stop 20 0 1 2 3 4 5 6 .
update-rc.d mysql stop 20 0 1 2 3 4 5 6 .
update-rc.d postgresql-8.2 stop 20 0 1 2 3 4 5 6 .

Buona parte degli script di avvio/fermata dei daemon tiene traccia del funzionamento di un daemon, quindi non darà alcun warning allo shutdown. Attenzione al punto alla fine delle righe!

Conclusioni

Si chiude qui questo primo articolo sull'ottimizzazione di Linux. Ci sono molti altri piccoli e grandi accorgimenti adottabili. Li vedremo nella prossima puntata.