Назад | Перейти на главную страницу

Настройка tmpfs `/ run / lock` для сотен тысяч файлов блокировки по 0 байт и работа с ограничением inode

У меня есть ситуация, когда мне нужно создать сотни тысяч файлов блокировки по 0 байтов для управления параллелизмом.

Я тестировал их создание, используя:

for i in `seq 1 50000`; do touch "/run/lock/${i}.lock"; done

Поскольку файлы имеют размер 0 байт, они не занимают места в разделе. Смотря на df -h:

Filesystem      Size  Used Avail Use% Mounted on
tmpfs            50M  344K   49M   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            246M     0  246M   0% /run/shm
none            100M     0  100M   0% /run/user

В 0% цифра вообще не меняется в /run/lock строка.

Однако размер памяти увеличивается в среднем примерно на 1 КБ на файл блокировки. Я обнаружил это, сравнив free -h до и после создания 70000 файлов блокировки внутри /run/lock. Это увеличение памяти отразилось на реальном использовании памяти (виртуальная память за вычетом буферов / кеша).

Позже я обнаружил, что это увеличение на 1 КБ, скорее всего, связано с inode. Поэтому я проверил использование inode, используя df -i:

Filesystem      Inodes  IUsed   IFree IUse% Mounted on
tmpfs            62729    322   62407    1% /run
none             62729  50001   12728   80% /run/lock
none             62729      1   62728    1% /run/shm
none             62729      2   62727    1% /run/user

Как видите, файлы блокировки увеличивают количество узлов внутри /run/lock раздел.

В настоящее время я использую Ubuntu и /run крепления не отражаются внутри /etc/fstab. Бег mount дает мне:

tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755)

У меня есть пара вопросов по этому поводу (но первый из них самый важный):

  1. Как мне увеличить лимит inode навсегда для /run/lock? Чтоб этот лимит выдержал перезагрузки?
  2. Было бы лучше для меня создать свой собственный каталог и смонтировать в нем tmpfs, чтобы использовать для этого вместо использования /run/lock?
  3. Является ли ограничение размера каждого раздела полностью независимым друг от друга? Это хранение файлов в /run похоже, не влияет /run/lock и наоборот.
  4. 1 КБ получен из inode? Я заметил, что при создании непустых файлов базовый блок составляет 4 КБ для каждого файла.
  5. Почему /run учитывая тип файловой системы tmpfs но /run/lock, /run/shm, /run/user указать тип файловой системы "none", тем более что все они поддерживаются TMPFS? Почему не все они читаются как tmpfs в Filesystem столбец?
  6. Если все каталоги независимо ограничены, как обработчик OOM-убийцы справляется с ситуацией, когда имеется несколько полных разделов TMPFS, каждый из которых имеет размер до 50% ОЗУ, и где также есть процессы, конкурирующие за ОЗУ. Очевидно, что нельзя использовать более 100% ОЗУ. Согласно https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt в нем упоминается, что система зайдет в тупик. Как это работает?

Отвечая на некоторые из ваших вопросов по порядку:

  1. Ты можешь использовать mount -o remount,nr_inodes=NUM /run/lock в скрипте запуска вашего приложения (если он запущен с uid = 0). Также должно быть безопасно добавить соответствующую строку в / etc / fstab, но не тестировал.
  2. Разделение здесь имеет некоторый смысл, так как в случае заполнения всех инодов не будет мешать остальной части системы.
  3. Да, полностью независимый.
  4. [...]
  5. В виртуальных файловых системах (не основанных на блочных устройствах) вы можете указать любое устройство в команде монтирования, значение имеет только тип.
  6. [...]

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

Вы идете в неправильном направлении. Вы можете использовать семантику файловой системы для обеспечения согласованности.

  1. Если вы хотите прочитать файл, просто откройте и прочтите его. Вам следует всегда использовать open, никогда access для этой операции. Если вы используете для этого библиотеку PHP, убедитесь, что она просто вызывает open и нет access в файле - но fopen должно работать нормально.

  2. Когда вы хотите обновить или создать новый файл, вы выполняете следующие операции: -

    • Создайте новый файл, используя механизм создания временного файла. Если его не существует - создайте новое имя файла, которое вряд ли будет существовать (filename.XXXXXX, где X заменяется случайными символами). Обязательно откройте в O_EXCL.
    • Запишите соответствующие данные в файл.
    • Переименуйте файл в имя старого файла.

Это безопасно с операционной точки зрения, потому что переименования определены как атомарные. Читатель, открывающий файл, увидит либо старый файл, либо новый файл, но никогда не увидит несуществующий файл в кэше.

В худшем случае, когда выполняется множество одновременных проверок каждого файла, несколько писателей на короткое время перезапишут друг друга. Но это способ - намного дешевле, чем использовать файловую блокировку для каждого файла.

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

С помощью rename и link семантика в этом случае гарантирует согласованность с вашим кешем и намного дешевле в управлении, чем файлы блокировки.