Перейти к основному содержимому

Как работает загрузка файлов в масштабе?

Как работает загрузка файлов в масштабе?

Задумывались ли вы, что на самом деле происходит после нажатия кнопки «Загрузить»?
Вы выбираете файл, и через несколько секунд он появляется в Google Drive или Amazon S3. Но за этой простой кнопкой стоит высокооптимизированная распределенная система, предназначенная для обработки миллионов загрузок каждый день.

Проектирование системы загрузок Google Drive и Amazon S3

Диаграмма потока загрузки файлов в S3

Наивный подход ❌
Новичок может подумать, что процесс выглядит так:

Клиент
    |
    |
Загрузить файл
    |
    v
Сервер
    |
    |
Сохранить файл
    |
    v
Хранилище

Кажется простым...
Но представьте:

  • Видео размером 1 ГБ
  • 10 миллионов пользователей
  • Медленный интернет
  • Сбои сети
  • Падения сервера

Такая архитектура быстро выйдет из строя.

Проблемы:

  • Пропускная способность сервера становится узким местом
  • Высокая загрузка ЦП
  • Загрузка начинается заново при обрыве соединения
  • Сложно масштабировать

Поэтому компании используют гораздо более умную архитектуру.

Шаг 1: Пользователь выбирает файл
Когда вы выбираете файл, клиент немедленно собирает метаданные:

{
  filename: "отпуск.mp4",
  size: 2.1 ГБ,
  type: "video/mp4"
}

Обратите внимание:
Фактический файл еще не загружается.
Подготавливаются только метаданные.

Шаг 2: Клиент отправляет метаданные в API

Клиент
      |
      | filename
      | size
      | contentType
      |
      v
API-шлюз

API проверяет:

  • Аутентификацию пользователя
  • Квоту хранилища
  • Тип файла
  • Разрешения

Если все валидно, процесс продолжается.

Шаг 3: Сервер генерирует предварительно подписанный URL
Вместо отправки файла через сервер приложений, сервер запрашивает безопасный URL для загрузки.

                Сервер
                     |
                     |
          Сгенерировать URL загрузки
                     |
                     |
                     v
                  Amazon S3

Пример:

https://bucket.s3.amazonaws.com/file123
?signature=abcxyz
&expires=600

Это называется предварительно подписанный URL.
Он:

  • Временный
  • Безопасный
  • С ограниченными правами
  • Автоматически истекает

Зачем использовать предварительно подписанные URL?
Без них:

Клиент
     |
     |
Сервер приложений
     |
     |
Хранилище

Каждый байт проходит через ваш сервер.
Плохая идея.

С предварительно подписанными URL:

Клиент
     |---------------------->
              Хранилище

Сервер приложений обрабатывает только авторизацию.
Тяжелая загрузка файла идет напрямую в облачное хранилище.

Преимущества:

  • Меньшая нагрузка на сервер
  • Снижение стоимости
  • Лучшая масштабируемость
  • Более быстрая загрузка

Шаг 4: Клиент загружает напрямую в S3
Теперь клиент загружает напрямую:

Клиент
      |
      |
      | Файл 2 ГБ
      |
      |
      v
Amazon S3

Сервер больше не участвует в передаче данных.
Именно поэтому системы могут поддерживать миллионы пользователей одновременно.

Шаг 5: Хранилище возвращает успех
После загрузки:

S3
  |
  |
200 OK
  |
  |
Клиент

Теперь клиент знает, что загрузка прошла успешно.

Шаг 6: Сохранение метаданных
Сервер приложений сохраняет информацию, например:

Таблица файлов
-----------------------------------
id
userId
filename
storageKey
size
mimeType
createdAt
updatedAt
-----------------------------------

Обратите внимание:
База данных хранит метаданные, а не сам файл.
Фактический файл остается в объектном хранилище.

Итоговая архитектура

                Метаданные
Клиент -------------------->
                     API
                      |
                      |
          Сгенерировать предварительно подписанный URL
                      |
                      |
                      v
                    S3
                      ^
                      |
                      |
Клиент -----------------------> Загрузить файл
                      |
                      |
               Сохранить метаданные
                      |
                      v
                  База данных

Что произойдет, если интернет отключится?
Предположим:

Загрузка...
███████████░░░░░░░░
         60%

