Хранение миллиона изображений в файловой системе
У меня есть проект, который будет генерировать огромное количество изображений. Около 1 000 000 для начала. Они не являются большими изображениями, поэтому при запуске я буду хранить их все на одной машине.
Как вы рекомендуете хранить эти изображения эффективно? (Файловая система NTFS в настоящее время)
Я рассматриваю схему именования... для начала все изображения будут иметь инкрементное имя от 1 до. Я надеюсь, что это поможет мне отсортировать их позже, если потребуется, и выбросить их в разные папки.
что будет лучше схема именования:
a / b / c / 0... z / z / z / 999
или же
A / B / C / 000... Z / Z / Z / 999
есть идеи по этому поводу?
24 ответа
Я бы рекомендовал использовать обычную файловую систему вместо баз данных. Использовать файловую систему проще, чем базу данных, вы можете использовать обычные инструменты для доступа к файлам, файловые системы предназначены для такого рода использования и т. Д. NTFS должна прекрасно работать как система хранения.
Не храните фактический путь к базе данных. Лучше сохранить порядковый номер изображения в базе данных и иметь функцию, которая может генерировать путь из порядкового номера. например:
File path = generatePathFromSequenceNumber(sequenceNumber);
Проще справиться, если вам нужно как-то изменить структуру каталогов. Может быть, вам нужно переместить изображения в другое место, может быть, вам не хватает места и вы начинаете хранить некоторые изображения на диске A, а некоторые на диске B и т. Д. Изменить одну функцию проще, чем изменить пути в базе данных.,
Я бы использовал этот вид алгоритма для генерации структуры каталогов:
- Сначала добавьте порядковый номер с начальными нулями, пока у вас не будет как минимум 12-значной строки. Это имя для вашего файла. Вы можете добавить суффикс:
12345
->000000012345.jpg
- Затем разбейте строку на 2 или 3 символьных блока, где каждый блок обозначает уровень каталога. Иметь фиксированное количество уровней каталогов (например, 3):
000000012345
->000/000/012
- Сохраните файл в сгенерированном каталоге:
- Таким образом, полный путь и имя файла для файла с идентификатором последовательности
123
является000/000/012/00000000012345.jpg
- Для файла с идентификатором последовательности
12345678901234
путь будет123/456/789/12345678901234.jpg
- Таким образом, полный путь и имя файла для файла с идентификатором последовательности
Некоторые вещи, которые следует учитывать относительно структуры каталогов и хранения файлов:
- Вышеприведенный алгоритм дает вам систему, в которой каждый конечный каталог имеет максимум 1000 файлов (если у вас меньше 1 000 000 000 000 файлов)
- Может быть ограничение на количество файлов и подкаталогов, которые может содержать каталог, например, файловая система ext3 в Linux имеет ограничение в 31998 подкаталогов на один каталог.
- Обычные инструменты (WinZip, Windows Explorer, командная строка, оболочка bash и т. Д.) Могут работать не очень хорошо, если у вас есть большое количество файлов в каталоге (> 1000)
- Структура каталогов сама по себе займет некоторое дисковое пространство, поэтому вам не нужно слишком много каталогов.
- С приведенной выше структурой вы всегда можете найти правильный путь к файлу изображения, просто взглянув на имя файла, если вам случится испортить структуру каталогов.
- Если вам нужен доступ к файлам с нескольких компьютеров, рассмотрите возможность совместного использования файлов через сетевую файловую систему.
- Приведенная выше структура каталогов не будет работать, если вы удалите много файлов. Это оставляет "дыры" в структуре каталогов. Но так как вы не удаляете файлы, все должно быть в порядке.
Я собираюсь поставить свои 2 цента на один отрицательный совет: не ходите с базой данных.
Я работаю с базами данных для хранения изображений в течение многих лет: большие (1 мегабайта) файлы, часто изменяемые, несколько версий файла, доступ к которым осуществляется достаточно часто. Проблемы с базой данных, с которыми вы сталкиваетесь при хранении больших файлов, чрезвычайно утомительны, проблемы с записью и транзакциями запутаны, и вы сталкиваетесь с проблемами блокировки, которые могут привести к серьезным авариям поездов. У меня больше практики написания сценариев dbcc и восстановления таблиц из резервных копий, чем когда-либо должен был делать любой нормальный человек.
Большинство новых систем, с которыми я работал, перенесли хранилище файлов в файловую систему и полагались на базы данных только для индексации. Файловые системы спроектированы таким образом, чтобы справляться с подобными злоупотреблениями, их гораздо проще расширять, и вы редко теряете всю файловую систему, если одна запись повреждена.
Я думаю, что большинство сайтов, которые имеют дело с этим, используют какой-то хэш, чтобы обеспечить равномерное распределение файлов в папках.
Скажем, у вас есть хеш файла, который выглядит примерно так 515d7eab9c29349e0cde90381ee8f810
Вы можете сохранить это в следующем месте, и вы можете использовать сколько угодно глубоких уровней, чтобы количество файлов в каждой папке было низким.\51\5d\7e\ab\9c\29\349e0cde90381ee8f810.jpg
Я видел этот подход, принятый много раз. Вам по-прежнему нужна база данных для сопоставления этих файловых хэшей с понятным для человека именем и другими метаданными, которые вам нужно сохранить. Но этот подход довольно хорошо масштабируется, поскольку вы можете начать распределять адресное пространство хеш-функции между несколькими компьютерами и / или пулами хранения и т. Д.
В идеале вам следует запустить некоторые тесты на время произвольного доступа для различных структур, поскольку ваши конкретные настройки жесткого диска, кэширование, доступная память и т. Д. Могут изменить эти результаты.
Предполагая, что у вас есть контроль над именами файлов, я бы разделил их на уровне 1000 с на каталог. Чем больше уровней каталогов вы добавляете, тем больше инодов вы записываете, так что здесь есть push-pull.
Например,
/ Корень /[0-99]/[0-99]/ имя_файла
Обратите внимание, что http://technet.microsoft.com/en-us/library/cc781134(WS.10).aspx содержит более подробную информацию о настройке NTFS. В частности: "Если вы используете большое количество файлов в папке NTFS (300 000 или более), отключите генерацию коротких имен файлов для повышения производительности, особенно если первые шесть символов длинных имен файлов похожи".
Вам также следует обратить внимание на отключение ненужных функций файловой системы (например, время последнего доступа). http://www.pctools.com/guides/registry/detail/50/
Что бы вы ни делали, не храните их все в одном каталоге.
В зависимости от распределения имен этих изображений вы можете создать структуру каталогов, в которой у вас будут однобуквенные папки верхнего уровня, где у вас будет другой набор подпапок для 2-й буквы изображений и т. Д.
Так:
скоросшиватель img\a\b\c\d\e\f\g\
будет содержать изображения, начинающиеся с 'abcdefg' и так далее.
Вы можете ввести свою собственную необходимую глубину.
Отличительной особенностью этого решения является то, что структура каталогов эффективно действует как хэш-таблица / словарь. По имени файла изображения вы будете знать его каталог, а по каталогу вы узнаете подмножество изображений, которые туда попадают.
У нас есть система фотомагазинов с 4 миллионами изображений. Мы используем базу данных только для метаданных, и все изображения хранятся в файловой системе с использованием системы с обратными именами, где имена папок генерируются из последней цифры файла, last-1 и т. Д. Например: 000001234.jpg хранится в структуре каталогов, например 4\3\2\1\000001234.jpg.
Эта схема очень хорошо работает с индексом идентичности в базе данных, потому что она равномерно заполняет всю структуру каталогов.
Новый MS SQL 2008 имеет новую функцию для обработки таких случаев, она называется FILESTREAM. Взглянуть:
Я бы сохранил их в файловой системе, но это зависит от того, насколько быстро будет расти количество файлов. Эти файлы размещены в Интернете? Сколько пользователей будет иметь доступ к этим файлам? На эти вопросы нужно ответить, прежде чем я смогу дать вам лучшую рекомендацию. Я бы также посмотрел на Haystack из Facebook, у них есть очень хорошее решение для хранения и обработки изображений.
Также, если вы выберете файловую систему, вам нужно будет разделить эти файлы по каталогам. Я смотрел на эту проблему и предложил решение, но оно ни в коем случае не идеальное. Я делю по хеш-таблице и пользователям, вы можете прочитать больше на моем блоге.
Ваши изображения должны быть названы уникально? Может ли процесс, который генерирует эти изображения, создавать одно и то же имя файла более одного раза? Трудно сказать, не зная, какое устройство создает имя файла, но сказать, что устройство "перезагружено", и после перезапуска оно начинает называть изображения так же, как в прошлый раз, когда оно "сбрасывалось" - если это такая проблема.
Кроме того, вы говорите, что вы получите 1 миллион изображений за месяц. Как насчет этого? Как быстро эти изображения будут продолжать заполнять файловую систему? Будут ли они завершаться в какой-то момент и выровняться примерно на 1 млн. ОБЩИХ изображений или оно будет расти и расти месяц за месяцем?
Я спрашиваю, потому что вы можете начать проектирование вашей файловой системы по месяцам, а затем по имиджу. Я мог бы предложить вам сохранить изображения в такой структуре каталогов:
imgs\yyyy\mm\filename.ext
where: yyyy = 4 digit year
mm = 2 digit month
example: D:\imgs\2009\12\aaa0001.jpg
D:\imgs\2009\12\aaa0002.jpg
D:\imgs\2009\12\aaa0003.jpg
D:\imgs\2009\12\aaa0004.jpg
|
D:\imgs\2009\12\zzz9982.jpg
D:\imgs\2010\01\aaa0001.jpg (this is why I ask about uniqueness)
D:\imgs\2010\01\aab0001.jpg
Месяц, год, даже день хорош для изображений типа безопасности. Не уверен, что это то, что вы делаете, но я сделал это с домашней камерой безопасности, которая делала снимки каждые 10 секунд... Таким образом, ваше приложение может переходить к определенному времени или даже диапазону, в котором вы можете подумать, что изображение было сгенерировано., Или вместо года, месяца - есть ли какое-то другое "значение", которое может быть получено из самого файла изображения? Некоторые другие дескрипторы, кроме примера даты, который я дал?
Я бы не стал хранить двоичные данные в БД. Никогда не было хорошей производительности / удачи с такими вещами. Не могу себе представить, что это хорошо работает с 1 миллионом изображений. Я бы сохранил имя файла и все. Если они все будут JPG, тогда даже не храните расширение. Я хотел бы создать контрольную таблицу, в которой хранится указатель на сервер файла, диск, путь и т. Д. Таким образом, вы можете переместить эти изображения в другое поле и по-прежнему находить их. Вам нужно пометить тегами ваши изображения? Если это так, то вы захотите построить соответствующие таблицы, которые позволяют такого рода маркировки.
Возможно, вы / другие обсуждали эти идеи, когда я отвечал. Надеюсь, это поможет.
Быстрый момент: вам не нужно хранить путь к файлу в вашей БД. Вы можете просто сохранить числовое значение, если ваши файлы названы так, как вы описываете. Затем, используя одну из четко определенных схем хранения, которые уже обсуждались, вы можете получить индекс в виде числа и очень быстро найти файл, пройдя через структуру каталогов.
Хотя я не обслуживал изображения в таком масштабе, ранее я написал небольшое приложение для галереи, обслуживающее ~25 тыс. Изображений на машине с частотой 400 МГц. 512 МБ ОЗУ или около того. Некоторые переживания;
Избегайте реляционных баз данных любой ценой; В то время как базы данных, без сомнения, умны в обработке данных, они не предназначены для такого использования (у нас есть специализированные, иерархические базы данных значения ключа для так называемых файловых систем). Хотя у меня нет ничего, кроме догадки, я бы поспорил, что кеш БД уходит в окно, если вы кидаете в него действительно большие капли. В то время как моё доступное оборудование было в самом начале, полное отсутствие обращения к БД при поиске изображения дало скорость на порядок выше.
Исследуйте, как ведет себя файловая система; в ext3 (или это был ext2 в то время - не помню) предел способности эффективно искать подкаталоги и файлы был около отметки 256; таким образом, имея только столько файлов и папок в любой данной папке. Опять заметное ускорение. Хотя я не знаю о NTFS, такие вещи, как XFS (которая, насколько я помню, использует B-деревья), чрезвычайно быстры, просто потому, что они могут выполнять поиск очень быстро.
Распределяйте данные равномерно; когда я экспериментировал с вышеизложенным, я пытался распределить данные равномерно по всем каталогам (я сделал MD5 URL-адреса и использовал его для каталогов;
/1a/2b/1a2b...f.jpg
). Таким образом, требуется больше времени, чтобы достичь любого ограничения производительности (и кэш файловой системы в любом случае становится пустым при таких больших наборах данных). (наоборот, вы можете захотеть увидеть, где находятся ограничения в начале; затем вы хотите выбросить все в первый доступный каталог.
Я участвую в проекте, который хранит 8,4 миллиона изображений в течение года для документирования состояния различных устройств. К более поздним изображениям обращаются чаще, а к более старым изображениям редко обращаются, если не было обнаружено условие, побуждающее кого-то копать архивы.
Мое решение, основанное на этом использовании, заключалось в постепенном сжатии изображений в сжатые файлы. Изображения представляют собой файлы JPG, каждый размером около 20 КБ и не сжимают сильно, поэтому схема сжатия ZIP отсутствует. Это делается просто для объединения их в одну запись файловой системы, что значительно помогает NTFS с точки зрения скорости, когда речь идет о перемещении их с диска на диск или просмотре списка файлов.
Изображения старше суток объединяются в "ежедневный" почтовый индекс; молнии старше месяца объединяются в соответствующие "месячные" молнии; и, наконец, ничего больше года больше не нужно и, следовательно, удаляется.
Эта система работает хорошо, потому что пользователи могут просматривать файлы (либо через операционную систему, либо через ряд клиентских приложений), а все имена называются на основе имен устройств и временных меток. Обычно пользователь знает эти две части информации и может быстро найти любое из миллионов изображений.
Я понимаю, что это, вероятно, не связано с вашими конкретными деталями, но я думал, что поделюсь.
Я был бы склонен создать структуру папок на основе даты, например, \ year \ month \ day, и использовать временные метки для имен файлов. При необходимости временные метки могут иметь дополнительный компонент счетчика, если изображения должны создаваться так быстро, что их может быть больше одного в течение миллисекунды. Благодаря использованию наиболее значимой или наименее значимой последовательности для сортировки имен поиск и обслуживание становятся проще простого. например, hhmmssmm[seq].jpg
Может быть, опоздал на игру по этому вопросу. Но одним из решений (если оно соответствует вашему варианту использования) может быть хеширование имени файла. Это способ создать легко воспроизводимый путь к файлу, используя имя файла, а также создать хорошо распределенную структуру каталогов. Например, вы можете использовать байты хэш-кода имени файла в качестве пути:
String fileName = "cat.gif";
int hash = fileName.hashCode();
int mask = 255;
int firstDir = hash & mask;
int secondDir = (hash >> 8) & mask;
Это приведет к тому, что путь будет:
/172/029/cat.gif
Вы можете найти cat.gif
в структуре каталогов путем воспроизведения алгоритма.
Использование HEX в качестве имен каталогов будет так же просто, как преобразование int
ценности:
String path = new StringBuilder(File.separator)
.append(String.format("%02x", firstDir))
.append(File.separator)
.append(String.format("%02x", secondDir)
.toString();
В результате чего:
/AC/1D/cat.gif
Я написал статью об этом несколько лет назад и недавно переместил ее в Medium. В нем есть еще несколько деталей и пример кода: Хеширование имени файла: Создание хешированной структуры каталогов. Надеюсь это поможет!
Вы рассматриваете возможность аварийного восстановления?
Некоторые из предложенных здесь решений приводят к искажению имени файла (например, если физический файл был перемещен, вы потеряете информацию о том, какой это файл на самом деле). Я рекомендую сохранить уникальное физическое имя файла, чтобы, если ваш основной список расположений файлов был поврежден, вы могли восстановить его с помощью небольшой оболочки, например, powershell, script;)
Из того, что я прочитал здесь, звучит так, как будто все эти файлы будут храниться в одной файловой системе. Рассмотрите возможность их хранения в нескольких файловых системах на нескольких машинах. Если у вас есть ресурсы, определите систему хранения каждого файла на двух разных компьютерах на случай, если вы потеряете источник питания, и замена займет 2 дня.
Подумайте, какие процедуры вам необходимо создать для переноса файлов между компьютерами или файловыми системами. Возможность сделать это с вашей системой в режиме реального времени и онлайн может сэкономить вам значительную головную боль в будущем.
Вы можете рассмотреть возможность использования GUID в качестве физического имени файла вместо инкрементного числа, если ваш счетчик инкрементных чисел (столбец идентификатора базы данных?) Испортился.
При необходимости рассмотрите возможность использования CDN, например Amazon S3.
Возможно, схема именования, основанная на дате создания - либо включающая всю информацию в имени файла, либо (лучше для просмотра позже), разделив ее по каталогам. Я могу думать о следующем, в зависимости от того, как часто вы генерируете изображения:
- Несколько изображений генерируются каждый день:
Year/Month/Day/Hour_Minute_Second.png
- Пара в месяц:
Year/Month/Day_Hour_Minute_Second.png
и т.д. Вы понимаете мою точку зрения... =)
Если они ВСЕ не требуются немедленно, и вы можете генерировать их на лету, и это небольшие изображения, почему бы не реализовать кэш-память LRU или дисковый кэш над генератором изображений?
Это может спасти вас от хранения и сохранить горячие изображения, которые будут поданы из памяти?
Если вы находитесь в Windows, как насчет exfat файловой системы
http://msdn.microsoft.com/en-us/library/aa914353.aspx
это было разработано с хранением медиа-файлов и доступно сейчас.
Я вижу другие упоминания о базе данных, но не вижу упоминаний об этом в вашем посте. В любом случае, мое мнение по этому конкретному вопросу таково: либо придерживайтесь базы данных, либо файловой системы. Если вам нужно смешать два, будьте осторожны с этим. Все становится сложнее. Но вам, возможно, придется. Хранение миллиона фотографий в базе данных не самая лучшая идея.
Вас может заинтересовать следующая спецификация, большинство цифровых камер следуют ей для управления хранением файлов: https://en.wikipedia.org/wiki/Camera_Image_File_Format
По сути, создается папка, такая как 000OLYMPUS
и фотографии добавляются в эту папку (например, DSC0000.RAW
). Когда счетчик имени файла достигает DSC9999.RAW
новая папка создана (001OLYMPUS
) и изображение добавляются снова, сбрасывая счетчик, возможно, с другим префиксом (например: P_0000.RAW
).
В качестве альтернативы вы также можете создавать папки на основе частей имени файла (уже упоминалось несколько раз). Например, если ваша фотография называется IMG_A83743.JPG
хранить в IMG_\A8\3\IMG_A83743.JPG
, Его сложнее реализовать, но он облегчит поиск ваших файлов.
В зависимости от файловой системы (это потребует некоторых исследований), вы можете просто сбросить все изображения в одну папку, но, по моему опыту, это обычно вызывает проблемы с производительностью.
Я просто запустил тест на zfs, потому что я люблю zfs, и у меня был раздел на 500 гигабайт, на котором у меня было сжатие. Я написал скрипт, который генерировал файлы размером 50-100 тыс. И помещал их во вложенные каталоги 1/2/3/4/5/6/7/8 (5-8 уровней в глубину) и позволил ему работать, я думаю, 1 неделю. (это был не очень хороший сценарий.) Он заполнил диск и в итоге получил около 25 миллионов файлов или около того. Доступ к любому файлу с известным путем был мгновенным. Перечисление любого каталога с известным путем было мгновенным.
Однако подсчет списка файлов (через find) занял 68 часов.
Я также провел тест, поместив множество файлов в один каталог. Я получил до 3,7 миллионов файлов в одном каталоге, прежде чем я остановился. Перечисление каталога для подсчета заняло около 5 минут. Удаление всех файлов в этом каталоге заняло 20 часов. Но поиск и доступ к любому файлу был мгновенным.
Чистый способ создать путь из большого числа - легко преобразовать его в гекс, а затем разделить!
например 1099496034834
> 0xFFFF1212
> FF/FF/12/12
public string GeneratePath(long val)
{
string hex = val.ToString("X");
hex=hex.PadLeft(10, '0');
string path="";
for(int i=0; i<hex.Length; i+=2 )
{
path += hex.Substring(i,2);
if(i+2<hex.Length)
path+="/";
}
return path;
}
Хранить и загружать:
public long Store(Stream doc)
{
var newId = getNewId();
var fullpath = GeneratePath(newId)
// store into fullpath
return newId;
}
public Stream Load(long id)
{
var fullpath = GeneratePath(newId)
var stream = ...
return stream;
}
Полные исходные коды: https://github.com/acrobit/AcroFS
Возможно, вы захотите взглянуть на ZFS (файловая система, менеджер томов от Sun). С уважением,
К сожалению, файловые системы очень плохи (производительность с большим количеством файлов в каждом каталоге или глубоких деревьях каталогов, проверка времени при перезапуске, надежность) при управлении большим количеством маленьких файлов, поэтому приведенное выше решение с использованием ZIP-файлов является лучшим, если вы хотите использовать файловую систему.
Использование менеджера баз данных, безусловно, лучший вариант; простой, например, BDB или GDBM; даже родственная СУБД, такая как MySQL, будет лучше. Только ленивые люди, которые не понимают файловые системы и базы данных (например, те, кто отклоняет транзакции), склонны использовать файловые системы в качестве баз данных (или, реже, наоборот).
Как насчет базы данных с таблицей, содержащей идентификатор и большой двоичный объект для хранения изображения? Затем вы можете добавлять новые таблицы, когда хотите связать больше элементов данных с фотографией.
Если вы ожидаете масштабирования, почему бы не масштабировать сейчас? Вы сэкономите время как сейчас, так и позже IMO. Реализуйте слой базы данных один раз, с чего довольно легко начать. Или реализуйте что-то с помощью папок и имен файлов и бла-бла-бла, а затем переключитесь на что-то другое, когда вы начнете взрывать MAX_PATH.