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

Наш сервер недавно исчерпал файловые дескрипторы, и в связи с этим у меня есть несколько вопросов. ulimit -n должен дать мне максимальное количество дескрипторов открытых файлов. Это число 1024. Я проверил количество дескрипторов открытых файлов, запустив lsof -u root |wc -l и получил 2500 фдс. Это намного больше, чем 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), так что это похоже на шаг в правильном направлении. "К сожалению" я не испытываю никаких проблем с исчерпанием файловых дескрипторов, поэтому мне будет трудно это проверить.

6 ответов

Я проверял это в 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: слишком много открытых файлов в журналах процессов)

@oligofren

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

  • Как и плакат, выбранный в ссылке, 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 исключить файловые дескрипторы типа: cwd/err/ltx/mem/mmap/pd/rtd/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" Аргумент используется для AND выбора (то есть аргументы "-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 имею в виду.

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

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

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

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

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

Распространенная ошибка - сравнивать результат необработанного вызова 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}' | сортировать | уник

повеселись!

Другие вопросы по тегам