Как решить ограничение количества подкаталогов linux?


9

У меня есть веб-сайт, на котором будут храниться изображения профиля пользователя. Каждое изображение хранится в каталоге (Linux), специфичном для пользователя. В настоящее время у меня 30+ клиентов, что означает, что у меня будет более 30 папок. Но моя текущая версия Linux (ext2 / ext3) не поддерживает создание более 32000 каталогов. Как мне пройти это? Даже у ребят на YouTube такая же проблема, с видео-миниатюрами. Но они решили это, перейдя на ReiserFS. Разве у нас не может быть лучшего решения?

Обновление: когда их спрашивали в IRC, люди спрашивали об обновлении его до ext4, который имеет ограничение в 64 КБ, и, конечно, вы даже можете пройти через это . Или взлом ядра для изменения лимита.

Обновление: как насчет разделения базы пользователей на папки на основе диапазона идентификаторов пользователей. Значение 1-1000 в одной папке, 1000-2000 в другой, вот так. Это кажется простым. Что скажешь, ребята?

Честно говоря, нет другого пути?


1
Почему вы не хотите изменить файловую систему? Если это ограничение ext2 / 3, у вас не будет никаких других изменений, кроме изменения файловой системы или разделения текущей FS на более мелкие FS (более разные точки монтирования).
Мануэль Фо

1
Мануэль: Если он меняет файловую систему, он привязывает конкретную ФС к своему приложению. Хотя это может в конечном итоге быть ответом, я бы, вероятно, это проблема, которая должна быть решена на уровне приложений. Если вам нужно взломать ядро ​​или файловую систему, вы, вероятно, идете по неверному пути, если не предъявляете особых требований.
Кайл Брандт

Ответы:


16

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

top_level_dir
|---aa
|   |---aardvark1
|   |---aardvark2
|---da
|   |---dan
|   |---david
|---do
    |---don

Еще лучше было бы создать некоторую форму хеширования имен и использовать ее для разделения. Таким образом, вы получите лучшее распределение по каталогам, а не с начальным примером букв, когда «da» будет очень полным, а «zz» - полностью пустым. Например, если вы берете CRC или MD5 имя и используете первые 8 бит, вы получите что-то вроде этого:

top_level_dir
|---00
|   |---some_username
|   |---some_username
|---01
|   |---some_username
...
|---FF
|   |---some_username

Это может быть расширено до необходимых глубин, например, так, если используется имя пользователя, а не хеш-значение:

top_level_dir
|---a
|   |---a
|       |---aardvark1
|       |---aardvark2
|---d
    |---a
    |   |---dan
    |   |---david
    |---o
        |---don

Этот метод используется во многих местах, таких как кеш squid, для копирования примера Людвига и локальных кешей веб-браузеров.

Важно отметить, что с ext2 / 3 вы начнете сталкиваться с проблемами производительности, прежде чем вы все равно приблизитесь к пределу 32000, так как каталоги ищутся линейно. Переход на другую файловую систему (например, ext4 или reiser) устранит эту неэффективность (reiser выполняет поиск в каталогах с двоичным алгоритмом разделения, поэтому длинные каталоги обрабатываются гораздо эффективнее, ext4 тоже может это сделать), а также фиксированный лимит на каталог.


Просто обновил описание вопроса, включив в него следующее: «Обновление: как насчет разделения базы пользователей на папки на основе диапазона идентификаторов пользователей. Значения 1–1000 в одной папке, 1000–2000 в другой. Это кажется простым. Что Вы говорите?"
Нон-да

1
Это будет хорошо работать и будет более эффективным, чем хеш, если пользователи обычно идентифицируются по идентификатору пользователя вместо (или так же) имени пользователя. Хотя, если вы всегда будете ссылаться на них по имени в другом месте системы, вам нужно будет добавить дополнительные поиски по имени-> id повсюду.
Дэвид Спиллетт

Спасибо, Дэвид! Я пробовал даже другое решение. Я создал всего 4 папки с диапазоном 1-30000, 30000-60000 и т. Д. Я думаю, что получение файла из такого большого каталога займет больше времени, чем из каталога, содержащего 1000 файлов (предыдущий подход). Что ты говоришь?
Нон-да

1
Это зависит от файловой системы. Если вы используете ext2 или ext3, я бы порекомендовал гораздо меньше, чем 30000 на каталог. Некоторые инструменты выдают предупреждения около 10000. Вы можете включить индексирование каталогов в ext3 / 4, чтобы помочь: tune2fs -O dir_index / dev / <coemename>, но просто поддерживая количество объектов в каталоге ниже (пару тысяч или меньше?), Я бы порекомендовал здесь ,
Дэвид Спиллетт

@ Мэдди, вам нужно это решение из-за других ограничений того, как Ext2 / 3 обрабатывает большое количество файлов. См. Serverfault.com/questions/43133/… для некоторых деталей. Разбиение имен в подкаталоги buckets-as-облегчает другие проблемы, с которыми вы могли бы столкнуться в конечном итоге. Обратите внимание, что это та же стратегия, которую использует Squid при первой настройке кеша объектов - например, по 64 директории в каждой по 64 директории внутри, просто в качестве примера.
Эйвери Пейн

