Как эффективно хранить и раздавать миллиарды мелких файлов?

У нас миллиарды мелких файлов. Используем XFS файловую систему с древовидной структурой. Все время сталкиваемся с ситуацией, когда у нас 90% инодов занято и при этом используется только 30% места.
Подход к хранению надо менять.
Задачу условно можно поделить на две секции:
1. Внутренние данные (условно, xml логи, до 100 файлов, объединенные по конкретному ID задачи (Mongo ObjectId), 1.5Тб+ файлов — 0.1...10Кб/файл в gzip, авто-удаление через 2 дня...3 месяца в зависимости от типа) — примерно 500 файлов/секунду прилетает
2. Раздача статики (условно, пользовательские файлы... к примеру, картинки — коих уже 2+Тб)
Надо как-то по хешу выдавать сразу через nginx. S3? MinIO?
  • Вопрос задан
  • 1300 просмотров
Пригласить эксперта
Ответы на вопрос 6
VoidVolker
@VoidVolker
Dark side eye. А у нас печеньки! А у вас?
условно, xml логи

  • Отказаться от хранения логов в ФС, а использовать специализированное решение - агрегатор логов (например).
  • Оптимизировать сами логи: сократить дублирующую и лишнюю информацию, выкинуть малозначимую, оптимизировать формат с целью сокращения объемов самих логов.
  • Для целей именно мониторинга состояний/статусов сервисов/приложений использовать специализированные решения типа заббикса.


Раздача статики (условно, пользовательские файлы... к примеру, картинки — коих уже 2+Тб)

Использовать специализированное файловое хранилище с БД и многуровневым кэшированием и соответствующей ФС. RAM - NVME - HDD. Конкретные решения не подскажу, к сожалению. Хм, а вот тут интересный тред про недостатки и особенности MinIO и судя по которому, в вашем случае оно может не подойти. Из треда:

HDDimon:
Так в итоге какое объектное хранилище вы выбрали? Ванильный hdfs?

onyxmaster:
MongoDB GridFS

HDDimon:
Если не секрет какой кластер и какой объем файлов храните? Какая fs?

onyxmaster:
Объём не очень большой, "чистый" около 150ТБ, чуть больше миллиарда объектов. Работает поверх XFS.


В целом же, рекомендую сделать декомпозицию решения на более простые задачи и разделить нагрузку по разным типам данных на специализированные решения.
Ответ написан
Комментировать
@hx510b
"Я знаю, что ничего не знаю"
В подобной задаче: у нас были сотни миллионов файлов мы их хранили на виртуальных дисках. Одна из причин такого подхода - это ограничение по inode и по iops.
На низлежащей базовой файловой системе эти файлы не хранили, а только на виртуальных дисках.
Таким подходом решались следующие проблемы:
1. Cнимались проблемы с количеством inode
2. Двигать виртуальные диски быстрее, т.к. копирование образа идет с наиболее эффективной скоростью, чем пофайлово. т.е. любые перемещения, перекладки, преобразование хранилища давались меньшей кровью.
3. Делать резервное копирование проще с образами, чем с миллионами файлов.
4. Если вдруг рухнет какая-то файловая система, то она может рухнуть, не утащив за собой все. да, мы попутно разделяли на разные блочные устройства. Чтобы доступ к одному блочному устройству не вешал всю систему.
при это rootfs вообще лучше сделать маленьким и разместить в RAM. Надо сказать, что с разрушением фс на сторадже мы не сталкивались, несмотря на бутерброд: drbd -> ext4 -> loop image -> ext4
5. За счет loop имиджей достигалась экономия пространства за счет оверселлинга: суммарные объем внутри виртуальных дисков мог быть равным или превышать объем низлежащего блочного устройства. Конечно за этим надо следить. Этому помогал zabbix и статичность хранимых файлов.
6. Для прикладных приложений все оставалось обычными файлами. Не пришлось менять код.
В момент создания этого проекта технологий было меньше чем сейчас, еще меньше было проверенных технологий. Все облачные масштабируемые хранилища слишком медленные и не дают прямого доступа к файлам.
Поэтому использовали обычный набор:
1. DRBD для сетевого зеркаливания между нодами.
2. EXT3/EXT4 инициализированные с большим количеством inode.
3. loop images - штатная возможность создания блочных устройств в файлах.
4. sparse files - технология пропуска пустых блоков внутри файла.
5. обычные symlinks.
Несмотря на некоторую сложность в начале, подход себя оправдал.

