@nkmr

Как лучше хранить много изображений для веб-приложения?

Приветствую!
Столкнулся с новой для себя задачей, и показалось, что правильным будет не только поискать способы решения в открытом доступе, но и обратиться за советом к кому-то с опытом в решении подобного вопроса.

Есть веб-приложение (веб-интерфейс + API), в качестве СУБД используется Postgres.
Пользователи в частности загружают на сервер изображения, после этого их просматривают/скачивают, также относительно редко само приложение использует эти изображения для ряда операций (без изменения).
Пусть условно со стороны пользователей это будет 1000-2000 запросов на отправку изображений ежедневно и 3000-5000 на получение, размер 1 изображения в среднем 4-5Мб. Предположим с оптимизмом, что объём информации со временем будет расти.

Очень важно хранить все изображения в исходном качестве, не терять их, а также иметь возможность разграничивать к ним доступ среди пользователей приложения. Чуть менее важно уметь отдавать изображения пользователю за разумное время.
Изначально пользователей было немного, наплыва данных не было, и без каких-либо проблем изображения хранились в БД в отдельной таблице в колонке с типом bytea.

На данный момент объём изображений приближается к 1Тб и стремительно растёт, при этом занимают они >90% хранимой информации.
Встаёт вопрос о том, как лучше, и надо ли, реорганизовать хранение изображений. Хочется минимизировать проблемы при работе с БД (процесс создания бекапов и производительность в целом), и потенциальные замедления в доставке изображений до пользователей. И главное, желательно, забыть на долгое время об описанной проблеме :)

До этого не сталкивался с задачами такого рода, поэтому достаточно слабо представляю варианты выбора и их последствия в долгосрочной перспективе.
Имеет ли смысл пытаться дальше расширять дисковое пространство и далее хранить изображения в базе?
Сразу перевозить изображения в облачное объектное хранилище? Позволяет ли оно решить вопрос разграничения доступа на уровне пользователей приложения так, чтобы само приложение не ходило грузить данные с облака?
Либо же какой вариант может быть ещё лучше? :)
  • Вопрос задан
  • 2024 просмотра
Решения вопроса 2
@Drno
в БД обычно хранится "ссылка" \ хеш на файл, а сам файл может хранится либо просто на диске в системе, либо на подключенном S3 к примеру, это уже как по деньгам \ удобству итд...
Ответ написан
ThunderCat
@ThunderCat Куратор тега Веб-разработка
{PHP, MySql, HTML, JS, CSS} developer
Хранение файлов в бд - самый хреновый вариант из имеющихся. По многим причинам, но основная - файлы должны лежать в файловой системе. Это их естественное состояние. Это быстро, не затратно, не потребляет лишнюю память/процессор и просто удобно. В зависимости от необходимости давать к ним доступ всем или по авторизации, будет либо работа напрямую с статикой через какой-нить нжинкс, либо программно сформированный поток байт через что-то типа пхпшного readfile...

В зависимости от возможностей хостинга, файлы хранят либо локально(в случае например собственного выделенного сервера и наличия райд стойки), либо, как уже написали, в облачных хранилищах, что чаще всего достаточно выгодно в плане денег за объем/трафик, плюс расширение хранилища будет просто отражаться на счете за услуги, а не ложиться ответственностью на вас как владельца сгоревших винтов с данными клиента. АПИ у всех весьма несложные, а драйвера для работы с удаленными файлохранилищами есть практически для всех популярных движков в виде готовых пакетов.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
@rPman
Веб приложения максимально оптимизированы при работе с файлами на диске.
Никакой другой метод не позволит дать такую производительность.

Поэтому - авторизацию доступа делай на уровне веб сервера (вот пример с нормальным oauth)

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

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

Тупой пример - числовой идентификатор переводи в hex, дели на группы по 4 символа и создавай соответствующие каталоги: /images/0d4f/3b00/a841/0d88, тут 0d88 это файл, остальные части - каталоги. Идентификатор соответственно 64-битное число 0x0d4f3b00a8410d88

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

p.s. хранить большие бинарные блобы в базе данных можно только при очень большой нужде в транзакциях, и это очень дорого и по памяти и по процессору.
Ответ написан
nokimaro
@nokimaro
Меня невозможно остановить, если я смогу начать.
Чтобы забыть о проблеме на долго конечно лучший выбор отдельное объектное хранилище. Не обязательно это должно быть облачное решение, можно организовать self-hosted S3-совместимое решение с использованием https://min.io/. Это позволит использовать любую готовую библиотеку s3-клиента для работы с файлами (upload/download/delete)

Плюсы - при правильной настройке размер хранилища можно бесконечно расширять и масштабировать/реплицировать.

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

Другой вариант это проксировать все запросы на файлы через приложение: пользователь запросил файл -> бэкенд проверил права доступа -> бэкенд обратился к s3 хранилищу чтобы получить файл -> бэкенд передал файл пользвоателю. Это примерно как было у вас с хранением файлов в базе, пользователь не может напрямую скачать файл из базы, а это за него делает ваше бэкенд приложение.
Ответ написан
Комментировать
@psiklop
Много слов, а задача тривиальная. Файлы на сервере хранят как дома. Представь тебе надо хранить фото. Распихал по папкам с названиями и тип-топ. Мало места - надо докупить или удалить лишнее. Надо бэкап значит надо. Это все элементарная логика и больше ничего. Все остальное как ее написать кодом.
Ответ написан
@denizkino_mesto
Все комментаторы выше далеки от реальности, хочешь в базе, хочешь в папках на дисковой подсистеме, хочешь в матрицах любых размерностей в оперативной памяти храни, как больше нравится и удобнее тебе. Производительность всей хурмы зависит только от реализации её, храниш на диске, складывай по папкам, которые будут служить разделами(индексами) расположения нужного файла с привязкой к чему-то удобному тебе, что быстро и без заморочек ты всегда понимал, как обратится к нужным данным, хранишь в базе, используй таблицу связей, храня в ней разделы, либо используй разделы прям в основной одной таблице, при выборке всегда добавляй связь с разделами для минимизации результатов выборки, используй при поиске ограничения топ, оффсет и прочую хурму, тоже и в оперативке. Файлы на дисковой подсистеме это та же база данных, только на уровне операционной системы и ее приложений, та же индексация, разбивка, долгий поиск и обращения к нужным данным при отсутствии структурированных индексов, для быстрого поиска рекомендую маркировать файлы самостоятельно тегами по которым можно их искать, как пример изображение с цветком, теги цвет, красный цветок, роза, ваза, цветок в вазе, лето, маша, ну суть думаю ясна. Файл dota2.exe теги игруха, дота, pvp, игры, игры на пк, компьютерные игры и т.д.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы