Почему (или как) количество дескрипторов открытых файлов, используемых root, превышает ulimit -n?

13

Наш сервер недавно исчерпал файловые дескрипторы, и в связи с этим у меня есть несколько вопросов. ulimit -nдолжен дать мне максимальное количество дескрипторов открытых файлов. Это число 1024. Я проверил количество открытых файловых дескрипторов, запустив его, lsof -u root |wc -lи получил 2500 fds. Это намного больше, чем 1024, поэтому я догадался, что это будет означать, что число 1024 для каждого процесса, а не для пользователя, как я. Ну, я побежал lsof -p$PidOfGlassfish|wc -lи получил 1300. Это часть, которую я не понимаю. Если ulimit -nэто не максимальное количество процессов на пользователя или на процесс, то для чего это нужно? Это не относится к пользователю root? И если да, то как я могу получить сообщения об ошибке исчерпания дескриптора файла?

РЕДАКТИРОВАТЬ: Единственный способ, которым я могу разобраться, ulimit -n- это применить количество открытых файлов (как указано в руководстве по bash), а не количество дескрипторов файлов (разные процессы могут открывать один и тот же файл). Если это так, то просто перечисляя количество открытых файлов (по оглавлению «/», таким образом , исключая файлы , отображенные на память) является не достаточными полномочиями :

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

Чтобы реально увидеть количество открытых файлов, мне нужно отфильтровать по столбцу имени только печать уникальных записей. Таким образом, следующее, вероятно, более правильно:

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

Приведенная выше команда ожидает вывод в следующем формате из 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

Это, по крайней мере, дает мне число меньше 1024 (число, сообщаемое ulimit -n), так что это похоже на шаг в правильном направлении. «К сожалению» я не испытываю никаких проблем с исчерпанием файловых дескрипторов, поэтому мне будет трудно это проверить.

oligofren
источник
2
lsof сообщает об отображениях памяти, а также об открытых файлах, поэтому ваш конвейер 'wc' дает завышенную оценку числа дескрипторов файлов, используемых этим процессом.
Ричард Кеттвелл
Ага! Теперь это хорошая информация. Но я не совсем уверен, что понимаю. Под «отображением памяти» вы подразумеваете файл с отображенной памятью? На мой взгляд, для этого потребуется дескриптор файла, или как еще ОС сможет обновить файл?
oligofren
И повторение два: Какой будет хороший способ найти все дескрипторы открытых файлов - те, на которые действительно влияют ограничения, наложенные "ulimit -n"?
oligofren
1
Отображения памяти не требуют открытого файла. Если вы хотите перечислить только открытые файлы, фильтрация вывода lsof, вероятно, самый простой подход.
Ричард Кеттвелл
Спасибо, отредактировал мой ответ. Использование «lsof -u root | grep / | sort -k9 -u», по-видимому, дает разумный ответ. Это как минимум число меньше, чем ulimit -n.
oligofren

Ответы:

9

Я проверял это в Linux версии 2.6.18-164.el5 - Red Hat 4.1.2-46. Я мог видеть, что ulimit применяется на процесс.

Параметр устанавливается на уровне пользователя, но применяется для каждого процесса.

Например: 1024 был предел. Было запущено несколько процессов, и файлы, открытые каждым из них, были подсчитаны с использованием

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

Не было ошибок, когда сумма файлов, открытых несколькими процессами, пересекла 1024. Я также проверил уникальное количество файлов, объединяющее результаты для разных процессов и подсчет уникальных файлов. Ошибки начали появляться только тогда, когда счетчик для каждого процесса превысил 1024. (java.net.SocketException: слишком много открытых файлов в журналах процессов)

Избранный
источник
Спасибо за проверку этого. Ты хоть представляешь, почему lsof -p$PidOfGlassfish|wc -lдал мне 1300? Я предполагаю, что два подхода к подсчету как-то различаются. Если нет, то, возможно, ограничение не распространяется на пользователя root?
oligofren
Просто любопытно, а зачем использовать ls -lвместо ls? Последний имеет дополнительную строку (например total 5), когда есть 5 файлов. В таком случае использование ls -l в приведенном выше примере сообщит 6, а не 5. Я использую ls /proc/<pid>/fd | wc -l.
Звездный день
@starfry Это просто разгильдяйство с моей стороны. Обычно я делаю это поэтапно и ls -lвыдает мне по одной записи на строку, которую я затем перенаправляю во что-то другое. Конечно, это также происходит при нормальном трубопроводе ls(но не иначе).
oligofren
3

Ulimit для файловых дескрипторов. Это относится к файлам, каталогам, сокетам, каналам epolls, eventfds, timerfds и т. Д. И т. Д.

В любой момент при запуске процессов ограничения могли быть изменены. Посетите /proc/<pid>/limitsи посмотрите, были ли изменены значения.

Мэтью Ифе
источник
3

@oligofren

Я также провел несколько тестов , чтобы определить , как "ulimits -Sn"для "open files"было приведено в исполнение.

  • Как и в случае постера Chosen, упомянутого в ссылке , ulimit для "open files"действительно применяется для каждого процесса. Чтобы увидеть текущие ограничения процесса:

    cat /proc/__process_id__/limits

  • Чтобы определить, сколько файлов открыт у процесса, вам нужно использовать следующую команду:

    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

Объяснение вышеизложенного и мой метод / результаты тестирования

Эти "-P -M -l -n"аргументы LSOF просто там , чтобы сделать Lsof работать как можно быстрее. Не стесняйтесь вынимать их.

-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

В "-d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt'"аргумент инструктирует lsofисключить дескрипторы файлов типа: УХО / ERR / LTX / MEM / ММАП / PD / ТПС / TXT.

Из справочной страницы 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;

Я счел "Lnn,jld,m86,tr,v86"это неприменимым для Linux и поэтому не удосужился добавить их в список исключений. Я не уверен в этом "Mxx".

Если ваше приложение использует файлы , отображенные на память / устройство , то вы можете удалить "^mem"и "^mmap"из списка исключений.

РЕДАКТИРОВАТЬ --- начать отрывать ---

Изменить: я нашел следующую ссылку, которая указывает, что:

.so-файлы, отображаемые в память, технически не совпадают с дескриптором файла, который контролирует приложение. / proc // fd - точка измерения для дескрипторов открытых файлов

Так что, если ваш процесс использует файлы с отображением в памяти, вам нужно отфильтровать * .so файлы.

Кроме того, JVM от Sun будет хранить файлы JAR карты памяти.

Отображаемый в память JAR-файл, в данном случае файл, содержащий «классы JDK». Когда вы отображаете JAR в память, вы можете очень эффективно обращаться к файлам внутри него (вместо того, чтобы каждый раз читать его с самого начала). Sun JVM отобразит в памяти все JAR на пути к классам; если вашему приложению необходим код для доступа к JAR, вы также можете отобразить его в памяти.

Таким образом, такие вещи, как tomcat / glassfish также будут отображать файлы jar с отображенной памятью. Я не проверял, относятся ли они к "ulimit -Sn"пределу.

РЕДАКТИРОВАТЬ --- конец обрезки ---

Опытным путем я обнаружил, что "cwd,rtd,txt"они не учитываются в отношении лимита на файл процесса (ulimit -Sn).

Я не уверен, "err,ltx,pd"учитывается ли ограничение на количество файлов, поскольку я не знаю, как создавать файловые дескрипторы этих типов дескрипторов.

В "-p __process_id__"аргументе ограничивает lsofтолько возвращать информацию для __process_id__указания. Удалите это, если вы хотите получить счет для всех процессов.

"-a"Аргумент используется для И на выбор (то есть «-p» и «-d» аргументы).

Оператор "awk '{if (NR>1) print}'"используется для пропуска заголовка, который lsofпечатается в его выводе.

Я тестировал, используя следующий 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---

Мне пришлось выполнить скрипт в отладчике perl, чтобы скрипт не завершился и не освободил файловые дескрипторы.

Выполнить: perl -d test.pl

В отладчике perl вы можете запустить программу, введя cи нажав Enter, и если у вас ulimit -Snбыло значение 1024 , вы обнаружите, что программа останавливается после создания Test1017.logфайла в /tmp.

Если вы теперь идентифицируете pid процесса perl и используете указанную выше lsofкоманду, вы увидите, что она также выдает 1024 .

Удалите "wc -l"и замените на, "less"чтобы увидеть список файлов, которые учитываются в пределе 1024 . Удалите "-d ^....."аргумент, а видеть , что cwd,txtи rtdдескрипторы не засчитываются предел.

Если вы сейчас запустите "ls -l /proc/__process_id__/fd/ | wc -l", вы увидите возвращенное значение 1025 . Это связано с тем, lsчто "total 0"в вывод добавлен заголовок, который был подсчитан.

Замечания:

Чтобы проверить, заканчивается ли в ОС дескрипторы файлов, лучше сравнить значение:

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

с

cat /proc/sys/fs/file-max

https://www.kernel.org/doc/Documentation/sysctl/fs.txt описывает, что file-nrи что file-maxозначает.

Джинеш Чокси
источник
0

Похоже, ваши рассуждения звучат примерно так: «Мне нужно снизить этот предел, чтобы у меня не заканчивались драгоценные дескрипторы». На самом деле все наоборот: если на вашем сервере заканчиваются файловые дескрипторы, вам нужно поднять этот предел с 1024 до чего-то большего. Для реалистичной glassfishреализации 32 768 разумно.

Лично я всегда поднимаю лимит примерно до 8 192 по всей системе - 1024 просто смешно. Но вы хотите поднять glassfishвыше. Проверьте /etc/security/limits.conf. Вы можете добавить специальную запись для пользователя, который glassfishзапускается как.

Дэвид Шварц
источник
Я не уверен, как вы могли бы истолковать меня так :-) Мне было интересно, почему это не применимо. Я установлю это выше, но я хочу понять, как это работает также. Если ограничение составляет 1024, то как у Glassfish может быть 1300 ручек?
oligofren
'lsof -u root | grep / | sort -k9 -u' выводит уникальные записи дескриптора файла. Я предполагаю, что количество строк из этого фактического числа относится к ulimit -n.
oligofren
0

Вы хотите взглянуть на общесистемные ограничения, установленные в / proc / sys / fs / file-max, и отрегулировать их там (до следующей перезагрузки) или установить fs.file-max в sysctl.conf, чтобы сделать его постоянным. Это может быть полезно - http://www.randombugs.com/linux/tuning-file-descriptors-limits-on-linux.html

rnxrx
источник
1
Этот комментарий о Bash не является точным. ulimit налагает набор ограничений для идентификатора пользователя для процессов, инициируемых через оболочку, что, по сути, практически все благодаря тому, как дерево процессов создается в Unix-подобных операционных системах. Это не Баш.
EightBitTony
Извините - отредактирую, но комментарий о системных ограничениях все еще остается.
rnxrx
Маловероятно, что он выходит за пределы системы. Возможно, но очень маловероятно.
Дэвид Шварц
EightBitTony: ulimit не устанавливает ulimit для набора ограничений для идентификатора пользователя. Свой процесс, когда применяются pam_limits. Ulimit, что означает «на пользователя», это «ulimit -u» «Максимальное количество процессов, доступных одному пользователю»
без имени пользователя
0

Распространенная ошибка - сравнивать результат необработанного вызова lsof с предполагаемым пределом.

Для глобального ограничения (/ proc / sys / fs / file-max) вы должны взглянуть на / proc / sys / fs / file-nr -> значение fist указывает, что используется, а последнее значение - ограничение

Ограничение OpenFile для каждого процесса, но может быть определено для пользователя, см. Команду "ulimit -Hn" для ограничений пользователя и см. /Etc/security/limits.conf для определений. Обычно применяется с «пользователем приложения», например: «tomcat»: установите ограничение в 65000 для пользователя tomcat, который будет применяться к процессу Java, который он запускает.

Если вы хотите проверить лимит, примененный к процессу, получите его PID, а затем: cat / proc / $ {PID} / limit. Если вы хотите проверить, сколько файлов открывается процессом, получите его PID, а затем: ls -1 / proc / {PID} / fd | wc -l (обратите внимание, для ls это «минус один», не путать с «минус эль»)

Если вы хотите узнать подробности с помощью lsof, но только для тех обработчиков файлов, которые учитывают лимит, попробуйте выполнить следующее: lsof -p $ {PID} | grep -P "^ (\ w + \ s +) {3} \ d + \ D +" lsof -p $ {PID} -d '^ cwd, ^ err, ^ ltx, ^ mem, ^ mmap, ^ pd, ^ rtd, ^ txt '-a

Замечание: «файлы» - это файлы / pipe / TCP-соединения / и т. Д.

Обратите внимание, что иногда вам, вероятно, понадобится быть пользователем root или использовать sudo для получения правильного результата для команд, без привилегий иногда у вас нет ошибок, просто меньше результатов.

и, наконец, если вы хотите знать, к каким «файлам» в вашей файловой системе обращается процесс, взгляните на: lsof -p {PID} | grep / | awk '{print $ 9}' | сортировать | уник

веселиться !

Ронан Кердуду
источник