По монтированию все выглядит примерно так:
root /
+- block device ext4
+- block device ext4
+- block device ext4
...

Внутри каждого блочного устройства block device ext4:
vdisk0.img
vdisk1.img
vdisk2.img
...

Монтируются они все в каталоги в дерево виртуального хранилища:
/virtstore
+- virtfolder0 
+- virtfolder1 
+- virtfolder2
...

За счет древовидной структуры каталогов, симлинков получали более менее пригодную схему для работы
Что еще можно сделать:
1. для миллионов мелких файлов можно в образе диска использовать btrfs со сжатием. для доступа только на чтение получается серьезная экономия по месту. но только в режиме чтения. при перезаписи плотность "упаковки" падает.
2. для интенсивной записи нужно разнести запись на разные блочные устройства. Чем больше физических блочных устройств, тем легче расшить узкие места по нагрузке и получить приемлемую производительность всей системы.

Для примера, команды для работы:

Создаем sparse имидж на 850 гб
dd if=/dev/zero bs=1M seek=850000 count=1 of=/path/to/image.img

либо
truncate -s 850G /path/to/image.img

Инициализация ФС:
mkfs.ext4 -m 0 -O dir_index -O resize_inode -t ext4  /path/to/image.img

Монтируем имидж:
mount -o loop /path/to/image.img /path/to/mount/point/

Для ускорения работы, монтировать лучше с оптимизированным параметрами монтирования, например:
rw,nosuid,nodev,noatime,nodiratime,strictatime
Соответственно такие образы можно монтировать, размонтировать, копировать и двигать. Можно уменьшать и увеличивать размер такого образа.
Ответ написан
Комментировать
saboteur_kiev
@saboteur_kiev
software engineer
gzip не лучшее решение, ибо он stream, и для случайного доступа к конкретному файлу лучше хотя бы zip

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

Если не файлы, то я думаю s3 (который внутри объектно-ориентированная база) либо другая объектно ориентированная база (ибо s3 бывает медленный)
Ответ написан
dimonchik2013
@dimonchik2013
non progredi est regredi
https://t.me/Seaweedfs

ну или минио , да
Ответ написан
Griboks
@Griboks
Как эффективно хранить и раздавать миллиарды мелких файлов?

Если вам не подходит файловая система, тогда используйте реляционную базу данных.
Ответ написан
mayton2019
@mayton2019
Bigdata Engineer
На ум приходит идея - разделить файлы. По размеру и по роду доступа.
Например картинки - положить не в файловую систему а во внешнее хранилище типа S3.
Здесь мы исходим из предположения что размер файла будет - как средний размер фотографии в jpeg.
Потому что за более мелкими - будет дорого ходить по сети кудато.

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

XFS - хорошая система. Я все магнитные блины в нее переформатировал но не было такого опыта с мелкими.
У меня как раз очень большие файлы лежат. Датасеты.

Еще я-бы предложил посмотреть на саму прикладную задачу с точки зрения коррелированного доступа.
Например каждый пользователь читает свой index.htm, avatar.jpg, e.t.c. Имеет смысл этот сет файлов
запаковать в очень быстрый архив. По сути в пакет даже без сжатия чтобы по заказу быстро отдавать
эту пачку по сети (user_id.pack). А там уж браузер разберется. Пришлем лишнее - не страшно. Все равно пакет летит.
Главное что теперь у нас нет россыпи мелких файлов а есть среднего размера упаковки на каждого
пользователя по user_id.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы