Проблема 3: Обсуждение слишком большого количества открытых файлов и ulimit

Linux

Too many open filesЯвляется распространенным исключением Java, обычно вызванным конфигурацией системы или программой, открывающей слишком много файлов. Эта проблема часто связана сulimitиспользование связанных. оulimitВ использовании есть много подводных камней, в этой статье мы разберемся с ними.

Исключение слишком много открытых файлов

Ниже приведен стек исключений Java, когда система превышает максимальное количество открытых файлов:

Exception in thread "main" java.io.IOException: Too many open files
	at java.io.UnixFileSystem.createFileExclusively(Native Method)
	at java.io.File.createTempFile(File.java:2024)
	at java.io.File.createTempFile(File.java:2070)
	at com.imshuai.wiki.ulimit.App.main(App.java:16)

Если это не программная проблема (программная проблема, надо посмотреть почему открывается много файлов, например через lsof), то вообще решается настройкой лимита количества открытых файлов через ulimit, но у самого ulimit тоже много ямы, так что подведем итоги.

что такое улимит

Обратитесь непосредственно к справочному документу ulimit (примечание: не man ulimit, а help ulimit, ulimit — это встроенная команда, первая предоставляет справку по ulimit на языке C):

Modify shell resource limits.

Provides control over the resources available to the shell and processes it creates, on systems that allow such control.

Как можно видеть,ulimit обеспечивает управление ресурсами, доступными для оболочки (или процессов, созданных оболочкой).. Помимо количества открытых файлов, управляемыми ресурсами являются: Максимальный размер файла записи, максимальный размер стека, размер файла дампа ядра, ограничение времени ЦП, максимальный размер виртуальной памяти и т. д., help ulimit перечислит ресурсы, ограниченные каждым параметром. или просмотретьulimit -aТакже можно увидеть, что:

maoshuai@ms:~/ulimit_test$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) 100
pending signals                 (-i) 15520
max locked memory       (kbytes, -l) 16384
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 15520
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

понять ulimit

Прежде чем использовать ulimit, есть несколько непонятных моментов:

Измерение управления ulimit

Чтобы понять ulimit, первый вопрос заключается в том, какова размерность предела. Например, если для параметра nofile задано значение 1024, это означаетТекущий пользовательВсего можно открыть только 1024 файла, илипроцесс сеанса с одной оболочкойМожет открывать только 1024 файла? ** На самом деле, help ulimit дал понять: процесс, но мы можем проверить это с помощью следующего метода:

Давайте откроем 800 файлов через java-программу:

class Ulimit{
    public static void main( String[] args ) throws IOException, InterruptedException
    {
    	List<FileInputStream> fileList = new ArrayList<FileInputStream>();
    	for(int i=0;i<800;i++) {
    		File temp = File.createTempFile("ulimit-test", ".txt");
    		fileList.add(new FileInputStream(temp));
    		System.out.println("file_seq=" + i + " " + temp.getAbsolutePath());  
    	}
    	// keep it running, so we can inspect it.
    	Thread.sleep(Integer.MAX_VALUE);
    }
}

Мы устанавливаем nofile на 1024

ulimit -n 1024

Затем мы запускаем два экземпляра процесса:

nohup java Ulimit >a.log &
nohup java Ulimit >b.log &

При проверке журналов a.log и b.log было создано 800 файлов, и ни об одном исключении не сообщалось.

Если вы установите ulimit на 700, повторите проверку и обнаружите, что программа Java сообщает, когда создает 688 файлов.Too many open filesИсключение (причина не 700 в том, что сама java тоже открывает некоторые файлы),

file_seq=688 /tmp/ulimit-test7270662509459661456.txt
Exception in thread "main" java.io.IOException: Too many open files
        at java.io.UnixFileSystem.createFileExclusively(Native Method)
        at java.io.File.createTempFile(File.java:2024)
        at java.io.File.createTempFile(File.java:2070)
        at Ulimit.main(Ulimit.java:12)

