Хранение большого количества изображений

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

В базе данных я укажу на URL-адрес изображения, но вот проблема: я знаю, что нецелесообразно размещать все в одном каталоге на сервере, поскольку это замедлит доступ к сканированию, поэтому как бы вы хранить их все? Какое-то дерево на основе имени jpeg / png?

Какие правила разделения изображений вы бы порекомендовали мне?

(Он будет ориентирован на использование в дешевых точечных coms, поэтому никакие манипуляции с сервером невозможны)


person Saiyine    schedule 15.01.2009    source источник


Ответы (12)


У нас была похожая проблема в прошлом. И нашел хорошее решение:

  • Дайте каждому изображению уникальный путеводитель.
  • Создайте запись в базе данных для каждого изображения, содержащую имя, расположение, guid и возможное расположение вспомогательных изображений (эскизы, уменьшенный размер и т. Д.).
  • Используйте первые (один или два) символа руководства для определения папки верхнего уровня.
  • Если в папках слишком много файлов, разделите их снова. Обновите ссылки, и вы готовы к работе.
  • Если количество файлов и доступов слишком велико, вы можете распределить папки по разным файловым серверам.

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

Ссылки, которые могут помочь сгенерировать уникальный идентификатор:

person Toon Krijthe    schedule 15.01.2009
comment
Если вы все равно используете базу данных, почему бы просто не превратить ее в большой двоичный объект и позволить базе данных позаботиться об этом? - person falstro; 15.01.2009
comment
из-за производительности вызовы базы данных обычно очень дороги, особенно для двоичных данных, таких как изображения. - person Mike Geise; 15.01.2009
comment
не говоря уже о том, что обслуживание изображений из базы данных означает, что вы почти всегда отправляете данные туда, где, как если бы вы могли обслуживать их из файловой системы, вы можете позволить браузеру / серверу обрабатывать кеширование изображений - person MikeJ; 24.03.2009
comment
@Gamecat IMHO, гораздо лучше, чем создание UUID, - это просто хешировать имя файла и использовать его начало в качестве имени каталога. Таким образом, вам не понадобится база данных, поскольку вы всегда можете пересчитать хэш, что намного быстрее, чем доступ к базе данных. (Я вижу, вы упомянули SHA-1, но не рекомендовали это явно). - person maaartinus; 21.03.2011
comment
@maaartinus, вы, наверное, правы. Но у нас уже была база данных (для CMS), которую нам просто нужно было связать с изображениями, и это отлично сработало для нас. - person Toon Krijthe; 21.03.2011
comment
Понятно (я тоже буду использовать хэш и базу данных). - person maaartinus; 22.03.2011
comment
Если у вас есть целочисленный уникальный идентификатор, простой способ сделать это - разбить его на три уровня: xxx / yyy / filename.jpg. Таким образом, вы можете использовать уникальный идентификатор. Например, если идентификатор равен 100789, он будет сохранен как 100/789 / filename.jpg. Тогда у вас есть до 1000 каталогов на каждом уровне. И всего 1000000 файлов. И у вас может быть несколько имен файлов в зависимости от разрешения: thumbnail.jpg, small.jpg и т. Д. - person B Seven; 03.05.2011
comment
Я также рекомендую использовать в вашем хэше известную константу при создании имен папок. Это мешает загрузчикам легко определять папку, в которую вы помещаете свои файлы (они могут хэшировать свои собственные изображения с помощью sha1, если они знают, как вы создаете папки). - person Steve Midgley; 10.11.2014

Несколько лет назад я работал над системой электронного управления документами, и мы сделали в значительной степени то, что предлагали Gamecat и wic.

То есть назначьте каждому изображению уникальный идентификатор и используйте его для получения относительного пути к файлу изображения. Мы использовали MOD, аналогичный тому, что предлагал wic, но мы разрешили 1024 папки / файла на каждом уровне, с 3 уровнями, поэтому мы могли поддерживать файлы размером 1 ГБ.

Однако мы удалили расширение из файлов. Записи БД содержали MIME-тип, поэтому расширение не требовалось.

Я бы не рекомендовал хранить в записи БД полный URL, только ID изображения. Если вы сохраняете URL-адрес, вы не можете переместить или реструктурировать свое хранилище без преобразования вашей БД. Относительный URL-адрес был бы приемлемым, поскольку таким образом вы можете по крайней мере перемещать репозиторий изображений, но вы получите больше гибкости, если просто сохраните идентификатор и получите URL-адрес.

