MonitorObjectif 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

InfoNe 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).

ImportantLa 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é.

Processus

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

ImportantSi 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 de top 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 commande top. Sur ma machine, c’est 1362. 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.

Tuer un processusC’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 :

Processus pstree

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 :

Processus ps

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

Processus 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.

Processus top

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

Laisser un commentaire

Emplacement de l’avatar

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *