Perché (o come) il numero di descrittori di file aperti in uso da root supera ulimit -n?


13

Di recente il nostro server ha esaurito i descrittori di file e per questo ho alcune domande. ulimit -ndovrebbe darmi il numero massimo di descrittori di file aperti. Quel numero è 1024. Ho controllato il numero di descrittori di file aperti eseguendo lsof -u root |wc -le ho ottenuto 2500 fds. Questo è molto più di 1024, quindi ho immaginato che significherebbe che il numero 1024 è per processo, non per utente, come pensavo. Bene, ho corso lsof -p$PidOfGlassfish|wc -le ottenuto il 1300. Questa è la parte che non capisco. Se ulimit -nnon è il numero massimo di processi per utente o per processo, a cosa serve? Non si applica all'utente root? E se è così, come potrei quindi ottenere i messaggi di errore sull'esaurimento del descrittore di file?

EDIT: L'unico modo in cui riesco a capire ulimit -nè se applica il numero di file aperti (come indicato nel manuale di bash) piuttosto che il numero di handle di file (processi diversi possono aprire lo stesso file). In questo caso, elencare semplicemente il numero di file aperti (passando su '/', escludendo quindi i file mappati in memoria) non è sufficiente:

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

Per vedere effettivamente il numero di file aperti, avrei bisogno di filtrare sulla colonna del nome solo per stampare le voci univoche. Pertanto, probabilmente è più corretto quanto segue:

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

Il comando precedente prevede l'output nel seguente formato da 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

Questo mi dà almeno un numero inferiore a 1024 (il numero riportato da ulimit -n), quindi questo sembra un passo nella giusta direzione. "Purtroppo" non sto riscontrando alcun problema con l'esaurimento dei descrittori di file, quindi avrò difficoltà a convalidarlo.


2
lsof riporta i mapping di memoria e i file aperti, quindi la pipeline "wc" produce una sovrastima del numero di descrittori di file utilizzati da quel processo.
Richard Kettlewell,

aha! ora che è una buona informazione. Ma non sono del tutto sicuro di aver capito. Per "mapping di memoria", intendi un file con mapping di memoria? Ciò richiederebbe un handle di file per la mia comprensione, o in quale altro modo il sistema operativo sarebbe in grado di aggiornare il file?
oligofren,

E follow-up due: quale sarebbe un buon modo per trovare tutti gli handle di file aperti - quelli che sono effettivamente interessati dai limiti imposti da "ulimit -n"?
oligofren,

1
I mapping di memoria non richiedono un file aperto. Se si desidera elencare solo i file aperti, filtrare l'output di lsof è probabilmente l'approccio più semplice.
Richard Kettlewell,

Grazie, ho modificato la mia risposta. Usare ´lsof -u root | grep / | sort -k9 -u´ sembra dare ciò che equivale a una risposta ragionevole. Questo è almeno un numero inferiore a ulimit -n.
Oligofren,

Risposte:


9

Ho provato questo in Linux versione 2.6.18-164.el5 - Red Hat 4.1.2-46. Ho potuto vedere che l'ulimit è applicato per processo.

Il parametro è impostato a livello utente, ma applicato per ogni processo.

Ad esempio: 1024 era il limite. Sono stati avviati più processi e i file aperti da ognuno sono stati contati utilizzando

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

Non ci sono stati errori quando la somma dei file aperti da più processi ha attraversato 1024. Ho anche verificato il conteggio dei file univoci che combina i risultati per processi diversi e il conteggio dei file univoci. Gli errori hanno iniziato a comparire solo quando il conteggio per ciascun processo ha superato 1024. (java.net.SocketException: troppi file aperti nei registri dei processi)


Grazie per averlo testato. Hai idea del perché lsof -p$PidOfGlassfish|wc -lmi abbia dato 1300? Immagino che i due approcci al conteggio differiscano in qualche modo. In caso contrario, forse il limite non si applica all'utente root?
Oligofren,

Solo curioso, perché usare ls -linvece di ls? Quest'ultimo ha una riga extra (ad es. total 5) Quando ci sono 5 file. In tal caso l'utilizzo ls -l nell'esempio sopra riporta 6 non 5. Uso ls /proc/<pid>/fd | wc -l.
Starfry,

@starfry Questa è solo la sregolosità da parte mia. Di solito lo faccio in modo graduale e ls -lmi dà una voce per riga, che poi inserisco in qualcos'altro. Di certo, ciò accade anche quando si esegue il piping normale ls(ma non diversamente).
oligofren,

