Миллионы (маленьких) текстовых файлов в папке


15

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

Самый простой способ - хранить все файлы в папке:

$ ls text_files/
1.txt
2.txt
3.txt

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

Два процесса FS будут:

  1. Записать текстовый файл из веб-скрипта (не должно зависеть от количества файлов в папке).
  2. Zip выбранные файлы, заданные списком имен файлов.

Мой вопрос заключается в том, повлияет ли хранение до десяти миллионов файлов в папке на производительность вышеупомянутых операций или общую производительность системы, чем создание дерева подпапок для файлов, в которых они будут жить?


4
Связанный: Как исправить ошибки прерывистого «Нет места на устройстве» во время mv, когда устройство имеет много места . Использование dir_index, которое по умолчанию часто включено, ускорит поиск, но может ограничить количество файлов в каталоге.
Марк Плотник

Почему бы не попробовать это быстро на виртуальной машине и посмотреть, на что это похоже? С bash легко заполнить папку миллионами текстовых файлов со случайными символами внутри. Я чувствую, что вы получите действительно полезную информацию в дополнение к тому, что вы узнаете здесь.
JoshuaD

2
@JoshuaD: Если вы заполняете все сразу на новой FS, вы, скорее всего, будете иметь все смежные иноды на диске, так что ls -lили что-то еще, что statкаждый инод в каталоге (например, bashзавершение глобализации / табуляции) будет искусственно быстрее чем после некоторого износа (удалите несколько файлов, напишите несколько новых). ext4 мог бы справиться с этим лучше, чем XFS, потому что XFS динамически распределяет пространство для инодов и данных, так что я думаю, что вы можете получить иноды более разбросанными. (Но это чистое предположение, основанное на очень небольших подробных знаниях; я едва использовал ext4). Перейти с abc/def/subdirs.
Питер Кордес

Да, я не думаю, что тест, который я предложил, сможет сказать оператору «это сработает», но он может определенно быстро сказать ему «это не сработает», что полезно.
JoshuaD

1
но наши требования к параллелизму и параллелизму делают использование родной файловой системы лучшим выбором. Что вы пробовали? Я бы даже подумал, что даже младшая СУБД, такая как MySQL и Java-сервлет, создающий zip-файлы на летуZipOutputStream , обгонит практически любую свободную собственную файловую систему Linux - я сомневаюсь, что вы хотите платить за GPFS от IBM. Цикл для обработки результирующего набора JDBC и создания этого zip-потока, вероятно, состоит всего из 6-8 строк кода Java.
Эндрю Хенле

Ответы:


10

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

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

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

Это можно решить, выполнив групповые операции с помощью findкоманды:

find <directory> -name '<wildcard expression>' -exec <command> {} \+

или подобный синтаксис, когда это возможно. Он find ... -exec ... \+автоматически примет во внимание максимальную длину командной строки и выполнит команду столько раз, сколько потребуется, при этом подгоняя максимальное количество имен файлов для каждой командной строки.


Современные файловые системы используют B, B + или аналогичные деревья для хранения записей каталога. ru.wikipedia.org/wiki/HTree
dimm

4
Да ... но если оболочка или lsкоманда не узнают, что список каталогов уже отсортирован, им все равно потребуется время для запуска алгоритма сортировки. И, кроме того, пользовательское пространство может использовать локализованный порядок сортировки (LC_COLLATE), который может отличаться от того, что файловая система может делать внутри.
TelcoM

17

Это опасно близко к основанному на мнении вопросу / ответу, но я постараюсь изложить некоторые факты с моими мнениями.

  1. Если в папке очень большое количество файлов, любая операция на основе оболочки, которая пытается их перечислить (например mv * /somewhere/else), может не удастся успешно развернуть подстановочный знак, или результат может быть слишком большим для использования.
  2. ls для перечисления очень большого количества файлов потребуется больше времени, чем для небольшого количества файлов.
  3. Файловая система сможет обрабатывать миллионы файлов в одном каталоге, но люди, вероятно, будут бороться.

Одна из рекомендаций - разделить имя файла на два, три или четыре символа и использовать их в качестве подкаталогов. Например, somefilename.txtможет быть сохранен как som/efi/somefilename.txt. Если вы используете числовые имена, разделите их справа налево, а не слева направо, чтобы обеспечить более равномерное распределение. Например, 12345.txtможет быть сохранен как 345/12/12345.txt.

Вы можете использовать эквивалент, zip -j zipfile.zip path1/file1 path2/file2 ...чтобы избежать включения промежуточных путей подкаталогов в ZIP-файл.

Если вы обслуживаете эти файлы с веб-сервера (я не совсем уверен, что это актуально), тривиально скрыть эту структуру в пользу виртуального каталога с правилами перезаписи в Apache2. Я бы предположил, что то же самое верно для Nginx.


