Как правильно использовать S3 хранилища, и на сколько моя идея верна?
Решил разобраться с S3 хранилищами. Выбрал MinIO, нашёл коннектор и пошёл читать гайды. Они или противоречат друг другу, или имеют комментарии из разряда "хватит учить людей плохому". Сейчас в голове "каша", поэтому хочу попросить проверить ниже описанную архитектуру на "хороший тон".
1 - В СУБД хранятся права доступа к файлам и пути к ним в MinIO. В MinIO хранятся только файлы (в их путях никакой информации не храниться).
Тут же возникает вопрос, стоит ли создавать какие либо ID для файлов, или их путей достаточно?
2 - Когда сайт загружается, клиентское приложение отправляет запрос к серверу. Сервер проверяет права доступа и возвращает временную ссылку на файл в MinIO. Клиентское приложение использует временную ссылку.
3 - Временные ссылки не кэшируются и не хранятся, так как переиспользование ссылок может привести к ситуации, когда пользователь получит ссылку за бесконечно малую до инвалидации и не сможет получить файл. Соответственно, на каждый запрос создаётся своя временная ссылка.
Также есть вопросы о масштабируемости. Например, следует ли мне создавать бакеты на регионы? Или свой MinIO сервер на регион? Какая практика будет лучшей (даже не из предложенных мной)?
Не надо верить людям, которые рассказывают сказки про "это не путь". В случае minio - это именно путь! Надо сразу иметь в голове тот механизм, который minio на самом деле использует для хранения данных. А minio хранит каждый бакет как каталог, в котором путь отражается в иерархии каталогов на файловой системе и конечный файл представляет из себя ещё один каталог, внутри которого два файла: json с метаданными и шифрованный блоб с содержимым.
Если в одном каталоге (в одном уровне иерархии) у minio будут миллионы записей, а сами данные хранятся на HDD (распространённая ситуация для хранения), то регулярно будут начинаться дикие тормоза на том, что операционная система будет вычитывать этот каталог с диска в память. И лучше не решать это установкой SSD, лучше решать это правильно, не создавая такую ситуацию с самого начала. Тем более что это совсем несложно. Достаточно раскладывать файлы по каталогам на основе даты, или диапазонов id, или хеша от имени (например, берём md5 и первые 2-3 символа - хеш), или по каким-то ещё логическим признакам в бизнес-логике.
(Это не какая-то глубоко теоретическая ситуация, мы реально столкнулись с проблемами из-за такой вот невнимательности, которые ещё и повлияли на другие приложения в том же кластере)
Что касается подхода к разворачиванию, нужно исходить из числа файлов, объёма файлов, числа запросов к ним, из необходимости геодоступности для отдельных пользователей, итд итп. Никаких универсальных ответов тут нет, без подробностей о предполагаемом профиле использования советовать нечего. В большинстве случаев вообще ничего особенно не нужно, может быть вполне достаточно одного инстанса.
С точки зрения minio два каталога в одном бакете и два бакета ничем не отличаются.
Пути к файлам в базе - да, лучше хранить именно так. Практика показывает, что в процессе жизненного цикла можно неоднократно изменить подход к организации хранения, и это будет наилучший способ обеспечить доступ к старым файлам без специальных усилий по их перекладыванию по новой. А новые файлы будут получать новый вид путей.
Временные ссылки - да, так их и используют часто. Сам minio их тоже не хранит, вся информация представлена в самой ссылке (время протухания и криптографическая подпись всего адреса). Поэтому можно хоть тысячу ссылок на один файл сделать - это никак не повредит производительности ни minio, ни вашего приложения.
Если делать проксирующий сервис (как тут в ответах посоветовали) - то да, так тоже делают - но рекомендую подойти к созданию такого аккуратно, тяп-ляп точно не надо. Иначе можно получить ситуацию, когда перед суперэффективным распределённым хранилищем наскоро написанный скрипт на php, который помрёт от сотни запросов или будет падать от любого чиха. Там может быть важно правильно обрабатывать partial content (поддерживать докачку) и всё такое. Между прочим, эффективность промышленных прокси-серверов (nginx, haproxy, envoy итд) по сравнению с наколенными поделками - это сильный аргумент в пользу того, чтобы свой проксирующий сервис не делать вообще. С другой стороны, откровенно показывать наружу, что фактически используется minio - это создавать риски целенаправленной атаки именно на minio. Ну, это вполне обычные риски, конечно, но их надо понимать.
Могу частично ответить по поводу путей. Многие понимают S3 как файловое хранилище, тогда как это объектное хранилище по сути, ключ-значение. Ключ - это то, что выглядит как путь, но на самом деле это не путь. И так совпало, что значение это обычно контейнер с содержимым, который представлен как файл. Поэтому путь и есть ID, и при этом значение нельзя поменять, его можно либо взять, либо положить. Делать какие-то дополнительные ID по этой причине обычно не надо, потому что ключ (за счет представления как путь) всегда является уникальным.