Настраиваемые лимиты в Linux

В этой статье разбираемся с лимитами, которые можно задать в операционных системах на базе ядра Linux. Рассмотрим конфиги: sysctl.conf, limits.conf и system.conf.

Введение

В Linux ограничения можно задавать на нескольких уровнях. Одни лимиты действуют для всей системы, другие — для пользователей или отдельных служб SystemD. В этой статье мы рассмотрим три конфига для разных подсистем Linux, с помощью которых можно задать некоторые ограничения для системы, для процессов, для пользователя или служб:

  • Лимиты, накладываемые ядром - sysctl.conf.
  • Лимиты, накладываемые подсистемой PAM - limits.conf.
  • Лимиты, накладываемые системой инициализации SystemD - system.conf.

Несмотря на похожее назначение, эти механизмы работают независимо друг от друга и применяются на разных этапах работы системы.

Лимиты, накладываемые sysctl.conf

Каждый открытый файл занимает файловый дескриптор. Информация об используемых файловых дескрипторах и их лимите хранится в файле /proc/sys/fs/file-nr:

$ cat /proc/sys/fs/file-nr
1120    0       9223372036854775807

В выводе мы видим 3 числа:

  1. Число выделенных файловых дескрипторов (1120) - обычно соответствует числу открытых файлов.
  2. Число выделенных, но не используемых файловых дескрипторов (0). Ядро версии выше чем Linux 2.6 всегда показывает 0, потому что количество выделенных файловых дескрипторов точно соответствует количеству используемых файловых дескрипторов.
  3. Максимальное число файловых дескрипторов (9223372036854775807) - лимит открытых файлов в системе.

Для того, чтобы задать лимит для всей системы, нужно в файле /etc/sysctl.conf использовать параметр fs.file-max:

$ sudo nano /etc/sysctl.conf
fs.file-max=1000000

Применим изменения и проверим:

$ sudo sysctl -p

$ cat /proc/sys/fs/file-nr
1120    0       1000000
  • На практике этот лимит обычно увеличивают, а необходимость уменьшать его возникает крайне редко.

Это был лимит для системы в целом, также можем настроить лимит для каждого процесса. Вначале посмотрим какой лимит стоит по умолчанию. Для этого нужно смотреть файл /proc/sys/fs/nr_open:

$ cat /proc/sys/fs/nr_open
1073741816
  • Любой процесс в системе не сможет открыть более 1073741816 файлов.

Чтобы поменять это значение используем файл /etc/sysctl.conf и параметр fs.nr_open:

$ sudo nano /etc/sysctl.conf
fs.nr_open=65536

$ sudo sysctl -p

$ cat /proc/sys/fs/nr_open
65536

Чтобы узнать, сколько сейчас открыто файлов у произвольного процесса, выполните ls /proc/<pid>/fd | wc -l:

$ sudo ls /proc/1068/fd/ | wc -l
11

А для того, чтобы пробежаться по списку процессов определённого пользователя и узнать сколько файлов эти процессы открыли, я написал такой скрипт:

$ nano openfiles-users-procs.sh

#!/bin/bash

case "$1" in
-h)
echo -e "Скрипт покажет открытые файлы для выбранного пользователя.
Опции:
 -h показать эту справку.
Примеры выполнения:
./files2.sh <username>
./files2.sh <uid>"
;;

*)
if [[ "$#" -eq 1 ]];
then
   id "$1" >/dev/null 2>&1
   if [[ $? -ne 0 ]]; then
   echo 'Пользователь не найден!'
   exit 1
   fi

   for pid in $(ps -u "$1" -o pid=)
   do
      open_files=0

      while IFS= read -r fd
      do
         target=$(readlink "$fd" 2>/dev/null)

         case "$target" in
            socket:*|pipe:*|anon_inode:*|memfd:*|"")
                ;;
            *)
                ((open_files++))
                ;;
         esac
      done < <(find "/proc/$pid/fd" -mindepth 1 -maxdepth 1 2>/dev/null)

      echo "Открытых файлов для PID $pid: $open_files"
done

else
   echo -e "Забыли указать имя или id пользователя!
Или ввели больше одного параметра.
Для справки выполните $0 -h"
fi
;;

esac

Примечание. Скрипт подсчитывает только открытые файлы и исключает сокеты, каналы (pipe), анонимные inode (anon_inode) и другие дескрипторы, не связанные с файлами файловой системы.

Выполнять нужно с sudo:

$ sudo ./openfiles-users-procs.sh alex
Открытых файлов для PID 1100: 6
Открытых файлов для PID 1102: 2
Открытых файлов для PID 1125: 10
Открытых файлов для PID 1126: 4
Открытых файлов для PID 1136: 0
  • Сложив эти числа мы узнаем, сколько файлов открыто у определённого пользователя.

