Настройка 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)
У меня есть пара вопросов по этому поводу (но первый самый важный):
- Как я могу увеличить предел инодов навсегда для /run/lock? Так что этот предел переживает перезапуски?
- Было бы лучше для меня создать свой собственный каталог и смонтировать на нем tmpfs, чтобы использовать его вместо использования /run/lock?
- Является ли ограничение размера каждого раздела полностью независимым друг от друга? Это хранит файлы в /runпохоже не влияет/run/lockи наоборот.
- 1KB получен из инода? Я заметил, что при создании непустых файлов базовый блок составляет 4 КБ для каждого файла.
- Почему /runучитывая тип файловой системыtmpfsно/run/lock,/run/shm,/run/userуказать тип файловой системы "none", тем более что все они поддерживаются TMPFS? Почему они все не читаются какtmpfsвFilesystemстолбец?
- Если все каталоги независимо ограничены, как OOM killer обрабатывает ситуацию, когда имеется несколько полных разделов TMPFS, каждый из которых имеет размер до 50% ОЗУ, и где также существуют процессы, борющиеся за ОЗУ. Очевидно, что нельзя использовать более 100% оперативной памяти. Согласно https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt нем упоминается, что система заблокирована. Как это работает?
2 ответа
Отвечая на некоторые ваши вопросы, по порядку:
- Ты можешь использовать mount -o remount,nr_inodes=NUM /run/lockв вашем скрипте запуска приложения (в случае, если он запускается с uid=0). Также должно быть безопасно добавить соответствующую строку в / etc / fstab, но не проверено.
- Разделение здесь имеет некоторый смысл, так как в случае заполнения все inode не будут мешать остальной системе.
- Да, полностью независимый.
- [...]
- С виртуальными файловыми системами (основанными не на блочных устройствах), вы можете указать в качестве команды монтирования любое устройство, это имеет значение только для типа.
- [...]
Не уверен, что ваше приложение создаст пустые файлы, открыв его (и как долго), но вы можете также рассмотреть возможность увеличения лимита открытых файлов (проверьте ulimit), чтобы избежать истощения.
Вы идете об этом в неправильном направлении. Вы можете использовать семантику файловой системы для обеспечения согласованности.
- Если вы хотите прочитать файл, просто откройте и прочитайте его. Вы должны всегда использовать - open, никогда- accessдля этой операции. Если вы используете для этого библиотеку PHP, убедитесь, что она просто вызывает- openи не- accessв файле - но- fopenдолжно работать нормально.
- Когда вы хотите обновить или создать новый файл, вы выполняете следующие операции:- - Создайте новый файл, используя механизм создания временного файла. Если он не существует - создайте новое имя файла, которое вряд ли существует (filename.XXXXXX, где X заменяется случайными символами). Обязательно откройте в O_EXCL.
- Запишите соответствующие данные в файл.
- Переименуйте файл в имя старого файла.
 
Это операционно безопасно, потому что переименования определены как атомарные. Читатель, открывающий файл, увидит либо старый файл, либо новый файл, но никогда не будет несуществующим файлом в кэше.
В худшем случае при множестве одновременных проверок каждого файла несколько авторов кратко перезаписывают друг друга. Но это намного дешевле, чем использование блокировки файлов для каждого файла.
В качестве альтернативы, вместо того, чтобы иметь файл блокировки для каждого файла - рассмотрите просто блокировку каждого отдельного объекта кеша напрямую. Я все еще не думаю, что это масштабируется как бы то ни было.
С помощью rename а также link семантика в этом случае гарантирует согласованность с вашим кешем и намного дешевле в управлении, чем блокировка файлов.