3

L'ulimit è per i filehandle. Si applica a file, directory, socket, epoll di pipe, eventfds, timerfds ecc ecc.

In qualsiasi momento durante l'avvio dei processi i limiti potrebbero essere stati modificati. Visita /proc/<pid>/limitse vedi se i valori sono stati modificati.


3

@oligofren

Ho anche effettuato alcuni test per determinare come "ulimits -Sn"per "open files"è stato applicato.

  • Come il poster scelto nel link , l'ulimit per "open files"viene effettivamente applicato per processo. Per vedere quali sono i limiti attuali del processo:

    cat /proc/__process_id__/limits

  • Per determinare quanti file ha aperto un processo, è necessario utilizzare il comando seguente:

    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

Spiegazione di quanto sopra e dei miei metodi / risultati del test

Gli "-P -M -l -n"argomenti di lsof sono semplicemente lì per far funzionare lsof il più velocemente possibile. Sentiti libero di eliminarli.

-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'"argomento indica lsofdi escludere i descrittori di file di tipo: cwd / err / ltx / mem / mmap / pd / rtd / txt.

Dalla pagina man 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;

Ho ritenuto "Lnn,jld,m86,tr,v86"non applicabile a Linux e quindi non mi sono preoccupato di aggiungerli all'elenco di esclusione. Non ne sono sicuro "Mxx".

Se l'applicazione utilizza file / dispositivi associati alla memoria, è possibile che si desideri rimuovere "^mem"e "^mmap"dall'elenco di esclusione.

EDIT --- inizia a tagliare ---

Modifica: ho trovato il seguente link che indica che:

i file .so mappati in memoria tecnicamente non sono gli stessi di un file handle su cui l'applicazione ha il controllo. / proc // fd è il punto di misurazione per i descrittori di file aperti

Quindi, se il tuo processo utilizza file mappati in memoria, dovrai filtrare i file * .so.

Inoltre, JVM di Sun memorizzerà i file jar della mappa

Un file JAR mappato in memoria, in questo caso il file che contiene le "classi JDK". Quando si mappa in memoria un JAR, è possibile accedere ai file al suo interno in modo molto efficiente (anziché leggerlo dall'inizio ogni volta). Sun JVM mapperà in memoria tutti i JAR sul percorso di classe; se il codice dell'applicazione deve accedere a un JAR, è anche possibile mapparlo in memoria.

Quindi cose come tomcat / glassfish mostreranno anche file jar mappati in memoria. Non ho testato se questi contano ai fini del "ulimit -Sn"limite.

EDIT --- fine snip ---

Empiricamente, ho scoperto che non"cwd,rtd,txt" vengono conteggiati rispetto al limite del file per processo (ulimit -Sn).

Non sono sicuro che "err,ltx,pd"vengano conteggiati ai fini del limite del file in quanto non so come creare handle di file di questi tipi di descrittori.

L' "-p __process_id__"argomento si limita lsofa restituire informazioni solo per l'oggetto __process_id__specificato. Rimuovere questo se si desidera ottenere un conteggio per tutti i processi.

L' "-a"argomento viene utilizzato per AND le selezioni (ovvero gli argomenti "-p" e "-d").

L' "awk '{if (NR>1) print}'"istruzione viene utilizzata per saltare l'intestazione che viene lsofstampata nel suo output.

Ho provato usando il seguente script perl:

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

Ho dovuto eseguire lo script nel debugger perl per assicurarmi che lo script non terminasse e rilasciasse i descrittori di file.

Eseguire: perl -d test.pl

Nel debugger di perl, puoi eseguire il programma inserendo ce premendo invio e se hai ulimit -Snun valore di 1024 , scoprirai che il programma si arresta dopo aver creato il Test1017.logfile /tmp.

Se ora identifichi il pid del processo perl e usi il lsofcomando sopra , vedrai che genera anche 1024 .

Rimuovere "wc -l"e sostituire con a "less"per visualizzare l'elenco dei file conteggiati verso il limite 1024 . Rimuovere anche l' "-d ^....."argomento per vedere che i descrittori cwd,txte non contano ai fini del limite.rtd

Se ora esegui "ls -l /proc/__process_id__/fd/ | wc -l", verrà visualizzato un valore di 1025 restituito. Questo perché è stata lsaggiunta "total 0"un'intestazione al suo output che è stata contata.

Nota:

Per verificare se il sistema operativo sta esaurendo i descrittori di file, è meglio confrontare il valore di:

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

con

cat /proc/sys/fs/file-max

https://www.kernel.org/doc/Documentation/sysctl/fs.txt documenta cosa file-nre cosa file-maxsignifichi.


0

Sembra che il tuo ragionamento sia qualcosa del tipo: "Devo abbassare quel limite in modo da non rimanere senza descrittori preziosi". La verità è esattamente il contrario: se il server ha esaurito i descrittori di file, è necessario aumentare tale limite da 1.024 a qualcosa di più grande. Per glassfishun'implementazione realistica , 32.768 è ragionevole.

Personalmente, alzo sempre il limite a circa 8.192 a livello di sistema - 1.024 è semplicemente ridicolo. Ma ti consigliamo di aumentare glassfishpiù in alto. Controllare /etc/security/limits.conf. È possibile aggiungere una voce speciale per l'utente glassfishesegue come.


Non sono sicuro di come potresti interpretarmi nel senso che :-) Quello che mi chiedevo è perché non sembrava applicarsi. Lo imposterò più in alto, ma voglio capire anche come funziona. Se il limite è 1024, come potrebbe Glassfish avere 1300 handle?
oligofren,