Интернет отключается.
Без специальной обработки:

Начать заново ❌

Загружать файл 5 ГБ снова неприятно.
Современные системы избегают этого с помощью возобновляемых загрузок.

Возобновляемая загрузка

Вместо одного огромного файла клиент делит его на части.
Пример:

Файл
|
|
-----------------------------
Часть 1
Часть 2
Часть 3
Часть 4
Часть 5
-----------------------------

Возможно:

20 МБ каждая

Процесс загрузки:

Часть 1 ✅
Часть 2 ✅
Часть 3 ✅
Часть 4 ❌
Часть 5 ❌

Соединение потеряно.

Позже:

Переподключение
|
|
Возобновить
|
|
Часть 4 ✅
Часть 5 ✅

Загружаются только недостающие части.
Огромная экономия пропускной способности.

Многокомпонентная загрузка в Amazon S3
Amazon S3 поддерживает многокомпонентную загрузку:

Инициализировать загрузку
        |
        |
Загрузить часть 1
Загрузить часть 2
Загрузить часть 3
Загрузить часть 4
        |
        |
Завершить загрузку

Внутренне S3 собирает все части в один объект.

Преимущества:

  • Повторная отправка отдельных частей
  • Параллельная загрузка
  • Лучшая надежность
  • Более высокая производительность

Параллельная загрузка
Вместо:

Часть1
↓
Часть2
↓
Часть3
↓
Часть4

Системы делают:

Часть1 ----->
Часть2 ----->
Часть3 ----->
Часть4 ----->

Все сразу.
Это значительно сокращает время загрузки.

_Что насчет очень больших файлов?_

Для таких файлов как :

  • 10 ГБ
  • 20 ГБ
  • 100 ГБ

Системы используют :
Разбиение на части
Многокомпонентная загрузка
Логика повторных попыток
Проверка контрольной суммы
Фоновая обработка

Это обеспечивает надежность даже в нестабильных сетях.

Как работает синхронизация между несколькими устройствами

Предположим, вы загружаете с ноутбука.

Ноутбук
      |
      |
Облачное хранилище
     /   \
    /     \
Телефон    Планшет

После завершения загрузки:

  • Метаданные обновляются
  • Служба синхронизации обнаруживает изменения
  • Другие устройства получают уведомления
  • Загружаются только измененные файлы

Вот почему ваш телефон быстро показывает новый файл без ручного обновления.

_Почему компании не хранят файлы в базах данных?_
Представьте, что вы храните видео размером 2 ГБ прямо в MySQL или PostgreSQL.

Проблемы:

  • Огромный рост базы данных
  • Медленное резервное копирование
  • Дорогая репликация
  • Низкая производительность

Вместо этого:

База данных
↓
Хранит:
- имя файла
- владелец
- путь
- размер
- права доступа
Объектное хранилище
↓
Хранит:
Фактический бинарный файл

Такое разделение делает системы масштабируемыми и более простыми в обслуживании.

Реальный производственный поток

                    Пользователь
                      |
                      |
                Выбрать файл
                      |
                      |
             Отправить метаданные
                      |
                      v
               API-шлюз
                      |
          Аутентификация
                      |
      Сгенерировать предварительно подписанный URL
                      |
                      v
                Объектное хранилище
          <--------------------
             Прямая загрузка
                      |
                      |
             Успех загрузки
                      |
                      |
             Сохранить метаданные
                      |
                      v
                  База данных
                      |
                      |
             Уведомить службу синхронизации
                      |
          -----------------------
          |                     |
       Ноутбук               Мобильный
          |                     |
       Синхронизировано ✅   Синхронизировано ✅

Вопросы для собеседования

Q1. Почему файлы не должны проходить через сервер приложений?

Потому что это создает узкое место по пропускной способности, увеличивает стоимость сервера и ограничивает масштабируемость. Прямая загрузка в объектное хранилище более эффективна.

Q2. Что такое предварительно подписанный URL?

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

Q3. Зачем хранить метаданные в базе данных, а не сам файл?

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

Q4. Что такое многокомпонентная загрузка?

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

Q5. Что такое возобновляемая загрузка?

Механизм, при котором прерванные загрузки продолжаются с последнего успешно загруженного фрагмента вместо начала с нуля.

Источникdevto