Tutorial > Come monitorare e gestire i processi su Linux

Come monitorare e gestire i processi su Linux

Pubblicato il: 15 gennaio 2021

Linux Sistema

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:

  1. fork(), il quale crea un nuovo spazio di indirizzamento e copia le risorse possedute dal processo genitore per renderle fruibili dal processo figlio;
  2. 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.