Objectif de cet atelier pratique :
- surveiller et gérer les processus sur un système Linux
Linux, un système multitâche
Linux est un système multitâche, ce qui veut dire que vous pouvez exécuter des programmes en parallèle, comme bon vous semble. Chaque programme occupe une certaine quantité de ressources, notamment de mémoire vive (RAM) et de processeur (CPU). Par conséquent, un nombre croissant de processus a pour effet de ralentir le système.
Tous ces programmes ne tournent pas vraiment en même temps, à proprement parler. Chaque processus reçoit un peu de temps de calcul, à tour de rôle, et cette répartition des ressources s’effectue tellement rapidement que l’utilisateur humain a l’illusion que tout se passe simultanément. Tous les processus sont soigneusement séparés les uns des autres, ce qui signifie qu’une application mal codée qui plante n’entraînera pas le reste du système dans sa déconfiture.
Tous les systèmes Linux contiennent une série d’outils pour surveiller et gérer les processus. Nous allons en présenter quelques-uns en détail, sous forme d’un atelier pratique agrémenté d’un zeste de théorie.
Surveiller un processus : ps
Connectez-vous à votre console Linux – directement ou à distance via SSH – et invoquez la commande suivante :
$ ps
Elle vous retourne un petit bilan qui ressemble à ceci :
PID TTY TIME CMD 1042 pts/0 00:00:00 bash 1071 pts/0 00:00:00 ps
Ne vous inquiétez pas si les numéros ne sont pas les mêmes que sur ma machine. C’est normal.
Les plus curieux d’entre vous ont probablement déjà parcouru la page du manuel en ligne de ps(1)
pour avoir une idée de ce qu’ils viennent de faire. Et ils ont trouvé la définition suivante :
ps - report a snapshot of the current processes.
La commande ps
présente en quelque sorte un cliché instantané des processus en cours. Invoquée sans autre argument, elle se limite aux processus de la console active. Ce qui nous intéresse ici, ce sont les deux colonnes PID
et CMD
. PID
(Process Identifier) est un nombre unique qui identifie un processus sans ambiguïté. Quant à la colonne CMD
(Command), elle correspond à la commande qui a déclenché le processus.
La colonne TTY
nous indique le terminal à partir duquel le processus a été lancé. Dans l’exemple précédent, pts/0
correspond à mon terminal graphique, étant donné que je me suis connecté à distance depuis mon ordinateur portable. Si j’avais invoqué la commande ps
directement dans la première console, le résultat aurait ressemblé à quelque chose comme ceci :
PID TTY TIME CMD 1042 tty1 00:00:00 bash 1071 tty1 00:00:00 ps
Enfin, TIME
indique le temps processeur utilisé par le processus, ce qu’il ne faut pas confondre avec le temps réel écoulé depuis le lancement du processus. L’information 00:00:00
signifie tout simplement que bash
et ps
utilisent tout au plus une fraction de seconde de temps CPU depuis leur lancement, ce qui est tout à fait normal.
Dans notre exemple, le shell Bash « tourne » avec le PID 1042. La commande ps
– qui est également un processus – affiche le PID 1071
. Tous les processus en cours ont reçu un identifiant unique se situant entre 1 et 32767. Chaque nouveau processus se voit attribuer le prochain PID disponible. Lorsqu’un processus est terminé d’une façon ou d’une autre, il libère son PID. Une fois que le PID maximum est atteint, le prochain nouveau processus sera doté du plus petit identifiant disponible.
Afficher les processus en cours
Maintenant que nous avons compris le principe, essayons d’aller un peu plus loin. La commande ps
accepte un certain nombre d’arguments, dont voici les plus fréquemment utilisés. Notez qu’ils sont invoqués sans le tiret -
initial :
x
affiche l’ensemble de vos propres processus en cours.a
ajoute les processus de tous les autres utilisateurs à la liste.u
fournit des renseignements supplémentaires comme le propriétaire du processus (USER
), l’utilisation de processeur (%CPU
) ou de la mémoire (%MEM
).
La syntaxe des arguments de la commande ps
peut prêter à confusion, selon la présence ou l’absence du tiret -
initial. Retenez simplement que ps a
ne signifie pas la même chose que ps -a
. Consultez la page man 1 ps
pour les détails.
L’option x
affiche l’ensemble de mes processus dans toutes les consoles, ainsi que ceux qui ne sont rattachés à aucune console. Dans l’exemple qui suit, je me suis connecté à distance (sshd
) à ma machine :
$ ps x PID TTY STAT TIME COMMAND 1032 ? Ss 0:00 /usr/lib/systemd/systemd --user 1035 ? S 0:00 (sd-pam) 1041 ? R 0:00 sshd: microlinux@pts/0 1042 pts/0 Ss 0:00 -bash 1071 pts/0 R+ 0:00 ps x
La sortie de ps aux
est assez longue. Même sur une installation minimale, le système lance 125 processus, dont cinq appartiennent à l’utilisateur connecté.
Compter les processus
Vous vous demandez peut-être comment j’ai fait pour compter tous ces processus. C’est l’occasion de vous rappeler la philosophie Unix : combiner des outils qui ne font qu’une seule chose. Pour avoir la liste complète de tous les processus en cours sur la machine, je dois utiliser la commande suivante :
$ ps ax
Le nombre de processus correspond à peu de choses près au nombre de lignes renvoyées par la commande précédente. La ligne d’en-têtes des colonnes ne correspond pas à un processus. Supprimons-la de l’affichage en utilisant l’option -v
(ou --invert-match
) de grep
:
$ ps ax | grep -v COMMAND
À partir de là, je peux donc reprendre ma commande et la combiner avec wc
pour obtenir le nombre de lignes, c’est-à-dire le nombre de processus en cours :
$ ps ax | grep -v COMMAND | wc -l 125
Nous obtenons un total de 125 processus. De la même manière, si je veux savoir combien de ces processus m’appartiennent, il suffit que j’invoque seulement l’option x
:
$ ps x | grep -v COMMAND | wc -l 6
Si le résultat vous surprend, n’oubliez pas que wc
est un processus comme les autres.
Envoyer un signal à un processus : kill
Maintenant, tentez l’expérience suivante :
- Ouvrez une deuxième console avec Alt+F2 ou en initiant une autre connexion distante avec SSH dans une deuxième fenêtre.
- Dans la deuxième console, lancez la commande
top
, qui vous affiche « à chaud » l’état des processus en cours. Nous la verrons en détail un peu plus loin. Notez que l’affichage detop
est actualisé toutes les deux secondes. - Revenez dans la première console avec Alt+F1 et affichez vos processus en cours avec
ps x
. Notez le PID de la commandetop
. Sur ma machine, c’est1362
. Sur la vôtre, ce sera probablement un autre identifiant. - Invoquez la commande
kill
suivie du PID que vous venez de noter :kill 1362
dans mon cas.
Notez les conséquences de cette commande dans la deuxième console. L’affichage de top
s’est arrêté et nous retrouvons l’invite de commande.
Est-ce que nous aurions « tué » la commande top
, comme le suggère le nom de la commande ? kill
est en effet susceptible de se révéler un véritable assassin et de terminer des processus avec l’équivalent numérique d’un coup de massue sur la tête. Néanmoins, il a procédé autrement ici.
C’est un peu comme dans la vraie vie, où vous avez les gentils tueurs et les méchants tueurs. Les gentils tueurs vous laissent le temps de mettre de l’ordre dans vos affaires, de rédiger votre testament, de vous raser, d’arranger votre nœud de cravate, etc. Les méchants tueurs ne posent pas de questions et vous balancent directement dans le ravin, rasé ou pas.
kill
invoqué sans arguments est un gentil tueur, c’est-à-dire qu’il laisse au processus le temps de s’arrêter proprement, de ranger à leur place toutes les données en cours d’utilisation. En revanche, si on le lui précise explicitement, kill
montre les crocs et devient impitoyable, ce qui est parfois nécessaire face à un processus qui a décidé de faire des siennes et de bloquer la machine.
Chose plus importante encore, kill
n’est pas qu’un tueur, comme son nom le laisserait croire. Il sait faire bien plus que cela. Pour en avoir la certitude, l’option -l
vous affichera la liste complète de ses compétences :
$ kill -l
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
...
Non, nous n’allons pas examiner les soixante-quatre options en détail. Nous avons juste compris que kill
permettait d’envoyer toute une série de signaux à des processus et nous allons en tester quelques-uns.
Arrêter et relancer un processus
Fermez la deuxième console – ou la deuxième session SSH – et affichez l’ensemble de vos processus en cours, en notant leur PID :
$ ps x PID TTY STAT TIME COMMAND 1032 ? Ss 0:00 /usr/lib/systemd/systemd --user 1035 ? S 0:00 (sd-pam) 1041 ? S 0:00 sshd: microlinux@pts/0 1042 pts/0 Ss 0:00 -bash 1372 pts/0 R+ 0:00 ps x
Maintenant, ouvrez une deuxième console – ou initiez une deuxième session distante avec SSH – et réitérez la commande depuis la première console :
$ ps x PID TTY STAT TIME COMMAND 1032 ? Ss 0:00 /usr/lib/systemd/systemd --user 1035 ? S 0:00 (sd-pam) 1041 ? R 0:00 sshd: microlinux@pts/0 1042 pts/0 Ss 0:00 -bash 1378 ? S 0:00 sshd: microlinux@pts/1 1379 pts/1 Ss+ 0:00 -bash 1408 pts/0 R+ 0:00 ps x
Notez le PID du shell Bash de la deuxième console (1379 sur ma machine) et envoyez le signal suivant au processus en cours :
$ kill -STOP 1379
Maintenant, basculez vers la deuxième console. Vous ne voyez rien ? Essayez donc de saisir n’importe quelle commande. Le curseur est là, mais la console ne réagit plus. C’est normal : vous venez de l’arrêter en lui envoyant un SIGSTOP
. Pour la relancer, rien n’est plus simple. Envoyez un SIGCONT
au processus interrompu :
$ kill -CONT 1379
À présent, vous pouvez continuer à utiliser votre shell normalement. Réinvoquez kill -l
et repérez SIGSTOP
et SIGCONT
dans la liste des signaux. Vous voyez qu’ils sont affublés respectivement des identifiants de signal 19
et 18
. Nous aurions également pu invoquer les deux dernières commandes comme ceci :
$ kill -19 1379 $ kill -18 1379
Terminer et tuer un processus
Dans la panoplie des signaux de kill
, deux nous intéressent particulièrement : SIGTERM
et SIGKILL
. Le premier est une manière « sympathique » de terminer un processus. Lorsque vous lancez la commande top
et que vous l’interrompez avec la touche Q (comme quit), c’est un SIGTERM
que vous envoyez. Nous aurions pu nous y prendre comme ceci pour arrêter top
proprement depuis une deuxième console :
$ kill -TERM 1362
Un coup d’œil sur la page de manuel de kill
nous apprend que c’est TERM
qui est utilisé si aucun signal n’est spécifié. Utilisez cette méthode si vous souhaitez terminer un programme dans les règles de l’art.
Il arrive parfois que cela ne soit pas possible. Personne n’est parfait et les programmeurs n’échappent pas à cette règle. Même dans le monde GNU/Linux, il arrive qu’un programme fasse des siennes et plante. Si nous n’avons pas d’application mal codée sous la main, nous pouvons du moins simuler l’arrêt d’un processus récalcitrant :
- Affichez les processus de votre console avec
ps x
. - Ouvrez une deuxième console locale ou distante.
- Lancez la commande
top
. - Identifiez le processus
bash
de la deuxième console. - Envoyez un
kill -TERM
à ce processus. - Invoquez à nouveau
ps x
depuis la première console. - Que constatez-vous ?
Sous Linux, une application – ou un processus – qui refuse d’obtempérer ne vous obligera pas à redémarrer la machine à coups de pied. Avant d’en venir à ces extrémités, il suffit de lui envoyer un petit SIGKILL
et le tour est joué. Concrètement, si nous reprenons notre exemple :
$ kill -KILL 1534
Ou alors :
$ kill -9 1534
Cette fois-ci, le processus bash
a bien été arrêté (et même « tué » à proprement parler), ce qui a entraîné la fermeture de la session.
S’adresser à un processus par son nom : killall
L’utilisation de la commande kill
nécessite dans tous les cas de connaître le PID du processus auquel vous vous adressez. Si cette démarche vous paraît fastidieuse, la commande killall
constitue une alternative plus confortable. killall
appelle un chat un chat, si l’on peut dire, et permet de gérer les processus en utilisant le nom du programme plutôt que son PID.
Pour tester killall
, reprenez l’exemple cité plus haut. Ouvrez une console, affichez l’ensemble des processus avec ps x
, ouvrez une deuxième console (locale ou distante), lancez la commande top
, revenez dans la première console et invoquez la commande suivante pour terminer top
dans les règles de l’art :
$ killall top
Maintenant, relancez top
dans la deuxième console et « tuez » l’application depuis la première console :
$ killall -KILL top
Les signaux à fournir en argument sont les mêmes que pour kill
et vous pouvez aussi utiliser la syntaxe numérique :
$ killall -9 top
Utiliser kill ou killall ?
La principale différence entre kill
et killall
réside dans le fait que killall
s’adresse à tous les processus qui portent le nom fourni en argument. Un exemple illustrera ceci. Lancez trois ou quatre consoles locales ou distantes. Chacune de ces consoles initie un shell Bash :
$ ps x | grep -v grep | grep bash 1042 pts/0 Ss 0:00 -bash 1619 pts/1 Ss+ 0:00 -bash 1654 pts/2 Ss+ 0:00 -bash 1688 pts/3 Ss+ 0:00 -bash
Maintenant, essayez ceci :
$ killall -9 bash
Toutes les sessions ont été fermées abruptement. Avec un peu de chance, il vous en reste une, en fonction de l’ordre dans lequel le massacre a eu lieu. Nous pouvons en conclure que killall
s’adresse à toutes les instances d’un processus qui portent le même nom. Au cas où l’on souhaite s’adresser à un processus individuellement, il faudra recourir à kill
.
Les processus dans tous leurs états
Vous avez peut-être remarqué la présence d’une colonne STAT
supplémentaire dans l’affichage de ps
avec certains arguments. Il s’agit de l’état (status) du processus en question. Voici quelques états que l’on peut rencontrer :
S
(sleeping) désigne un processus endormi.R
(running) signifie que le processus est en cours d’exécution.Z
(zombie) concerne les processus terminés dont le processus parent n’a pas pu lire le code retour.SW
(swap) veut dire que le processus est non seulement endormi, mais qu’il a été délocalisé dans la mémoire d’échange. Rappelez-vous, il s’agit d’une portion du disque dur spécialement réservée pour les cas de figure où la mémoire vive ne suffit pas pour faire tourner correctement tous les processus actifs.
Un lien de parenté : pstree
Nous venons d’évoquer le terme de « processus parent ». Sachez que les processus d’un système Linux s’organisent de façon hiérarchique. Le premier programme lancé au démarrage de votre machine est init
(systemd
). Arrêtons-nous un instant et voyons ce qui se passe lorsque vous allumez votre serveur (ne vous inquiétez pas si vous ne comprenez pas tout, nous aurons l’occasion de revenir dessus) :
- Le matériel de la machine est initialisé par le BIOS/UEFI.
- Le secteur de démarrage (MBR ou Master Boot Record) est chargé. Il exécute le chargeur de démarrage (bootloader, en l’occurrence GRUB).
- Le chargeur de démarrage lance le noyau (kernel).
- Le noyau initialise les périphériques.
- Il charge les modules (ou pilotes ou drivers) correspondants.
- Il monte le système de fichiers racine.
- Il exécute
init
(systemd
), le programme responsable du démarrage de tous les processus utilisateurs, avec le PID 1. Sur notre système, il se présente sous la forme d’un lien symbolique/sbin/init
qui pointe vers/lib/systemd/systemd
. - À son tour,
init
(systemd
) exécute un ensemble de scripts. - Le serveur est en état de marche.
La commande pstree
affiche l’organisation hiérarchique de tous les processus en cours sur votre système :
Notez que, en haut à gauche, vous retrouvez init
(systemd
), le père de tous les processus.
Une autre façon de prendre en compte la hiérarchie des processus consiste à utiliser ps
avec les arguments nécessaires :
Ici, c’est l’option l
qui se charge d’expliciter les liens de famille entre les différents processus. Juste à côté de la colonne PID
, la colonne PPID
(Parent Process Identifier) affiche les identifiants respectifs des processus parents.
Massacre familial
Vous pouvez tenter une petite expérience – similaire à ce que nous avons fait un peu plus haut – pour mieux cerner la notion de filiation entre processus.
- Ouvrez une console et affichez l’ensemble des processus avec
ps x
. - Ouvrez une deuxième console locale ou distante et lancez la commande
top
. - Revenez dans la première console et affichez la hiérarchie des processus avec
ps axfl
.
Voici ce que j’obtiens sur ma machine :
$ ps axfl ... 0:00 \_ sshd: microlinux [priv] ... 0:00 | \_ sshd: microlinux@pts/0 ... 0:00 | \_ -bash ... 0:00 | \_ ps axfl ... 0:00 \_ sshd: microlinux [priv] ... 0:00 \_ sshd: microlinux@pts/1 ... 0:00 \_ -bash ... 0:00 \_ top ...
Dans la hiérarchie des processus, bash
avec le PID 2026
(sur ma machine) est juste au-dessus de top. Je décide de tuer ce processus :
$ kill -9 2026
J’affiche l’ensemble de mes processus dans la première console. Comme il fallait s’y attendre, la dernière commande kill
a engendré un petit massacre familial, car en tuant le processus père (le shell bash
), nous avons également tué le fils (la commande top
).
Tirer à vue sur tout ce qui bouge ?
Pour éviter que les frappes chirurgicales ne se transforment en boucherie générale, les processus sont régis par un système de droits d’accès similaire à celui qui s’applique sur les fichiers et les répertoires. Rappelez-vous que l’option u
de ps
affiche le propriétaire de chaque processus, dans la première colonne intitulée USER
.
Notre installation minimale comporte un serveur SSH qui tourne en tant que service sshd
:
$ ps ax | grep -v grep | grep sshd
804 ? Ss 0:00 /usr/sbin/sshd ...
1826 ? Ss 0:00 sshd: microlinux [priv]
1830 ? S 0:00 sshd: microlinux@pts/0
Les deux premiers processus appartiennent à root
, le dernier à l’utilisateur microlinux :
$ ps aux | grep -v grep | grep sshd root 804 ... Ss 10:27 0:00 /usr/sbin/sshd ... root 1826 ... Ss 18:01 0:00 sshd: microlinux [priv] microli+ 1830 ... S 18:01 0:00 sshd: microlinux@pts/0
Essayons d’arrêter le serveur SSH en tant que simple utilisateur :
$ kill 804 -bash: kill: (804) - Operation not permitted
Insistons un peu pour voir :
$ kill -9 804 -bash: kill: (804) - Operation not permitted
Un utilisateur du commun des mortels ne peut donc pas afficher tous les processus en cours sur la machine pour ensuite tirer à vue sur tout ce qui bouge. En revanche, là comme ailleurs, root
peut tout se permettre. Il a donc la possibilité de mettre fin à tous les processus de n’importe quel utilisateur du système :
- les processus des utilisateurs physiques (
microlinux
,lyacoub
,jmortreux
, etc.) - les processus des utilisateurs système (
sshd
,apache
, etc.) - ses propres processus, c’est-à-dire ceux qui appartiennent à
root
Surveiller l’utilisation des processus de la machine : top
L’administrateur système est particulièrement concerné par le contrôle des processus dans deux cas de figure :
- lorsque le système est installé sur une machine peu performante en termes de processeur et de mémoire vive
- lorsqu’un processus décide de faire des siennes en monopolisant les ressources disponibles, ce qui résulte en un serveur « dur d’oreille » voire carrément bloqué
Le serveur de production sur lequel j’héberge les données de mon entreprise est une machine dotée d’un processeur douze cœurs et d’une quantité respectable de mémoire vive. Je peux donc faire tourner simultanément un serveur de noms, un serveur de courrier électronique, un serveur web, un serveur de messagerie instantanée, un serveur de stockage réseau, une webradio et d’autres choses encore sans ressentir le moindre ralentissement prohibitif au niveau des services hébergés. Si j’essayais d’obtenir la même configuration sur le serveur bas de gamme qui me sert de bac à sable – doté d’un processeur bicœur et d’une quantité relativement modeste de mémoire vive – il y a fort à parier que le système serait très vite complètement saturé. Dans ce cas, il faudrait utiliser les ressources de la machine avec plus de parcimonie.
Il existe un moyen fort pratique de mesurer exactement la consommation en ressources de chaque processus : c’est l’outil top
, que nous avons déjà eu l’occasion de voir. Pour le lancer, invoquez simplement son nom :
$ top
- Appuyez sur Maj+F pour afficher la fenêtre de gestion des champs (Fields Management).
- Utilisez les touches FlècheHaut et FlècheBas pour naviguer dans la fenêtre.
- Mettez le champ
%MEM=Memory Usage
en surbrillance. - Appuyez sur S (sort) pour définir la mémoire vive comme nouveau critère de tri.
- Quittez la fenêtre de sélection des champs en appuyant sur Q.
À présent, top
vous affiche l’ensemble des processus actifs classés par ordre décroissant de consommation de mémoire. Les processus les plus gourmands figurent en tête.
Pour revenir au mode d’affichage initial, procédez de manière similaire :
- Appuyez sur Maj+F pour afficher la fenêtre de gestion des champs (Fields Management).
- Mettez le champ
%CPU=CPU Usage
en surbrillance. - Appuyez sur S pour définir la consommation processeur comme nouveau critère de tri.
- Quittez la sélection des champs en appuyant sur Q.
Dans sa configuration par défaut, top
calcule la consommation moyenne des processeurs. La touche 1 permet de basculer vers l’affichage individuel de chaque processeur. Appuyez une seconde fois sur 1 pour revenir au mode d’affichage par défaut.
Si votre serveur est peu performant, top
vous aidera à identifier les applications un peu trop gourmandes en ressources et à les configurer avec circonspection.
Lire la suite : Gérer les services
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.
0 commentaire