Хотя u в ulimit означает пользователя, оказывается,Измерение, контролируемое ulimit, — это сеанс оболочки или процесс, созданный оболочкой (по крайней мере, для nofile). То есть количество файлов, открытых текущим пользователем, может намного превышать значение nofile.

Итак, поlsof | wc -lНеверно проверять количество открытых файлов в системе, чтобы определить, не превышено ли количество открытых файлов. Кроме того,lsof | wc -lДа и не отражает количество открытых системой файлов! (последующая еженедельная добавка)

Различие между мягким и твердым

Вторым важным аспектом понимания ulimit является различие между soft и hard.Ограничения Ulimit на ресурсы делятся на две категории: soft и hard, то есть один и тот же ресурс (например, nofile) имеет два значения soft и hard.

По команде ulimit различает soft и hard с помощью -S и -H. Если -S или -H не указаны, это относится к мягкому при отображении значения и относится к при его установкеУстановите как мягкие, так и жесткие значения.

Но в чем разница между мягким и твердым? Следующее объяснение является более точным (из man 2 getrlimit )

The soft limit is the value that the kernel enforces for the corresponding resource. The hard limit acts as a ceiling for the soft limit: непривилегированный процесс может установить только свое мягкое ограничение на значение в диапазоне от 0 до жесткого ограничения и** (необратимо) **понизить свое жесткое ограничение. возможности) может вносить произвольные изменения в любое предельное значение.

Обобщите разницу между мягким и твердым:

  1. Всякий раз, когда soft всегда меньше или равен hard
  2. Независимо от того, превышает ли он значение soft или hard, операция будет отклонена. В сочетании с первым пунктом это предложение эквивалентно следующему: При превышении мягкого лимита операция будет отклонена.
  3. Процесс может модифицировать soft или hard текущего процесса. Но модификация должна соответствовать правилам:
  • После модификации soft не может превышать hard. То есть, когда soft увеличивается, он не может превышать hard; когда hard уменьшается до значения, меньшего, чем текущий soft, соответственно soft тоже уменьшается.
  • Как некорневые, так и корневые процессы могут увеличивать или уменьшать soft произвольно в диапазоне [0-hard].
  • Процесс без полномочий root может сильно уменьшаться, но не может сильно увеличиваться. То есть nofile изначально был 1000, а его модифицировали на 900. Модифицировать на 1000 нельзя. (Это односторонняя, безвозвратная операция)
  • Корневой процесс может произвольно изменять жесткое значение.

Нет никакой разницы в управлении между soft и hard, что ограничит использование ресурсов, но soft можетМодифицируется самим процессом перед использованием.

Модификация и действие ulimit

Знать ulimit — это хорошо, но, что более важно, как его модифицировать, что является обычной задачей на работе.

Что касается эффекта ulimit, вы можете понять несколько моментов:

  1. Значение ulimit всегда наследует настройку родительского процесса.
  2. Команда ulimit изменяет настройки текущего процесса оболочки. Это также показывает, что,Чтобы гарантировать, что в следующий раз это вступит в силу, измененное место должно быть постоянным.(По крайней мере эквивалентно целевому процессу), например .bashrc или сценарий запуска процесса)
  3. Из пункта 2 также можно сделать вывод, что модификация ulimit не влияет на запущенный процесс.
  4. Увеличьте жесткое значение, что может быть сделано только пользователем root

Ниже приведены два случая:

Случай 1: Для процесса без полномочий root требуется nofile 2048. После проверки текущий софт — 1024, а хард — 4096

Вы можете напрямую добавить ulimit -nS 2048 в сценарий запуска процесса.

Случай 2: Процесс без полномочий root требует nofile 10240. После проверки текущий софт — 1024, а хард — 4096

Очевидно, что пользователи без полномочий root не могут пробиться. Может быть изменено только пользователем root, общая модификация/etc/security/limits.confфайл, способ модификации также описан в комментариях в конфигурационном файле, формат такой:

Запись содержит 4 столбца, которые представляют собой домен диапазона (то есть эффективный диапазон, который может быть именем пользователя, именем группы или * для всех пользователей без полномочий root); тип t: то есть мягкий, жесткий или - означает установить как soft, так и hard; элемент элемента, элемент управления ресурсами в ulimit, перечисление имени может ссылаться на комментарии в файле; последнее является значением. Например, установите для nofile всех пользователей без полномочий root значение 100000.

*  hard nofile 10000
*  soft nofile 10000

Просмотр ограничений запущенного процесса

После изменения ulimit вы можете просмотреть его непосредственно с помощью команды ulimit.Также есть более точный способ просмотра запущенных процессов(Например, чтобы узнать значение ulimit процесса, запущенного до изменения ulimit, требуется этот метод): Проверьте файл limit в каталоге процесса. Например, файл /proc/4660/limits записывает все значения лимитов процесса 4660:

maoshuai@ms:~/ulimit_test$ cat /proc/4660/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             15520                15520                processes 
Max open files            2000                 2000                 files     
Max locked memory         16777216             16777216             bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       15520                15520                signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us 

ulimit без параметров

Раньше был Сяобай, который использовал его напрямуюulimitпосмотреть, посмотреть распечататьunlimited, открытый файл считается неограниченным. Очевидно, это неправильно,help ulimitчетко заявляет:

If no option is given, then -f is assumed.

Поэтому ulimit не добавляет параметры, что эквивалентноulimit -f -S(Это эквивалентно -S без указания -S или -H), что на самом деле относится к максимальному размеру файла, который может быть записан.

разное

Как проверить количество открытых файлов в системе

Хотя команда losf используется для «вывода списка открытых файлов», ее можно использовать сlsof | wc -lПодсчет открытых файлов очень неточен. Основная причина:

  • В некоторых случаях строка может отображать поток вместо процесса.В многопоточных случаях это будет ошибочно принято за многократно открываемый файл.
  • Дочерние процессы совместно используют обработчики файлов Если вы используетеlsofСтатистика, вы должны использовать сложные условия фильтрации. Более простой и точный способ — просмотр каталога /proc. Чтобы система открыла файл, посмотрите непосредственно на /proc/sys/file-nr, где первое число — это количество открытых файлов (ссылка на описание file-nr:woohoo.kernel.org/doc/doc U-дверь…).要查看一个进程的打开文件数,直接查看目录/proc/$pid/fd里的文件数即可:

Java будет автоматически обновлена ​​на жесткий NOFile мягкий предел

В процессе исследования,Я обнаружил, что программа Java, похоже, не зависит от мягкого значения nofile.. Глядя на файл лимитов процесса (/proc/$pid/limits), я обнаружил, что программное обеспечение nofile было обновлено до того же, что и жесткое. Обыскав всю сеть,Обнаружено, что при реализации JDK soft из nofile будет напрямую изменен на то же значение, что и hard., вы можете обратиться к:How and when and where jvm change the max open files value of Linux?

Java, запущенная в eclipse в Ubuntu, и java, запущенная из командной строки, имеют разные nofiles

Через pstree установлено, что java eclipse запускается через gnome-shell, а командная строка запускается через gnome-terminal. где gnome-terminal снова запускается через systemd --user, который, похоже, не читает значение /etc/security/limits.conf. Описание этой ямы есть возможность заполнить заново.

file-max контролирует общее количество файлов, которые может открыть ядро.

Помимо контроля ulimit,/proc/sys/fs/file-maxЭтот файл определяет общее количество файлов, которые может открыть ядро ​​системы. Поэтому, даже если для параметра nofile в ulimit задано значение ulimited, он все равно ограничен.

ulimit общие параметры

ulimit -a # 查看所有soft值
ulimit -Ha # 查看所有hard值
ulimit -Hn # 查看nofile的hard值
ulimit -Sn 1000 # 将nofile的soft值设置为1000
ulimit -n 1000 # 同时将nofiles的hard和soft值设置为1000

Ссылаться на


«Еженедельник изучения Java и Linux» выходит каждую пятницу и одновременно обновляется по адресу:Github,Знай почти,Наггетс