Объектное хранилище S3
Посчитал, чем оно отличается по деньгам. Возьмём одинаковый объём в 47,7 гигабайта. Если это 10 тысяч крупных файлов, то сто тысяч чтений стоят 40 рублей. Если тот же объём разложен на 10 миллионов мелких файлов и читается сто миллионов раз, те же 40 рублей превращаются в 40 тысяч. Объём хранения при этом одинаковый - 95 рублей.
Стержень: это не файловая система, а хранилище объектов с оплатой за операции; отсюда и другие правила проектирования, и другие ошибки.
// Формулировки: «чем объектное хранилище отличается от диска?», «как раздавать файлы клиентам?», «зачем правила жизненного цикла?»
Почему это не диск
Тут нет каталогов - только плоский набор объектов с ключами. Слэши в ключе рисуют иллюзию папок, но переименование «папки» означает перезапись всех объектов с новыми ключами. Нет и частичной записи: объект целиком заменяется новым, дописать в середину нельзя.
Зато есть то, чего нет у диска: доступ по сети из любого места, практически неограниченный объём, хранение копий в нескольких зонах из коробки и оплата ровно за то, что лежит. Плата - задержка: обращение к объекту это сетевой запрос, десятки миллисекунд вместо микросекунд.
// Отсюда главное правило проектирования: сюда кладут то, что пишется целиком и читается целиком. Картинки, документы, резервные копии, выгрузки, логи. Не кладут: файлы баз данных, то, что правится по кусочкам, и то, к чему нужен доступ за микросекунды. Попытка примонтировать объектное хранилище как обычный диск работает, но каждый вызов файловой системы превращается в сетевой запрос со всеми последствиями.
- объект
- цельная единица хранения с ключом; частично не правится
- плоское пространство ключей
- каталогов нет, слэши в имени - только видимость
Доступ: не раздавайте всё публично
Простейший способ отдать файл клиенту - сделать хранилище публичным. Он же самый частый источник утечек: открытые наружу хранилища находят сканеры, и в них регулярно обнаруживаются чужие документы и резервные копии.
Правильный способ - ссылка с подписью и сроком: приложение генерирует ссылку, которая работает, скажем, пятнадцать минут и только на этот объект. Хранилище при этом закрыто, а раздача идёт напрямую от него, мимо вашего приложения - значит, вы не тратите на это ни трафик приложения, ни его потоки.
// Загрузку от пользователя делают тем же приёмом наоборот: приложение выдаёт подписанную ссылку на запись, и браузер грузит файл прямо в хранилище. Иначе весь пользовательский поток идёт через ваши серверы. И отдельно про доступ сервисов: им выдают не общий ключ, а роль с правами на конкретный набор объектов, потому что общий ключ живёт вечно и утекает вместе с любым логом.
- подписанная ссылка
- временный доступ к одному объекту без открытия всего хранилища
- прямая загрузка
- браузер грузит файл в хранилище, минуя ваши серверы
Классы хранения и жизненный цикл
У объекта есть класс хранения, и цена между классами отличается в разы. Посчитал на пяти терабайтах логов: держать всё в горячем классе - 10 тысяч рублей в месяц; всё в холодном - 3,5 тысячи; всё в архивном - тысяча.
Но держать всё в архиве нельзя: у холодных классов есть минимальный срок хранения и плата за извлечение, а у архивного - ещё и время подготовки: минуты в лучшем случае, часы в худшем. Поэтому применяют правило жизненного цикла: тридцать дней горячо, потом девяносто холодно, дальше архив, а через год удалить. По моему расчёту это даёт 2650 рублей вместо 10 тысяч - экономия 74% на одной настройке.
// Две вещи, которые обязательно включают рядом. Хранение прошлых версий объекта: без него перезапись необратима, а удаление тем более. И блокировка удаления для резервных копий - тогда даже тот, кто получил доступ, не сможет стереть архив раньше срока. Правило жизненного цикла при этом надо писать аккуратно: оно применяется само, и ошибка в фильтре молча удалит не то.
- класс хранения
- горячий, холодный, архивный; цена отличается в разы
- правило жизненного цикла
- автоматический перевод объектов между классами и удаление по возрасту
- плата за извлечение
- у холодных классов чтение стоит отдельно и бывает небыстрым
Как отвечать: «Как правильно раздавать пользовательские файлы через объектное хранилище?»
Хранилище держу закрытым, а клиенту выдаю подписанную ссылку с коротким сроком - скажем, пятнадцать минут и только на конкретный объект. Тогда файл едет напрямую из хранилища, минуя мои серверы: я не трачу ни трафик приложения, ни его потоки. Загрузку делаю зеркально: приложение выдаёт подписанную ссылку на запись, и браузер грузит файл прямо в хранилище. Публичное хранилище не использую вообще - именно так регулярно утекают чужие документы и резервные копии. Сервисам выдаю не общий ключ, а роль с правами на нужный набор объектов, потому что общий ключ живёт вечно и утекает вместе с логами. И сразу настраиваю жизненный цикл: я считал на пяти терабайтах логов, что перевод в холодный и архивный классы по возрасту даёт экономию около 74% против хранения всего в горячем.
Ответ закрывает и безопасность, и нагрузку на приложение, и деньги. Подписанные ссылки в обе стороны - признак того, что человек это делал.
На чём валятся
- −Открывают хранилище публично ради простоты раздачи.
- −Гонят все загрузки и скачивания через своё приложение и упираются в его потоки.
- −Кладут в объектное хранилище то, что правится по кусочкам.
- −Считают только объём и не считают операции: миллионы мелких файлов стоят в разы дороже.
- −Не включают хранение прошлых версий: перезапись объекта необратима.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 7, остальные разбираются в тренажёре.
- Приложение отдаёт пользовательские файлы, проксируя их через себя из бакета. Как сделать лучше?A)Кэшировать файлы на диске приложения после первой отдачиB)Отдавать подписанную ссылку с коротким срокомC)Открыть бакет на публичное чтение и раздавать прямые ссылкиD)Поднять реплику бакета рядом с приложением и читать из неё
показать ответ и разбор
+B)Отдавать подписанную ссылку с коротким сроком// разбор: Проксирование через приложение занимает его потоки и полосу ради работы, которую хранилище делает лучше. Подписанная ссылка с коротким сроком даёт клиенту прямой доступ к конкретному объекту, оставляя проверку прав на стороне приложения. Сверху обычно ставят CDN: тогда популярные файлы отдаются с ближайшей точки, а расходы на исходящий трафик из хранилища падают.
- Бакет с логами растёт и стоит всё дороже. Что настраивают в первую очередь?A)Сжатие на стороне хранилища для всех объектовB)Ограничение на размер бакета, чтобы запись остановиласьC)Перенос старых логов в другой бакет ночным скриптомD)Политика жизненного цикла: класс и удаление
показать ответ и разбор
+D)Политика жизненного цикла: класс и удаление// разбор: Политика жизненного цикла — штатный механизм: объекты старше месяца уезжают в более дешёвый класс хранения, старше года удаляются, недоделанные многочастевые загрузки чистятся автоматически. Это дешевле и надёжнее скриптов. Помнить надо про две вещи: у холодных классов есть минимальный срок хранения и плата за извлечение, а при включённом версионировании удаление создаёт маркер и старые версии тоже надо чистить правилом.
- Объектное хранилище декларирует «11 девяток» надёжности. Значит ли это, что бэкап данных в нём не нужен?A)Да: при такой надёжности данные защищены от всегоB)Да, если включить репликацию в другой регионC)Нет, потому что объектное хранилище часто недоступноD)Нет: девятки про железо, не про ошибочное удаление
показать ответ и разбор
+D)Нет: девятки про железо, не про ошибочное удаление// разбор: «11 девяток» durability означают крайне низкую вероятность потери объекта из-за отказа железа (данные реплицируются внутри хранилища). Но это не защита от логических бед: ошибочное удаление, перезапись, баг в коде, скомпрометированный ключ сотрут/испортят объект, и репликация растиражирует это. Защищаются версионированием (хранить прежние версии), MFA-delete, политиками и отдельными неизменяемыми копиями. Durability и «бэкап от своих ошибок» — разные вещи.
- В бакет с приватными данными пользователей случайно открыли публичный доступ. Как правильно не допускать такого?A)Полагаться на сложное имя бакета, его не угадаютB)Оставить публичный доступ, но зашифровать объектыC)Block Public Access + подписанные ссылкиD)Раздать всем один общий ключ доступа к бакету
показать ответ и разбор
+C)Block Public Access + подписанные ссылки// разбор: Публично открытый бакет — классическая утечка. Правильно: включить Block Public Access (запрет публичного доступа на уровне аккаунта и бакета, чтобы случайная политика его не открыла), а нужные файлы отдавать точечно — подписанными ссылками с коротким сроком или через CDN с контролем доступа. Шифрование at-rest от публичного скачивания не защищает (сервис отдаёт расшифрованное), а секретность имени и общий ключ — не контроль доступа.
- Нужно заливать в объектное хранилище очень большие файлы и держать высокую пропускную. Что для этого используют?A)Одним PUT целиком, просто с большим таймаутомB)Multipart-загрузку: файл частями параллельно, с докачкой упавшихC)Сжать файл на клиенте, чтобы влез в один запросD)Разбить файл на отдельные объекты с разными именами
показать ответ и разбор
+B)Multipart-загрузку: файл частями параллельно, с докачкой упавших// разбор: Большие объекты заливают multipart upload: файл режут на части и грузят их параллельно, каждую можно повторить при обрыве, а в конце хранилище собирает объект целиком. Это даёт и скорость (параллелизм насыщает канал), и устойчивость (упавшую часть докачивают, а не весь файл заново). Для высокой частоты запросов дополнительно продумывают распределение ключей/префиксов, чтобы нагрузка не била в один «горячий» префикс.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.