Tutti gli amministratori di sistema sanno qual’è la funzione del paging (swapspace).
Nato come metodo di protezione negli anni in cui la RAM era una risorsa preziosissima sui sistemi server, ha cambiato via via connotazione, diventando uno strumento di ottimizzazione delle prestazioni.
Forsenontuttisannoche i sistemi LINUX usano una politica molto aggressiva nel tentativo di ottimizzare le risorse disponibili. Ogni risorsa non utilizzata è considerata uno spreco.
Se osservate l’occupazione di RAM in un sistema LINUX, vi accorgerete che la memoria libera è sempre poca. In effetti la memoria non utilizzata è considerata dal kernel come uno spreco e, come tale, va evitato. Per questo motivo viene impiegata come cache/buffer per aumentare le prestazioni di lettura/scrittura dello storage.
Nei kernel della serie 2.6 questo concetto si spinge oltre: non solo viene utilizzata la RAM libera, ma il sistema cerca di ottenerne altra con una politica molto aggressiva.
Tale politica consiste nel mandare in paging nella memoria virtuale alcune parti di memoria non utilizzate di recente come quella dei processi in “idle” cioè che pur essendo in esecuzione, non stanno impegnando la CPU di sistema. In questo modo si può riutilizzare la memoria precedentemente allocata per incrementare le prestazioni complessive della macchina.
L’aggressività è regolabile attraverso il parametro swappiness del kernel. La wikipedia (verificate il link precedente) riporta l’informazione errata che con un valore zero il sistema si comporta in maniera assolutamente rispettosa dei processi in idle, utilizzando il paging solo in caso di reale necessità per evitare l'”out of memory”.
Non è così. Purtroppo impostando a zero tale parametro, il sistema continua a swappare alcuni programmi im esecuzione.
Infatti il kernel calcola in questo modo la tendenza ad utilizzare lo swapping:
swap_tendency = mapped_ratio/2 + distress + vm_swappiness;
Come vedete il terzo parametro vm_swappiness azzerato non è sufficiente ad annullare la tendenza nella formula. Se la tendenza raggiunge un valore > 100 il kernel reclamerà memoria dai processi in esecuzione. Il primo parametro mapped_ratio indica la percentuale di memoria mappata, il secondo distress misura la difficoltà del kernel nel liberare memoria. Quando il kernel decide di reclamare memoria la distress sarà zero, se ci saranno successivi tentativi il valore si eleverà progressivamente fino a 100.
Come dobbiamo fare se abbiamo la necessità di inibire l’uso dello swapping se non in caso di memoria di sistema effettivamente scarsa?
Purtroppo non c’è alcun modo. Googlando su internet troverete un sacco di persone che hanno posto la stessa domanda.
La risposta standard di alcuni individui piuttosto saccenti è del tipo “Pretendete di sapere come va utilizzata la memoria meglio di chi ha scritto il kernel del vostro sistema? Lasciate che il vostro sistema si gestisca da solo e lo farà per il meglio!”.
Tali risposte sono a mio avviso di una cecità clamorosa. Non metto in dubbio l’ottimo lavoro svolto dagli sviluppatori del nostro kernel preferito.
In linea di massima il sistema fa un ottimo lavoro per sfruttare al massimo le risorse, ma non si può generalizzare.
Vi espongo un caso concreto per il quale la scelta del kernel di swappare i processi non è assolutamente una buona idea.
Siamo su un server che funge da hypervisor KVM con macchine virtuali poco attive e parametro swappiness=0.
Con riferimento al precedente articolo, ecco qual’era la situazione durante l’esportazione delle immagini delle macchine virtuali:
[root@kvm backup]# free total used free shared buffers cached Mem: 7801732 5711072 2090660 0 53984 1507288 -/+ buffers/cache: 4149800 3651932 Swap: 9214968 1540844 7674124
A fronte di una quantità esorbitante di memoria libera di cui una parte utilizzata per la cache, abbiamo uno swapfile che è cresciuto fino a oltre 1,5GB.
Alcuni processi in esecuzione sono stati “paginati” nella memoria virtuale.
Quali? Purtroppo la scelta del kernel è caduta su……. le macchine virtuali in esecuzione!
Ho potuto verificarlo lanciando il comando smem.
Ecco quali erano i processi che utilizzavano lo swap:
[root@kvm backup]# smem PID User Command Swap USS PSS RSS ......... ......... 14353 root /sbin/dmeventd 0 16616 16778 17904 1661 named /usr/sbin/named -u named 0 17708 17807 18752 2480 qemu /usr/libexec/qemu-kvm -name 115404 510852 511596 677636 2353 qemu /usr/libexec/qemu-kvm -name 159656 868056 868880 907940 12114 qemu /usr/libexec/qemu-kvm -name 394384 1026608 1027327 1030820 2535 qemu /usr/libexec/qemu-kvm -name 445992 1615800 1616581 2217232
Effettivamente erano processi che non stavano lavorando molto.
Ma una di queste macchine virtuali contiene il server su cui gira questo blog. Una macchina virtuale con la memoria swapping ha prestazioni talmente scarse da essere assolutamente inutilizzabile! Infatti, tentando di collegarsi via web al sito in quel momento, il browser andava in timeout.
Quindi, pur non pretendendo di di sapere come deve essere impiegata la RAM meglio di chi sviluppa il kernel, vorrei che, almeno in alcuni casi particolari, fosse possibile evitare il paging in virtuale di alcuni processi o, al limite, imporre al kernel di utilizzare lo swapspace solo in caso di critica mancanza di memoria.
Purtroppo non mi risulta che sia possibile configurare il sistema con le caratteristiche di cui sopra, quindi ho dovuto ricorrere ad una soluzione molto pericolosa: disattivare lo swap.
Con oltre 2 GB di memoria libera non mi aspetto problemi di sorta, l’hypervisor ed i pochi servizi in esecuzione non avranno mai necessità superiori.
Ma è comunque una soluzione pericolosa da non utilizzare assolutamente in server in produzione.
Il sistema gira senza paging da un paio di settimane e le prestazioni delle macchine virtuali sono tornate ad un buon livello, ma vorrei che ci fosse un modo meno rischioso per ottenere lo stesso risultato.
Fabrizio Vettore
Grazie Fabrizio, mi è servito molto, sopratutto come conferma.