Introduzione
Un server Linux, come ogni altro computer con cui interagisci, esegue delle applicazioni. Ogni applicazione in esecuzione può utilizzare uno o più cosiddetti "processi". Mentre Linux gestisce il basso livello nel ciclo di vita dei processi, in diverse occasioni un sysadmin potrebbe aver bisogno di interagire con il sistema operativo per gestirli da un alto livello.
In questa guida ti verrà spiegato come controllare i processi in esecuzione sul tuo server Linux e come occuparti della loro gestione. Tutte le distribuzioni Linux seguono un funzionamento simile dei processi.
Se hai bisogno di effettuare queste operazioni sul tuo server dovrai prima connetterti tramite una connessione SSH. Se non l’hai ancora fatto, ti consigliamo di seguire la nostra guida per connetterti in sicurezza con il protocollo SSH. In caso di server locale puoi passare al punto successivo e aprire il terminale del tuo server.
Come monitorare i processi su Linux
top
Il miglior modo per monitorare i processi in esecuzione sul tuo server Linux consiste nell’utilizzo del comando top:
$ top
top - 15:14:40 up 46 min, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 56 total, 1 running, 55 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 1019600k total, 316576k used, 703024k free, 7652k buffers
Swap: 0k total, 0k used, 0k free, 258976k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 24188 2120 1300 S 0.0 0.2 0:00.56 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.07 ksoftirqd/0
6 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
7 root RT 0 0 0 0 S 0.0 0.0 0:00.03 watchdog/0
8 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 cpuset
9 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 khelper
10 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs
Come puoi vedere nella schermata di esempio, dopo aver digitato il comando top, diverse informazioni appariranno a video:
- Nella prima riga puoi visualizzare l'orario di sistema (15:14:40), il tempo da quando il server è up (46 min), gli utenti che sono collegati via SSH (1 user) e il carico medio del server (load average) calcolato sull'ultimo arco di tempo di un minuto, cinque minuti e quindici minuti;
- Dalla seconda alla quinta riga, trovi le informazioni statistiche sul sistema, come ad esempio il numero totale dei processi (tasks) e il loro stato, il consumo della CPU e della memoria RAM della macchina;
- In basso potrai vedere, uno per uno, i processi in esecuzione.
Riprendendo l’esempio di sopra, puoi notare come al momento ci siano 1 processo in esecuzione e 55 processi non in esecuzione. Occorre specificare che, mentre il processo attivo consumerà risorse, quelli in fase di sleeping non generano alcun consumo di CPU per il sistema.
htop
Una versione migliorata di top è htop, disponibile se installata nelle repository. Per abilitare il comando, sarà necessario installarlo tramite comando:
$ sudo apt-get install htop
Il nuovo comando fornirà una presentazione delle informazioni più comprensibile e gradevole all’utente. Puoi vederne un esempio di seguito:
htop
Mem[||||||||||| 49/995MB] Load average: 0.00 0.03 0.05
CPU[ 0.0%] Tasks: 21, 3 thr; 1 running
Swp[ 0/0MB] Uptime: 00:58:11
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
1259 root 20 0 25660 1880 1368 R 0.0 0.2 0:00.06 htop
1 root 20 0 24188 2120 1300 S 0.0 0.2 0:00.56 /sbin/init
311 root 20 0 17224 636 440 S 0.0 0.1 0:00.07 upstart-udev-brid
314 root 20 0 21592 1280 760 S 0.0 0.1 0:00.06 /sbin/udevd --dae
389 messagebu 20 0 23808 688 444 S 0.0 0.1 0:00.01 dbus-daemon --sys
407 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.02 rsyslogd -c5
408 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.00 rsyslogd -c5
409 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.00 rsyslogd -c5
406 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.04 rsyslogd -c5
553 root 20 0 15180 400 204 S 0.0 0.0 0:00.01 upstart-socket-br
Come catalogare i processi
ps
I comandi top e htop, illustrati in precedenza, forniscono un’interfaccia gradevole, che richiama molto un task manager, per visualizzare alcune informazioni sui processi in esecuzione.
A volte potresti dover ricorrere però a strumenti più efficaci per monitorare i processi in esecuzione. Uno di questi è ps.
Se richiamato senza ulteriori specifiche, il comando restituisce solamente l’elenco dei processi appartenenti all’utente:
$ ps
PID TTY TIME CMD
1017 pts/0 00:00:00 bash
1262 pts/0 00:00:00 ps
Interpretando la schermata, è chiaro come, al momento, gli unici due processi eseguiti dall’utente siano bash (cioè il prompt dei comandi) e ps stesso.
Per una visione più completa dei processi all’interno del sistema, potrai aggiungere la specifica "aux" al comando:
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.2 24188 2120 ? Ss 14:28 0:00 /sbin/init
root 2 0.0 0.0 0 0 ? S 14:28 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 14:28 0:00 [ksoftirqd/0]
root 6 0.0 0.0 0 0 ? S 14:28 0:00 [migration/0]
root 7 0.0 0.0 0 0 ? S 14:28 0:00 [watchdog/0]
root 8 0.0 0.0 0 0 ? S< 14:28 0:00 [cpuset]
root 9 0.0 0.0 0 0 ? S< 14:28 0:00 [khelper]
. . .
Questa opzione dice a ps di mostrare tutti i processi di tutti gli utenti in un formato user-friendly.
Per una visione ad albero, dove puoi vedere la struttura gerarchica e le relazioni intercorrenti tra i processi, usa invece il comando:
$ ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 3 0 0 ? -1 S 0 0:00 \_ [ksoftirqd/0]
2 6 0 0 ? -1 S 0 0:00 \_ [migration/0]
2 7 0 0 ? -1 S 0 0:00 \_ [watchdog/0]
2 8 0 0 ? -1 S< 0 0:00 \_ [cpuset]
2 9 0 0 ? -1 S< 0 0:00 \_ [khelper]
2 10 0 0 ? -1 S 0 0:00 \_ [kdevtmpfs]
2 11 0 0 ? -1 S< 0 0:00 \_ [netns]
. . .
Facendo attenzione alle informazioni presenti a video, potrai constatare che i processi con nomi preceduti da \_ sono “figli” del processo “padre” kthreadd.
ID di un processo
Nei sistemi basati su Linux e Unix, a ogni processo viene assegnato un ID o PID. In questo modo i processi vengono identificati da un numero univoco e tracciati dal sistema. Trovi l'ID del processo nella prima colonna "PID" dei risultati mostrati in precedenza.
Puoi ottenere in maniera immediata l’ID di un processo, utilizzando anche il comando pgrep seguito dal nome del processo che ti interessa:
$ pgrep bash
1017
Nell’esempio, utilizzando pgrep con il nome del processo relativo al prompt dei comandi, ci verrà restituito l’ID 1017.
Il primo processo che va in esecuzione all’avvio del sistema, chiamato init, avrà ID pari a 1.
$ pgrep init
1
Il processo principale init è responsabile del dispiegamento di tutti gli altri processi sul sistema. Tutti i processi eseguiti successivamente avranno un numero di ID più grande, secondo un ordine crescente.
Il genitore di un processo è il responsabile del suo dispiegamento sul sistema. I processi genitori sono dotati di un PPID (Parent Process ID), che potrai vedere negli specchietti informativi dei processi, richiamabili tramite i principali comandi visti in precedenza.
Ogni comunicazione dell’utente con il sistema, riferita ai processi, coinvolge sempre una traduzione tra i nomi dei processi e il loro ID, motivo per cui spesso ti viene mostrato il PID dai servizi per la loro gestione.
Relazioni genitore-figlio fra processi
La creazione di un processo figlio avviene in due step:
- fork(), il quale crea un nuovo spazio di indirizzamento e copia le risorse possedute dal processo genitore per renderle fruibili dal processo figlio;
- exec(), il quale carica un file eseguibile nello spazio di indirizzamento e lo esegue.
Se un processo figlio termina prima del suo genitore, il primo rimane come processo zombie fino a che il genitore non completi l’acquisizione delle informazioni da esso o non indichi al kernel di non avere più bisogno di quelle informazioni.
Alla fine di questo passaggio, le risorse del processo in sospeso vengono liberate. Se accade, invece, che il processo genitore muoia prima del figlio, allora il processo init() si occuperà di riassegnare a un altro processo quello rimasto superstite.
Come inviare segnali ai processi
Ogni processo in Linux risponde ai segnali. Essi sono dei messaggi, inviati a livello di sistema operativo, per chiedere a dei programmi di cambiare o terminare un determinato comportamento.
Come inviare segnali a processi tramite il PID
Il modo migliore per inviare dei segnali a un programma è tramite il comando kill. Tramite questo comando, ovviamente, si tenta di terminare un processo.
Un esempio su come dovresti utilizzarlo potrebbe essere:
$ kill PID_processo
Tramite questo esempio di comando, si invierebbe un segnale di TERM al processo. Tale segnale serve a chiedere al processo se può terminare. Ciò permette al programma di completare le procedure non interrompibili istantaneamente per poi liberare le risorse e uscire.
Se il programma non dovesse rispondere al segnale ricevuto tramite il normale comando kill, allora puoi forzarne la chiusura inviando il segnale KILL al posto di TERM.
$ kill -KILL PID_processo
Questo segnale speciale non verrà inviato al programma, bensi al kernel, ovvero il “nucleo” del sistema operativo, che procederà a interrompere il processo interessato. Forzare il termine di un processo è consigliato solo nel caso in cui ti trovi di fronte a un programma che tende a ignorare la richiesta TERM.
I segnali sono anche identificati da valori numerici perciò, nel caso in cui potessi averne bisogno, potresti associare al comando kill, per esempio, la stringa -15 al posto di -TERM o la stringa -9 al posto di -KILL.
Come inviare segnali per altri scopi
Il comando kill non serve solo a inviare segnali per richiedere l’arresto dei processi, ma può essere usato per farti interagire in altri modi con i diversi programmi.
Puoi, per esempio, dare un segnale di HUP (hang-up) per chiedere a un programma di riavviarsi.
Per mostrarti un esempio, prova con Apache, che segue il comportamento di molti programmi:
$ sudo kill -HUP PID_diApache
Per conoscere la lista di tutti i segnali che puoi inviare tramite il comando kill, basterà inserire la stringa:
$ sudo kill -1
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
. . .
Come potrai osservare dall’output, riceverai sia i valori numerici che i nomi dei segnali da poter associare al comando per inviare diverse tipologie di segnale.
Come inviare segnali ai processi tramite nome
A parte il PID, puoi inviare segnali ai processi anche utilizzando i loro nomi. Per far ciò, dovrai utilizzare il comando pkill seguito dal nome del processo interessato:
$ pkill -9 ping
Traducendo la stringa di esempio, avrai inviato un comando di chiusura forzata al processo di nome ping.
Lo stesso comando è equivalente alla stringa:
$ pkill -9 ‘pgrep ping’
Se invece volessi interagire con ogni istanza di un processo (per esempio con tutte le istanze in esecuzione di Firefox), ti basterà usare il comando killall come in esempio:
$ killall firefox
Per esempio, inviando un TERM tramite il comando killall, termineresti tutte le istanze attive di Firefox.
Come manipolare le priorità dei processi
In un ambiente server, potresti aver bisogno di sistemare la priorità assegnata tra i diversi processi: alcuni potrebbero necessitare di maggiori risorse o di priorità temporale, mentre altri potrebbero essere eseguiti successivamente.
Linux gestisce il sistema delle priorità tramite il comando niceness.
A seconda del consumo di risorse, un programma viene considerato meno carino, poiché più “egoista” nel consumo di risorse o più carino, poiché più “generoso” nel risparmio di risorse da poter dedicare ad altri processi. Solitamente, i primi hanno priorità più alta a dispetto degli altri che ne hanno una più bassa.
Tornando a guardare l’esempio del comando top, potrai notare una colonna denominata NI. Questo è il valore nice del processo.
$ top
Tasks: 56 total, 1 running, 55 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.3%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 1019600k total, 324496k used, 695104k free, 8512k buffers
Swap: 0k total, 0k used, 0k free, 264812k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1635 root 20 0 17300 1200 920 R 0.3 0.1 0:00.01 top
1 root 20 0 24188 2120 1300 S 0.0 0.2 0:00.56 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.11 ksoftirqd/0
Il range dei valori nice può andare da -19/-20 (priorità più alta) a 19/20( priorità più bassa).
Per eseguire un programma con un certo valore, puoi usare proprio il comando nice:
$ nice -n 15 nome_comandodaeseguire
La stringa qui sopra può funzionare solo quando avvii un nuovo programma.
Se dovessi, invece, aver bisogno di cambiare il valore di priorità di un programma già in esecuzione, dovrai ricorrere al comando renice.
$ renice 0 PID_processodicuicambiarepriorità
N.B. Mentre il comando nice può essere combinato con i nomi dei processi, il comando renice funziona necessariamente con i PID.
Conclusioni
La gestione dei processi su Linux è un argomento che a volte mette in difficoltà i nuovi utenti, a causa della differenza nell’utilizzo degli strumenti tramite terminale rispetto a quelli con un'interfaccia grafica.
Anche se la sintassi dei comandi può risultare ostica all’inizio, saper lavorare con il terminale rimane una competenza must-have per poter monitorare al meglio l'andamento dei processi sul proprio server. Con pratica e ripetizione, queste operazioni diventeranno via via più intuitive e spontanee.