Мільйони (невеликих) текстових файлів у папці


15

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

Найпростіший спосіб - це зберігання всіх файлів у папці:

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

що має бути можливим у файловій системі EXT4 , яка не обмежує кількість файлів у папці.

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

  1. Напишіть текстовий файл із веб-фрагмента (не повинно впливати кількість файлів у папці).
  2. Zip вибрані файли, задані списком імен файлів.

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


4
Пов’язані відомості: Як виправити помилки "Не залишається місця на пристрої" під час роботи телевізора, коли у пристрою багато місця . Використання dir_index, яке часто включається за замовчуванням, прискорить пошук, але може обмежити кількість файлів у каталозі.
Марк Плотнік

Чому б не спробувати його швидко на віртуальній машині і подивитися, що це таке? За допомогою bash тривіально заповнювати папку з мільйоном текстових файлів із випадковими символами всередині. Я відчуваю, що ви отримаєте дійсно корисну інформацію таким чином, крім того, що ви тут дізнаєтесь.
ДжошуаD

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

Так, я не думаю, що тест, який я запропонував, зможе сказати ОП "це спрацює", але це, безумовно, може швидко сказати йому "це не буде працювати", що корисно.
ДжошуаD

1
але наші вимоги до паралельності та паралелізму роблять використання рідної файлової системи найкращим вибором Що ви спробували? Зрештою, я думаю, що навіть нижчі версії RDBMS, такі як MySQL та сервлет Java, що створюють поштові файли на ходу,ZipOutputStream можуть бити майже за будь-яку безкоштовну рідну файлову систему Linux - я сумніваюся, що ви хочете заплатити за GPFS IBM. Цикл для обробки набору результатів JDBC та створення цього потоку zip, ймовірно, становить лише 6-8 рядків коду Java.
Ендрю Генле

Відповіді:


10

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

Якщо ви можете протистояти закликам до завершення TAB і, наприклад, написати імена файлів, які потрібно зафіксувати повністю, не повинно виникнути проблем.

Ще однією проблемою з підстановкою може бути розширення підстановки, можливо, створить більше імен файлів, ніж буде розміщено в командному рядку максимальної довжини. Типова максимальна довжина командного рядка буде більш ніж достатньою для більшості ситуацій, але коли ми говоримо про мільйони файлів в одному каталозі, це вже не є безпечним припущенням. При перевищенні максимальної довжини командного рядка при розширенні підстановки, більшість оболонок просто відмовлять від усього командного рядка, не виконуючи його.

Це можна вирішити, виконуючи операції з wildcard за допомогою findкоманди:

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

або подібний синтаксис, коли це можливо. find ... -exec ... \+Буде автоматично брати до уваги максимальну довжину командного рядка, і виконати команду стільки раз , скільки потрібно при монтажі максимальну кількість імен файлів кожної командного рядка.


Сучасні файлові системи використовують B, B + або подібні дерева для збереження записів у каталозі. en.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-файл буде містити " вибрані файли, задані списком імен файлів ".
roaima

Я рекомендую використовувати zip -j - ...та передавати потоковий вихід безпосередньо в мережеве з'єднання клієнта zip -j zipfile.zip .... Запис фактичного zipfile на диск означає, що шлях даних зчитується з диска-> стискання>> запису на диск-> читання з диска-> надсилання клієнту. Це може втричі перевищити вимоги вводу-виводу вашого диска при прочитанні з диска-> стиснення-> надсилання клієнту.
Ендрю Генле

5

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

У кінцевому рахунку багато файлів зображень. Десь у діапазоні 250 000+. Усі вони зберігаються в змонтованому блоці зберігання даних, де розумний час доступу.

Моя перша спроба зберігання зображень була в одній папці як /mnt/images/UUID.jpg

Я зіткнувся з наступними викликами.

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

Мені довелося зберігати файли в папках, використовуючи час створення для створення шляху. Як от/mnt/images/YYYY/MM/DD/UUID.jpg . Це вирішило всі вищезазначені проблеми і дозволило мені створити поштові файли, націлені на дату.

Якщо єдиний ідентифікатор для файлу у вас є числовим числом, і ці числа, як правило, працюють послідовно. Чому б не згрупувати їх 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 парметрування та поштову поведінку (за замовчуванням) додавання файлів до 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.