Лимиты, накладываемые PAM — limits.conf

Подсистема PAM (Pluggable Authentication Modules) отвечает за аутентификацию пользователей. PAM используется большинством служб, выполняющих аутентификацию пользователей (SSH, login, su, sudo и др.). При логине в систему, подсистема PAM может наложить определённые лимиты на сеанс пользователя, и эти лимиты настраиваются с помощью /etc/security/limits.conf. Ограничения задаются следующим образом:

$ sudo nano /etc/security/limits.conf

*           soft    core            0
root        hard    core            100000
*           hard    rss             10000
@student    hard    nproc           20
@faculty    soft    nproc           20
@faculty    hard    nproc           50
ftp         hard    nproc           0
ftp         -       chroot          /ftp
@student    -       maxlogins       4

Описание четырёх столбцов:

  1. Указываем кого нужно ограничить:
    • если всех пользователей, пишем звёздочку *;
    • если определённого пользователя, пишем имя пользователя (root);
    • если группу, пишем имя группы начиная с собачки @student.
  2. Дальше задаём тип ограничения: soft или hard
    • Мягкое ограничение. Приложение может приблизиться к мягкому лимиту и, если оно поддерживает обработку соответствующего ограничения, скорректировать своё поведение до достижения жёсткого лимита.
    • Жёсткое - запрещающее ограничение.
    • Если приложение не реагирует на достижение мягкого лимита, то для него и soft и hard сработают одинаково, то есть не дадут получить запрашиваемый ресурс.
  3. В третьей колонке указываем параметр ограничения:
    • core — максимальный размер файла дампа памяти (KB). Такой дамп создаётся при некорректном завершении процесса. Я об этом писал  здесь ;
    • nofile — максимальное число открытых файлов;
    • rss — максимальный размер потребляемой памяти (КБ);
    • nproc — максимальное количество процессов;
    • maxlogins — максимальное количество входов в систему одним пользователем;
    • maxsyslogins — максимальное количество входов в систему всеми пользователями.
  4. В последней колонке задаются значения ограничивающего параметра.

Примечание. Параметр rss соответствует ограничению RLIMIT_RSS, однако на современных ядрах Linux он фактически не используется. Начиная с Linux 2.4.30 ядро игнорирует этот лимит, поэтому для ограничения потребления памяти обычно применяют cgroups или параметры SystemD (MemoryMax=). Параметр сохранён в limits.conf главным образом для совместимости.

Лимиты, накладываемые SystemD — system.conf

В операционных системах с системой инициализации SystemD существует специальный конфиг — /etc/systemd/system.conf. С помощью него можно настроить ограничения по умолчанию для служб. Но также, ограничения можно задавать в самих файлах юнитов, в секции [Service].

Файл system.conf — это основной конфигурационный файл для SystemD.

Когда вы создаёте свой юнит SystemD типа service, то есть службу, вы можете в секции [Service] задать некоторые ограничения для этой службы. Про такие юниты я писал  здесь . Или вы можете ограничить все службы указав общее ограничение в файле system.conf. При этом ограничение в самом юните приоритетнее, чем общее ограничение.

Рассмотрим некоторые из ограничений в таблице:

Параметр в файле system.confПараметр в файле юнитаОписание параметра
DefaultLimitCPU=<секунд>LimitCPU=<секунд>Ограничение в секундах на количество процессорного времени, которое может потреблять процесс. После достижения лимита процесс получает сигнал SIGXCPU. Если он не завершится самостоятельно, ядро принудительно завершит его.
DefaultLimitFSIZE=<байт>LimitFSIZE=<байт>Максимальный размер файлов, которые может создать процесс. При попытке создать файл большего размера процесс либо завершится, либо обработает ошибку и продолжит работать.
DefaultLimitCORE=<байт>LimitCORE=<байт>Максимальный размер файла дампа в байтах, который процесс может сохранить. При значении 0 файлы дампа не создаются. Когда он не равен нулю, большие дампы усекаются до указанного размера.
DefaultLimitNOFILE=<число>LimitNOFILE=<число>Максимальное число открытых файлов.
DefaultLimitAS=<байт>LimitAS=<байт>Максимальный размер виртуальной памяти процесса (address space). После достижения лимита новые попытки выделить память завершаются ошибкой (ENOMEM), а многие приложения после этого завершают работу.
DefaultLimitNPROC=<число>LimitNPROC=<число>Максимальное число процессов.
DefaultLimitNICE=<уровень>LimitNICE=<уровень>Максимальный уровень NICE

Если понравилась статья, подпишись на мой канал в  VK  или  Telegram .