Кроме того, я бы не рекомендовал разрешать прямые ссылки на ваши файлы изображений из Интернета. Вместо этого предоставьте URL-адрес серверной программы (например, сервлета Java) с идентификатором изображения, указанным в URL-запросе (http://url.com/GetImage?imageID=1234).

Сервлет может использовать этот идентификатор для поиска записи БД, определения типа MIME, определения фактического местоположения, проверки ограничений безопасности, ведения журнала и т. Д.

person Clayton    schedule 15.01.2009
comment
хорошие моменты. позволяет ли запрос сервлета кэшировать? Я наблюдаю аналогичную проблему, но в моем приложении время передачи имеет решающее значение, поэтому я искал способы кэширования изображений на клиенте. Я сплю? - person MikeJ; 24.03.2009
comment
@MikeJ: Вы можете создать отдельный класс для доступа к изображениям. Этот класс будет знать, как получить путь из идентификатора и т. Д. Он также может содержать кеш, возможно, в виде хэш-таблицы, которой вы управляете самостоятельно, или, возможно, консервированный класс кеша. Сервлет будет получать изображения с этого объекта, а не с диска. - person Clayton; 24.03.2009

Обычно я просто использую числовой идентификатор базы данных (auto_increment), а затем использую оператор модуля (%), чтобы выяснить, куда поместить файл. Просто и масштабируемо. Например, путь к изображению с идентификатором 12345 можно создать так:

12345 % 100 = 45
12345 % 1000 = 345

Заканчивается через:

/home/joe/images/345/45/12345.png

Или что-то вроде того.

Если вы используете Linux, ext3 и файловую систему, вы должны знать, что есть ограничения на количество каталогов и файлов, которые вы можете иметь в каталоге. Ограничение составляет 32000 каталогов, поэтому вы всегда должны стремиться к тому, чтобы количество каталогов оставалось низким.

person Martin Wickman    schedule 15.01.2009
comment
Для чего нужны и «345», и «45»? Похоже, что в каждом из ваших каталогов первого уровня (например, «345») будет ровно один подкаталог (в данном случае «45»). - person Dustin Boswell; 05.11.2010

Я знаю, что нецелесообразно размещать все они в одном каталоге на сервере, поскольку это замедлит доступ к сканированию.

Это предположение.

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

http://www.databasesandlife.com/flat-directories/

person Adrian Smith    schedule 18.08.2010
comment
Спасибо, что поделился. OP упомянул PHP, и одна практическая проблема заключается в том, что доступ по FTP к каталогу с большим количеством файлов может истекать. - person James P.; 06.05.2011
comment
Я думаю, что важно сказать, как вы это делаете в своей статье в блоге, что некоторые файловые системы поддерживают очень большое количество файлов в одной папке. По моему опыту, некоторые (другие) файловые системы работают за пределами заявленных спецификаций для больших # файлов, но не все файловые операции будут работать. Если вы собираетесь хранить очень большое количество файлов в одной папке, сначала проверьте это! Тем не менее, почему бы просто не сбалансировать структуру папок в виде дерева с помощью какого-либо хеша? - person Steve Midgley; 10.11.2014

При сохранении файлов, связанных с идентификаторами auto_increment, я использую что-то вроде следующего, которое создает три уровня каталогов, каждый из которых состоит из 1000 каталогов и 100 файлов в каждом каталоге третьего уровня. Это поддерживает ~ 100 миллиардов файлов.

если $ id = 99532455444, то следующие возвращают / 995/324/554/44

function getFileDirectory($id) {
    $level1 = ($id / 100000000) % 100000000;
    $level2 = (($id - $level1 * 100000000) / 100000) % 100000;
    $level3 = (($id - ($level1 * 100000000) - ($level2 * 100000)) / 100) % 1000;
    $file   = $id - (($level1 * 100000000) + ($level2 * 100000) + ($level3 * 100));

    return '/' . sprintf("%03d", $level1)
         . '/' . sprintf("%03d", $level2)
         . '/' . sprintf("%03d", $level3)
         . '/' . $file;
}
person Isaac    schedule 28.07.2010

Посмотрите на файловую систему XFS. Он поддерживает неограниченное количество файлов, и Linux поддерживает это. http://oss.sgi.com/projects/xfs/papers/xfs_usenix/index.html

person EXTROMEDIA    schedule 10.12.2009

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

Пример

  1. 2009
  2. -01
  3. --01
  4. --02
  5. --03
  6. --31

таким образом у вас останется не более трех папок.

person Mike Geise    schedule 15.01.2009

В настоящее время я столкнулся с этой проблемой, и то, что написал Исаак, заинтересовало меня этой идеей. Моя функция немного отличается.

function _getFilePath($id) {
    $id = sprintf("%06d", $id);
    $level = array();
    for($lvl = 3; $lvl >= 1; $lvl--)
        $level[$lvl] = substr($id, (($lvl*2)-2), 2);
    return implode('/', array_reverse($level)).'.jpg';
}

Мои изображения исчисляются тысячами, поэтому у меня есть только этот предел до 999999, и поэтому он разделится на 99/99 / 99.jpg или 43524 на 04/35 / 24.jpg

person Mikhail    schedule 05.03.2011

Используйте иерархию файловой системы. Идентифицируйте свои изображения, используя что-то вроде 001/002/003 / 004.jpg, было бы очень полезно. Однако разделение - это совсем другая история. Может быть случайным, на основе содержимого, на основе даты создания и т. Д. На самом деле зависит от вашего приложения.

person PolyThinker    schedule 15.01.2009

Вы можете проверить стратегию, используемую Apple iPod для хранения мультимедийного контента. Есть папки на одном уровне глубины и файлы с заголовками одинаковой ширины. Я считаю, что ребята из Apple потратили много времени на тестирование своего решения, поэтому оно может принести вам мгновенную пользу.

person Boris Pavlović    schedule 15.01.2009
comment
Я не очень понимаю, что вы здесь имеете в виду. Вы можете привести пример? - person Rik Heywood; 15.01.2009

Если изображения, которые вы обрабатываете, являются цифровыми фотографиями, вы можете использовать данные EXIF ​​для их сортировки, например, по дате съемки.

person Keltia    schedule 15.01.2009

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

person Mats Fredriksson    schedule 15.01.2009
comment
ИМО, это плохой совет. 1. Вскоре ваша БД станет огромной, и это принесет другие проблемы. 2. С другой стороны, невозможно будет кэшировать изображения с помощью кеширующего прокси-сервера, такого как nginx или HAproxy, который очень быстро работает со статическим контентом. 3. DB станет бутылочным горлышком при довольно низкой нагрузке. - person Roman Podlinov; 30.04.2013