Petite anlyse d'un problème survenu sur un serveur Solaris 10. Le contexte était le suivant : dysfonctionnement applicatif, impossible de se connecter au serveur bien que la couche IP semblait active.
Généralement je me pose pas de question dans ce genre de cas : je force une prise de dump (afin d'analyser le problème) et reboote le serveur (minimiser l'impact utilisateurs).
Avant de se lancer dans l'analyse du core, essayons de comprendre ce message. Le système tente de créer de nouveaux "processus" mais n'y parvient pas par manque de ressource.
Questions :
- Quelles sont les ressources nécessaires pour la création d'un nouveau processus ?
- Quelles sont les limites possibles ?
Un petit tour dans notre librairie : Solaris Internals et plus spécifiquement le chapitre 2 "The Solaris Process Model". La lecture est un peu longue mais très enrichissante... Bref, en vulgarisant beaucoup (désolé pour les puristes), il existe deux limites possibles : une est appliquée au Process, l'autre au Thread.
Le système Solaris est capable de créer un nombre déterminé de processus et de threads. Les deux limites Process et Thread sont utilisées à cet effet. La 1er ressource nécessaire à la création d'un processus (ou d'un thread) reste la mémoire (notons cela dans le coin de notre tête).
Revenons un peu à notre crash... Qu'avons nous ?
> ::showrev
Hostname: myserver
Release: 5.10
Kernel architecture: sun4u
Application architecture: sparcv9
Kernel version: SunOS 5.10 sun4u Generic_142909-17
Platform: SUNW,SPARC-Enterprise
Vérifions le nombre de process et threads actif sur le serveur au moment du crash
> ::walk proc !wc -l
14041
> ::walk thread !wc -l
63017
Les limites ne sont pas atteintes, cependant le nombre de threads semble assez important. Une autre façon de savoir si le nombre de process a été atteinte est d'utiliser la variable suivante :
> fork_fail_pending/D
fork_fail_pending:
fork_fail_pending: 0
Le problème semble provenir d'une allocation mémoire. Deux cas possible, le serveur ne disposait plus de mémoire virtuelle ou la table mémoire d'allocation des process (ou thread) est pleine. Le 1er cas ne semble pas possible (on aurait saturé la totalité de la mémoire virtuelle, ce qui provoque du swap... lire ce petit article). Intéressons nous au 2ème cas. L'allocation mémoire dans la table kernel concerne les threads.
> ::kmastat
cache buf buf buf memory alloc alloc
name size in use total in use succeed fail
------------------------- ------ ------ ------ --------- --------- -----
kmem_magazine_1 16 10662 27940 450560 244998 0
kmem_magazine_3 32 5701 32258 1040384 498170 0
kmem_magazine_7 64 5318 23495 1515520 436661 0
kmem_magazine_15 128 4544 24822 3227648 454626 0
[...]
segkp_16384 16384 0 0 0 0 0
segkp_24576 24576 0 0 0 0 0
segkp_32768 32768 63080 63080 2067005440 14589775 1429945523
segkp_40960 40960 0 0 0 0 0
[...]
------------------------- ------ ------ ------ --------- --------- -----
Total [static] 110821376 1078194013 0
Total [hat_memload] 483278848 1120195850 0
[...]
Total [umem_np] 12320768 556204 0
Total [segkp] 2146041856 186166476 1429945523
Total [zfs_file_data_buf] 3911852032 9675276 0
[...]
Nous avons plusieurs demandes d'allocation en erreur pour le cache segkp. La taille de ce cache semble trop petite par rapport au nombre important de threads que le système gére. Pour résoudre ce problème il est nécessaire d'augmenter la taille de ce cache (un peu de lecture).
Conseil, si vous utilisez un serveur fortement mutualisé (bcp de process et threads), n'oublie pas d'allouer un peu plus de mémoire au kernel (notamment la table segkp).