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

2 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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