Pourquoi (ou comment) le nombre de descripteurs de fichiers ouverts utilisés par root dépasse-t-il ulimit -n?

13

Notre serveur a récemment manqué de descripteurs de fichiers, et à ce sujet, j'ai quelques questions. ulimit -nest censé me donner le nombre maximum de descripteurs de fichiers ouverts. Ce nombre est 1024. J'ai vérifié le nombre de descripteurs de fichiers ouverts en exécutant lsof -u root |wc -let j'ai obtenu 2500 fds. C'est beaucoup plus que 1024, donc je suppose que cela signifierait que le nombre 1024 est par processus, pas par utilisateur, comme je le pensais. Eh bien, j'ai couru lsof -p$PidOfGlassfish|wc -let obtenu 1300. C'est la partie que je ne reçois pas. Si ce ulimit -nn'est pas le nombre maximum de processus par utilisateur ou par processus, à quoi sert-il? Ne s'applique-t-il pas à l'utilisateur root? Et si oui, comment pourrais-je alors obtenir les messages d'erreur sur le manque de descripteur de fichier?

EDIT: La seule façon dont je peux avoir un sens ulimit -nest d'appliquer le nombre de fichiers ouverts (comme indiqué dans le manuel bash) plutôt que le nombre de descripteurs de fichiers (différents processus peuvent ouvrir le même fichier). Si tel est le cas, alors simplement lister le nombre de fichiers ouverts (grepping sur '/', excluant ainsi les fichiers mappés en mémoire) ne suffit pas :

lsof -u root |grep /|sort  -k9  |wc -l #prints '1738'

Pour voir réellement le nombre de fichiers ouverts, je devrais filtrer sur la colonne de nom pour imprimer uniquement les entrées uniques. Ainsi, ce qui suit est probablement plus correct:

lsof -u root |grep /|sort  -k9 -u |wc -l #prints '604'

La commande ci-dessus attend une sortie au format suivant à partir de lsof:

java      32008 root  mem       REG                8,2 11942368      72721 /usr/lib64/locale/locale-archive
vmtoolsd   4764 root  mem       REG                8,2    18624     106432 /usr/lib64/open-vm-tools/plugins/vmsvc/libguestInfo.so

Cela me donne au moins un nombre inférieur à 1024 (le nombre rapporté par ulimit -n), donc cela semble être un pas dans la bonne direction. "Malheureusement", je n'ai aucun problème avec le manque de descripteurs de fichiers, j'ai donc du mal à le valider.

oligofren
la source
2
lsof signale les mappages de mémoire ainsi que les fichiers ouverts, de sorte que votre pipeline «wc» génère une surestimation du nombre de descripteurs de fichiers utilisés par ce processus.
Richard Kettlewell
aha! maintenant c'est une bonne info. Mais je ne suis pas sûr de bien comprendre. Par "mappages de mémoire", vous voulez dire un fichier mappé en mémoire? Cela nécessiterait un descripteur de fichier à ma connaissance, ou comment le système d'exploitation pourrait-il mettre à jour le fichier autrement?
oligofren
Et suivi deux: Quelle serait une bonne façon de trouver tous les descripteurs de fichiers ouverts - ceux qui sont réellement affectés par les limites imposées par "ulimit -n"?
oligofren
1
Les mappages de mémoire ne nécessitent pas de fichier ouvert. Si vous souhaitez répertorier uniquement les fichiers ouverts, le filtrage de la sortie de lsof est probablement l'approche la plus simple.
Richard Kettlewell
Merci, édité ma réponse. Utiliser ´lsof -u root | grep / | sort -k9 -u´ semble donner ce qui équivaut à une réponse raisonnable. C'est au moins un nombre inférieur à ulimit -n.
oligofren

Réponses:

9

J'ai testé cela dans la version Linux 2.6.18-164.el5 - Red Hat 4.1.2-46. J'ai pu voir que l'ulimit est appliqué par processus.

Le paramètre est défini au niveau de l'utilisateur, mais appliqué à chaque processus.

Par exemple: 1024 était la limite. Plusieurs processus ont été démarrés et les fichiers ouverts par chacun ont été comptés à l'aide de

