Назад | Перейти на главную страницу

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

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

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

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

Откровенно говоря, другого выхода нет?

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

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 тоже может), а также фиксированный лимит на каталог.

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

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

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

Например, кеш SQUID делает это так:

f / 4b / 353ac7303854033

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

У нас нет лучшего решения?

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

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

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

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

Вот (более старый) технический документ Microsoft по этой теме: В BLOB или не в BLOB.

Я собрал небольшую веб-галерею, где в итоге столкнулся с разновидностью этой проблемы; У меня «всего» было ~ 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, поэтому я считаю, что это хорошо подходит для хеширования имен пользователей, каталогов и других коротких вещей. И это тоже быстро ...
  • Я не включаю весь хеш, так как он будет создавать слишком много каталогов и эффективно уничтожать дисковый кеш снова и снова.

Не мгновенный ответ на вашу проблему, но что-то, что нужно посмотреть в будущем, - это связанный проект OpenBSD под названием 'Воплощение'

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

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

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

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

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

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

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

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

Например

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

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

У вас должно получиться что-то вроде этого:

/files/1366/5876/

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

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

или

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

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

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

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

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

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

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

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

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

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