*Расширение будет успешным , если вы бежите из памяти, но если вы не поднять предел STACKSIZE (на Linux) или использовать оболочку , где mvесть встроенный или может быть встроенным (ksh93, ЗШ), то execve()системный вызов может произойти сбой с ошибкой E2BIG.
Стефан

@ StéphaneChazelas да ладно, мой выбор слов мог бы быть лучше, но чистый эффект для пользователя почти такой же. Я посмотрю, смогу ли я немного изменить слова, не увязнув в сложности.
Roaima

Просто любопытно, как вы распакуете этот zip-файл, если не будете включать в него промежуточные пути подкаталогов, не сталкиваясь с обсуждаемыми вами проблемами?
Осьминог

1
@Octopus OP утверждает, что zip-файл будет содержать « выбранные файлы, заданные списком имен файлов ».
Роайма

Я бы рекомендовал использовать zip -j - ...и передавать поток вывода напрямую через сетевое соединение клиента zip -j zipfile.zip .... Запись фактического zip-файла на диск означает, что путь к данным считывается с диска-> сжатие-> запись на диск-> чтение с диска-> отправка клиенту. Это может утроить ваши требования к вводу-выводу диска по сравнению с чтением с диска-> сжимать-> отправлять клиенту.
Эндрю Хенле

5

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

Там в конечном итоге много файлов изображений. Где-то в диапазоне 250000+. Все они хранятся в смонтированном блочном хранилище, где время доступа разумно.

Моя первая попытка хранения изображений была в одной папке как /mnt/images/UUID.jpg

Я столкнулся со следующими проблемами.

  • lsчерез удаленный терминал просто зависнет. Процесс пошел бы зомби и CTRL+Cне сломал бы его.
  • прежде чем я достигну этой точки, любая lsкоманда быстро заполнит выходной буфер и CTRL+Cне остановит бесконечную прокрутку.
  • Сжатие 250000 файлов из одной папки заняло около 2 часов. Вы должны выполнить команду zip, отсоединенную от терминала, в противном случае любое прерывание соединения означает, что вы должны начать заново.
  • Я не рискну пытаться использовать zip-файл в Windows.
  • Папка быстро стала зоной, запрещенной для людей .

В итоге мне пришлось хранить файлы в подпапках, используя время создания для создания пути. Такие как /mnt/images/YYYY/MM/DD/UUID.jpg. Это решило все вышеперечисленные проблемы и позволило мне создавать zip-файлы с указанием даты.

Если единственным идентификатором файла, который у вас есть, является числовое число, и эти числа, как правило, выполняются последовательно. Почему бы не сгруппировать их 100000, 10000а 1000.

Например, если у вас есть файл с именем 384295.txtпуть будет:

/mnt/file/300000/80000/4000/295.txt

Если вы знаете, вы достигнете нескольких миллионов. Используйте 0префиксы для 1 000 000

/mnt/file/000000/300000/80000/4000/295.txt

1

Записать текстовый файл из веб-скрипта (не должно зависеть от количества файлов в папке).

Для создания нового файла требуется сканирование файла каталога на наличие достаточного свободного места для новой записи каталога. Если на диске недостаточно места для хранения новой записи каталога, она будет помещена в конец файла каталога. По мере увеличения количества файлов в каталоге время сканирования каталога также увеличивается.

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

Zip выбранные файлы, заданные списком имен файлов.

Это также может потребовать дополнительного времени в каталоге с миллионами файлов. В файловой системе с хешированными записями каталога (например, EXT4) эта разница минимальна.

Повлияет ли хранение до десяти миллионов файлов в папке на производительность вышеуказанных операций или общую производительность системы, чем создание дерева подпапок для файлов, в которых они будут жить?

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


1

Во-первых: не позволяйте 'ls' сортировать с помощью 'ls -U', возможно, обновите ваш ~ / bashrc, чтобы он имел 'alias ls = "ls -U" или что-то подобное.

Для вашего большого набора файлов вы можете попробовать это следующим образом:

  • создать набор тестовых файлов

  • посмотреть, если много имен файлов вызывают проблемы

  • используйте xargs parmeter-batching и zip (по умолчанию) для добавления файлов в zip, чтобы избежать проблем.

Это сработало хорошо:

# create ~ 100k files
seq 1 99999 | sed "s/\(.*\)/a_somewhat_long_filename_as_a_prefix_to_exercise_zip_parameter_processing_\1.txt/" | xargs touch
# see if zip can handle such a list of names
zip -q /tmp/bar.zip ./*
    bash: /usr/bin/zip: Argument list too long
# use xargs to batch sets of filenames to zip
find . -type f | xargs zip -q /tmp/foo.zip
l /tmp/foo.zip
    28692 -rw-r--r-- 1 jmullee jmullee 29377592 2017-12-16 20:12 /tmp/foo.zip
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.