7

Если вы связаны с ext2 / ext3, единственная возможность, которую я вижу, это разделить ваши данные. Найдите критерий, который разбивает ваши данные на управляемые куски одинакового размера.

Если бы речь шла только об изображениях профиля:

  1. Используйте хеш (например, SHA1) изображения
  2. Используйте SHA1 в качестве имени файла и каталога

Например, кеш SQUID делает это следующим образом:

F / 4b / 353ac7303854033

Каталог верхнего уровня - это первая шестнадцатеричная цифра, второй уровень - следующие две шестнадцатеричные цифры, а имя файла - оставшиеся шестнадцатеричные цифры.


2

Не можем ли мы найти лучшее решение?

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

Смотрите здесь для сравнения файловых систем.

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


У вас есть хорошие ссылки на производительность файловой системы NTFS?
Турбьерн Равн Андерсен

да, кроме личного опыта с приложением, которое слишком долго оставалось для создания новых файлов в каталоге ... (для их удаления потребовались часы), а также для повышения производительности Subversion за счет ограничения числа файлов в каталоге до 1000. Или прочитайте : support.microsoft.com/kb/130694 Я не думаю, что они когда-либо "исправляли" это, как это все еще отмечалось как перфект. твик для NTFS.
gbjbaanb

1

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

Вот (старая) техническая статья Microsoft на тему: BLOB или не BLOB .


1

Я взломал небольшую веб-галерею, где я нашел вариант этой проблемы; У меня «только» было около 30 000 изображений в каталоге кеша, что оказалось довольно медленным (ext2 использует связанные списки для индексов каталогов, насколько я помню).

Я закончил тем, что делал что-то вроде этого:

def key2path(key):
    hash = md5(key)
    return os.path.join(hash[0], hash[1], key)

Это разделит данные на 256 каталогов, что обеспечивает быстрый поиск по каталогам для каждого из трех уровней.

  • Я решил использовать MD5 вместо SHA-1, так как MD5 гарантирует другой вывод, если вы измените любые 12 битов из 32, поэтому я считаю, что он хорошо подходит для хэширования имен пользователей, каталогов и прочего. И это тоже быстро ...
  • Я не включаю весь хэш, так как он будет производить слишком много каталогов и эффективно очищать кэш диска снова и снова.

1
Возможно, вы могли бы использовать более простой хеш, такой как CRC, поскольку хеш не должен быть криптографически сильным, как MD5 или SHA ... но разница в производительности, вероятно, в любом случае незначительна ...
sleske

0

Не немедленный ответ на вашу проблему, но то, на что стоит обратить внимание в будущем - это связанный с OpenBSD проект под названием «Epitome».

Epitome - это механизм, который предоставляет услуги хранения в одном экземпляре, хранения с адресным содержимым и дедупликации.

Все ваши данные хранятся в хранилище данных в виде хешированных блоков, удаляя неуникальные блоки, чтобы сократить использование пространства, и позволяет вам по существу забыть о механизме хранения, поскольку вы можете просто запрашивать содержимое из хранилища данных по UUID.

Epitome в настоящее время является экспериментальным, но есть что посмотреть на будущее.


0

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

Найдите решение, которое создает более глубокое, но более узкое дерево, например, путем создания подпапок, как описано другими.


0

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

Конечно, если у вас сложное приложение, которое опирается на плоскую структуру каталогов, вам, вероятно, потребуется много исправлений. Поэтому полезно знать, что существует обходной путь, используйте символические ссылки, у которых нет упомянутого ограничения в 32 КБ. Тогда у вас будет достаточно времени, чтобы исправить приложение ...


0

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

Например

Допустим, ваша временная метка: 1366587600

Пропустите последние 2 цифры (иначе это просто немного смешно). Разделите штамп на наборы по 4 (количество каталогов не должно превышать 9999 - если вы хотите, вы можете разделить его по-другому).

Это должно оставить вас с чем-то вроде этого:

/files/1366/5876/

Затем также проверьте сумму в dir перед загрузкой, если она получает большое количество загрузок (то есть 32000 + за 100 секунд), затем выполните итерацию каталога по секунде или букве, например:

/files/1366/5876/a/file.txt

или

/files/1366/5876/00/file.txt

Затем зарегистрируйте отметку времени + букву или полный код пути в БД вместе с пользователем, и вы должны быть установлены.

pathstamp: 1366587600 или 13665876a (если вы используете буквы).

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


0

Я бы предложил решить, сколько максимальных подкаталогов вы хотите (или можете) иметь в родительской папке.

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

Тогда вы можете сделать: modulo = currentId % numberOfSubdirectories

moduloтеперь будет содержать номер вашего подкаталога, который никогда не будет больше, чем numberOfSubdirectoriesвы выбрали.

Делай что хочешь с модулем, хеш это, например.

Также таким образом подкаталоги будут заполняться линейно.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.