ls -l /proc/--$pid--/fd/ | wc -l

Il n'y a eu aucune erreur lorsque la somme des fichiers ouverts par plusieurs processus a dépassé 1024. J'ai également vérifié le nombre de fichiers uniques combinant les résultats pour différents processus et comptant les fichiers uniques. Les erreurs ont commencé à apparaître uniquement lorsque le nombre de chaque processus a dépassé 1024. (java.net.SocketException: trop de fichiers ouverts dans les journaux de processus)

Choisi
la source
Merci d'avoir testé cela. Avez-vous une idée pourquoi lsof -p$PidOfGlassfish|wc -lm'a donné 1300? Je suppose que les deux approches du comptage diffèrent en quelque sorte. Sinon, alors peut-être que la limite ne s'applique pas à l'utilisateur root?
oligofren
Juste curieux, pourquoi utiliser ls -lau lieu de ls? Ce dernier a une ligne supplémentaire (par exemple total 5) lorsqu'il y a 5 fichiers. Dans un tel cas, l'utilisation ls -l dans l'exemple ci-dessus rapporterait 6 et non 5. J'utilise ls /proc/<pid>/fd | wc -l.
Starfry
@starfry C'est juste de la négligence de ma part. Je fais généralement cela par étapes et ls -lme donne une entrée par ligne, que je redirige ensuite vers autre chose. Bien sûr, cela se produit également lorsque la tuyauterie est normale ls(mais non autrement).
oligofren
3

L'ulimit est pour les descripteurs de fichiers. Il s'applique aux fichiers, répertoires, sockets, epolls de tuyaux, eventfds, timerfds etc. etc.

À tout moment pendant le démarrage des processus, les limites peuvent avoir été modifiées. Visitez /proc/<pid>/limitset voyez si les valeurs ont été modifiées.

Matthew Ife
la source
3

@oligofren

J'ai également effectué des tests afin de déterminer comment "ulimits -Sn"pour "open files"a été appliquée.

  • Comme l'affiche Chosen mentionnée dans le lien , l'ulimit pour "open files"est en effet appliqué par processus. Pour voir quelles sont les limites actuelles du processus:

    cat /proc/__process_id__/limits

  • Pour déterminer le nombre de fichiers ouverts par un processus, vous devez utiliser la commande suivante:

    lsof -P -M -l -n -d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt' -p __process_id__ -a | awk '{if (NR>1) print}' | wc -l

Explication de ce qui précède et de ma méthode / résultats de test

Les "-P -M -l -n"arguments de lsof sont simplement là pour faire fonctionner lsof le plus rapidement possible. N'hésitez pas à les retirer.

-P - inhibits the conversion of port numbers to port names for network files
-M - disable reporting of portmapper registrations for local TCP, UDP and UDPLITE ports
-l - inhibits the conversion of user ID numbers to login names
-n - inhibits the conversion of network numbers to host names for network files

L' "-d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt'"argument indique lsofd'exclure les descripteurs de fichiers de type: cwd / err / ltx / mem / mmap / pd / rtd / txt.

Depuis la page de manuel lsof:

   FD         is the File Descriptor number of the file or:

                   cwd  current working directory;
                   Lnn  library references (AIX);
                   err  FD information error (see NAME column);
                   jld  jail directory (FreeBSD);
                   ltx  shared library text (code and data);
                   Mxx  hex memory-mapped type number xx.
                   m86  DOS Merge mapped file;
                   mem  memory-mapped file;
                   mmap memory-mapped device;
                   pd   parent directory;
                   rtd  root directory;
                   tr   kernel trace file (OpenBSD);
                   txt  program text (code and data);
                   v86  VP/ix mapped file;

J'ai considéré "Lnn,jld,m86,tr,v86"comme non applicable à Linux et je n'ai donc pas pris la peine de les ajouter à la liste d'exclusion. Je n'en suis pas sûr "Mxx".

Si votre application utilise des fichiers / périphériques mappés en mémoire, vous souhaiterez peut-être les supprimer "^mem"et "^mmap"les exclure de la liste.

MODIFIER --- commencer le snip ---

Edit: j'ai trouvé le lien suivant qui indique que:

Les fichiers .so mappés en mémoire ne sont pas techniquement les mêmes que les descripteurs de fichiers sur lesquels l'application a le contrôle. / proc // fd est le point de mesure des descripteurs de fichiers ouverts

Donc, si votre processus utilise des fichiers mappés en mémoire, vous devrez filtrer les fichiers * .so.

De plus, la JVM de Sun va mapper en mémoire les fichiers jar

Un fichier JAR mappé en mémoire, dans ce cas le fichier qui contient les "classes JDK". Lorsque vous mappez en mémoire un fichier JAR, vous pouvez accéder aux fichiers qu'il contient de manière très efficace (au lieu de le lire chaque fois depuis le début). La JVM Sun mappe en mémoire tous les fichiers JAR du chemin de classe; si votre code d'application doit accéder à un fichier JAR, vous pouvez également le mapper en mémoire.

Ainsi, des choses comme tomcat / glassfish afficheront également des fichiers jar mappés en mémoire. Je n'ai pas testé si ceux-ci comptent pour la "ulimit -Sn"limite.

EDIT --- fin de capture ---

Empiriquement, j'ai trouvé que "cwd,rtd,txt"sont pas pris en compte en ce qui concerne la limite par fichier de processus (ulimit -Sn).

Je ne sais pas s'ils "err,ltx,pd"sont pris en compte dans la limite de fichiers car je ne sais pas comment créer des descripteurs de fichiers de ces types de descripteurs.

L' "-p __process_id__"argument se limite lsofà renvoyer uniquement des informations pour le __process_id__spécifié. Supprimez-le si vous souhaitez obtenir un compte pour tous les processus.

L' "-a"argument est utilisé pour ET les sélections (c'est-à-dire les arguments "-p" et "-d").

L' "awk '{if (NR>1) print}'"instruction est utilisée pour ignorer l'en-tête qui lsofs'imprime dans sa sortie.

J'ai testé en utilisant le script perl suivant:

File: test.pl
---snip---
#!/usr/bin/perl -w
foreach $i (1..1100) {
  $FH="FH${i}";
  open ($FH,'>',"/tmp/Test${i}.log") || die "$!";
  print $FH "$i\n";
}
---snip---

J'ai dû exécuter le script dans le débogueur perl pour m'assurer que le script ne se termine pas et libérer les descripteurs de fichiers.

Éxécuter: perl -d test.pl

Dans le débogueur de Perl, vous pouvez exécuter le programme en entrant cet en appuyant sur Entrée et si votre ulimit -Snvaleur était 1024 , vous constaterez que le programme s'arrête après la création du Test1017.logfichier dans /tmp.

Si vous identifiez maintenant le pid du processus perl et utilisez la lsofcommande ci-dessus, vous verrez qu'il génère également 1024 .

Supprimez le "wc -l"et remplacez-le par un "less"pour voir la liste des fichiers comptés pour la limite de 1024 . Supprimez également l' "-d ^....."argument pour voir que les descripteurs cwd,txtet ne comptent pas dans la limite.rtd

Si vous exécutez maintenant "ls -l /proc/__process_id__/fd/ | wc -l", vous verrez une valeur de 1025 retournée. En effet, lsun en- "total 0"tête a été ajouté à sa sortie qui a été compté.

Remarque:

Pour vérifier si le système d'exploitation manque de descripteurs de fichiers, il est préférable de comparer la valeur de:

cat /proc/sys/fs/file-nr | awk '{print $1}'

avec

cat /proc/sys/fs/file-max

https://www.kernel.org/doc/Documentation/sysctl/fs.txt documente ce file-nrque file-maxsignifie et signifie.

Jinesh Choksi
la source
0

Il semble que votre raisonnement soit quelque chose comme "Je dois abaisser cette limite pour ne pas manquer de précieux descripteurs". La vérité est exactement l'inverse - si votre serveur n'a plus de descripteurs de fichiers, vous devez augmenter cette limite de 1 024 à quelque chose de plus grand. Pour une glassfishmise en œuvre réaliste , 32 768 est raisonnable.