'lsof -u root | grep / | sort -k9 -u' stampa le voci uniche del descrittore di file. Immagino che il numero di righe da questo sia il numero effettivo a cui si applica ulimit -n.
oligofren,

0

Volete dare un'occhiata ai limiti a livello di sistema impostati in / proc / sys / fs / file-max e modificarlo lì (fino al prossimo riavvio) o impostare fs.file-max in sysctl.conf per renderlo permanente. Questo potrebbe essere utile - http://www.randombugs.com/linux/tuning-file-descriptors-limits-on-linux.html


1
Quel commento su bash non è accurato. ulimit impone un set di limiti per ID utente, per i processi avviati tramite la shell, che è praticamente praticamente tutto grazie a come l'albero dei processi viene generato su Unix come i sistemi operativi. Non è bash.
EightBitTony,

Siamo spiacenti, verranno modificati, ma i commenti sui limiti di sistema rimangono validi.
rnxrx,

È molto improbabile che stia colpendo i limiti del sistema. Possibile, ma molto improbabile.
David Schwartz,

EightBitTony: ulimit non imposta ulimit per set di limiti ID utente. È per processo quando vengono applicati i pam_limits. L'ulimit che è "per utente" è "ulimit -u" "Il numero massimo di processi disponibili per un singolo utente"
Nessun nome utente

0

Errore comune nel confrontare il risultato della chiamata lsof non elaborata con il limite presunto.

Per il limite globale (/ proc / sys / fs / file-max) dovresti dare un'occhiata a / proc / sys / fs / file-nr -> il valore del pugno indica cosa viene usato e l'ultimo valore è il limite

Il limite OpenFile è per ogni processo ma può essere definito su un utente, vedere il comando "ulimit -Hn" per i limiti utente e vedere /etc/security/limits.conf per le definizioni. Generalmente applicato con "utente app", ad es. "Tomcat": impostare il limite su 65000 per l'utente tomcat che verrà applicato al processo java in esecuzione.

Se vuoi controllare il limite applicato su un processo, ottieni il suo PID e quindi: cat / proc / $ {PID} / limits Se vuoi controllare quanti file sono aperti da un processo, ottieni il suo PID e poi: ls -1 / proc / {PID} / fd | wc -l (nota per ls è 'meno uno', non confondersi con 'meno meno')

Se vuoi conoscere i dettagli con lsof ma solo per quei gestori di file che contano per il limite, prova con quelli: lsof -p $ {PID} | grep -P "^ (\ w + \ s +) {3} \ d + \ D +" lsof -p $ {PID} -d '^ cwd, ^ err, ^ ltx, ^ mem, ^ mmap, ^ pd, ^ rtd, ^ txt '-a

Nota: i "file" sono file / pipe / connessioni tcp / ecc.

Nota che a volte dovrai probabilmente essere root o usare sudo per ottenere il risultato corretto per i comandi, senza privilegio a volte non hai errori, solo meno risultati.

e infine se vuoi sapere a quali 'file' sul tuo filesystem si accede da un processo, dai un'occhiata a: lsof -p {PID} | grep / | awk '{print $ 9}' | ordina | uniq

divertiti !

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.