Personnellement, j'augmente toujours la limite à environ 8 192 à l'échelle du système - 1 024 est tout simplement ridicule. Mais vous voudrez augmenter glassfishplus haut. Vérifiez /etc/security/limits.conf. Vous pouvez ajouter une entrée spéciale pour l'utilisateur glassfishs'exécute en tant que.

David Schwartz
la source
Je ne sais pas comment vous pourriez m'interpréter comme signifiant :-) Ce que je me demandais, c'est pourquoi cela ne semblait pas s'appliquer. Je vais le mettre plus haut, mais je veux aussi comprendre comment cela fonctionne. Si la limite est de 1024, alors comment Glassfish pourrait-il avoir 1300 poignées?
oligofren
'lsof -u root | grep / | sort -k9 -u' imprime les entrées du descripteur de fichier unique. Je suppose que le nombre de lignes de ceci est le nombre réel auquel ulimit -n s'applique.
oligofren
0

Vous voulez jeter un œil aux limites à l'échelle du système définies dans / proc / sys / fs / file-max et les ajuster là (jusqu'au prochain redémarrage) ou définir fs.file-max dans sysctl.conf pour le rendre permanent. Cela pourrait être utile - http://www.randombugs.com/linux/tuning-file-descriptors-limits-on-linux.html

rnxrx
la source
1
Ce commentaire sur bash n'est pas exact. ulimit impose un ensemble de limites par identifiant utilisateur, pour les processus lancés via le shell, qui est pratiquement tout grâce à la façon dont l'arborescence des processus est générée sur les systèmes d'exploitation Unix. Ce n'est pas bash.
EightBitTony
Désolé - modifiera, mais les commentaires sur les limites du système sont toujours valables.
rnxrx
Il est très peu probable qu'il atteigne les limites du système. Possible, mais très peu probable.
David Schwartz
EightBitTony: ulimit ne définit pas ulimit par ensemble de limites de l'ID utilisateur. Son par processus lorsque les pam_limits sont appliqués. Le ulimit qui est "par utilisateur" est le "ulimit -u" "Le nombre maximum de processus disponibles pour un seul utilisateur"
Aucun nom d'utilisateur
0

Erreur courante pour comparer le résultat de l'appel lsof brut avec la limite supposée.

Pour la limite globale (/ proc / sys / fs / file-max), vous devriez jeter un œil à / proc / sys / fs / file-nr -> la première valeur indique ce qui est utilisé et la dernière valeur est la limite

La limite OpenFile est pour chaque processus mais peut être définie sur un utilisateur, voir la commande "ulimit -Hn" pour les limites utilisateur et voir /etc/security/limits.conf pour les définitions. Généralement appliqué avec "utilisateur d'application", par exemple: "tomcat": définissez la limite à 65000 pour l'utilisateur tomcat qui s'appliquera lors du processus java qu'il exécute.

Si vous voulez vérifier la limite appliquée sur un processus, obtenez son PID puis: cat / proc / $ {PID} / limits Si vous voulez vérifier combien de fichiers sont ouverts par un processus, obtenez son PID puis: ls -1 / proc / {PID} / fd | wc -l (note pour ls c'est 'moins un', ne pas confondre avec 'moins el')

Si vous voulez connaître les détails avec lsof mais uniquement pour les gestionnaires de fichiers qui comptent pour la limite, essayez avec ceux-ci: lsof -p $ {PID} | grep -P "^ (\ w + \ s +) {3} \ d + \ D +" lsof -p $ {PID} -d '^ cwd, ^ err, ^ ltx, ^ mem, ^ mmap, ^ pd, ^ rtd, ^ txt '-a

Remarque: les 'fichiers' sont des fichiers / connexions pipe / tcp / etc.

Notez que parfois vous devrez probablement être root ou utiliser sudo pour obtenir le résultat correct pour les commandes, sans privilège parfois vous n'avez pas d'erreur, juste moins de résultats.

et enfin si vous voulez savoir à quels «fichiers» de votre système de fichiers un processus accède, consultez: lsof -p {PID} | grep / | awk '{print $ 9}' | trier | uniq

s'amuser !

Ronan Kerdudou
la source