Обзор

Если вы зарегистрированы в социальных сетях, то есть большая вероятность, что вы использовали инстаграм хотя бы раз в жизни. Вы когда-нибудь задумывались, как приложение работает так безупречно, и если вам нужно создать подобное приложение, как вы будете действовать? В этой статье мы расскажем, как создать приложение, похожее на Instagram.

Требования

Функциональный

  1. Пользователь должен иметь возможность загружать изображение/видео в свой профиль.
  2. Пользователь должен иметь возможность видеть загрузки других пользователей, подписанных на пользователя.
  3. Пользователь должен иметь возможность подписаться на других пользователей.
  4. Пользователь может выполнять поиск изображения/видео по названию.

Не функциональный

  1. Задержка пользовательского фида должна быть низкой.
  2. Нас устраивает возможная согласованность, так как загруженное изображение может быть показано другому пользователю через несколько миллисекунд.
  3. Наше приложение должно быть высокодоступным.
  4. Хранилище данных, которое мы будем использовать для хранения изображений/видео, должно быть надежным, и данные не должны быть потеряны.

Дополнительные требования

  1. Пользователи могут добавлять теги к фото/видео.
  2. Пользователи могут оставлять комментарии к посту.
  3. Пользователи могут искать фото на основе тегов.

Оценка мощности

Оценка трафика

Предположим, у нас 500 миллионов активных пользователей в день, и мы получаем примерно 5 миллионов загрузок в день.

Общее количество загрузок ~ 57 в секунду

Оценка хранилища

Предположим, что средний размер загрузки составляет 200 КБ.

Тогда общее хранилище, необходимое на 1 день, составляет 200*5 ~ 1 ТБ в день.

API

  1. Загрузить изображение
POST: /image
Request {
    image: MultipartFile
    title: String
}
Response {
    imageId: String
}

2. Получить ленту

GET: /feed?pageNumber={pageNumber}&limit={limit}
Response {
    feeds: Feed[]
}
Feed: {
    imageId: String
    imageUrl: String
    title: String
}

3. Подпишитесь на пользователя

POST: /follow/{followingUserId}

4. Поиск изображения

GET: /search?keyword={searchKeyword}
Response: {
    feeds: Feed[]
}
Feed: {
    imageId: String
    imageUrl: String
    title: String
}

Рассмотрение дизайна

  1. Хранилище данных для хранения загруженного изображения. Наша система тяжело читается, поэтому нам нужно хранилище данных, которое может быстро получить загруженное изображение и отобразить его в пользовательском приложении. Необходимо помнить о нескольких вещах: 1) Хранилище данных должно быть надежным, поскольку мы не хотим, чтобы загруженное пользователем изображение потерялось. 2) Пользователь может загружать любое количество изображений, поэтому хранилище данных должно быть масштабируемым для обработки миллиардов изображений. 3) Задержка при получении фотографий должна быть низкой. Мы можем рассмотреть хранилище объектов для хранения загруженных пользователем изображений, что-то вроде AWS S3. Существуют и другие типы хранилищ, такие как хранилище файлов и блочное хранилище, но с учетом вышеперечисленных факторов хранилище объектов будет правильным выбором для нашего проекта, поскольку оно обеспечивает низкую задержку чтения и эффективное управление огромным количеством записей.
  2. Хранилище данных для хранения пользовательских данных и их загрузок. — Теперь у нас есть хранилище данных для хранения загруженного изображения пользователями. Нам нужна база данных для хранения метаданных пользовательских загрузок и пользовательских данных. О чем следует помнить при выборе хранилища данных — 1) База данных должна быть высокодоступной. 2) У него должна быть низкая задержка чтения, так как наша система уже загружена. 3) Он должен быть достаточно масштабируемым, чтобы обрабатывать миллиарды записей. 4) Он должен быть надежным и поддерживать сегментирование и репликацию. Учитывая вышеперечисленные факторы, мы не видим потребности в реляционной базе данных. Мы можем выбрать базу данных NoSQL на основе значений ключей. Для этого дизайна системы мы можем выбрать AWS DynamoDB для хранения пользовательских данных и метаданных загрузки изображений.

Дизайн базы данных

Нам нужны следующие таблицы для хранения наших данных —

  1. Таблица для хранения пользовательских данных
userId: string[HashKey]
name: string
emailId: string
creationDateInUtc: long

2. Таблица для хранения данных подписчиков

followingUserId_followerUserId: string [HashKey]
followingUserId: string [RangeKey]
followerUserId: string
creationDateInUtc: long

Мы не можем выбрать followingUserId в качестве хэш-ключа, потому что это может создать несбалансированный раздел, поскольку могут быть пользователи, у которых будут миллионы подписчиков. Этот тип пользователей известен как горячие пользователи. Следовательно, для поддержания сбалансированного раздела мы можем выбрать комбинацию followingUserId и followerUserId в качестве hashKey.

3. Таблица для хранения пользовательских загрузок

uploadId: string[Hashkey]
userId: string[RangeKey]
imageLocation: string
uploadDateInUtc: long
caption: string

4. Таблица для хранения данных пользовательской ленты

userId: string[Hashkey]
uploadId: string
creationDateInUtc: long[RangeKey]

Дизайн высокого уровня

Сведения о компонентах

  1. Клиент. Это будет мобильное/настольное приложение, которое будет подключаться к внутренним серверам через REST API, определенный выше.
  2. Балансировщик нагрузки. Мы будем использовать балансировщик нагрузки для распределения трафика между разными серверами. Это сделает нашу Систему более доступной, и в случае, если сервер выйдет из строя из-за балансировщика нагрузки, балансировщик нагрузки сможет распределить трафик по разным серверам.
  3. Служба изображений. Служба изображений отвечает за предоставление API для загрузки изображения и получения метаданных изображения. API метаданных вернет путь к изображению в s3, который будет использоваться клиентами для загрузки изображения в свое приложение.
  4. S3 — мы используем объектное хранилище для хранения загруженных пользователями изображений. AWS S3 — это масштабируемое и дешевое объектное хранилище, которое мы можем использовать здесь. Мы можем интегрировать его с AWS CloudFront, чтобы изображения отображались в пользовательском приложении намного быстрее.
  5. CloudFront. Amazon CloudFront — это сервис сети доставки контента (CDN), созданный для обеспечения высокой производительности, безопасности и удобства для разработчиков. С помощью CloudFront изображения будут быстрее отображаться в пользовательском приложении.
  6. Image DDB. Мы используем базу данных AWS Dynamo DB для хранения метаданных загружаемых пользователем изображений. Мы обсуждали это в предыдущем разделе.
  7. SNS — при каждой загрузке пользователя мы публикуем уведомление с помощью AWS Simple Notification Service. Это будет полезно для других процессов обработки, таких как мониторинг, создание каналов, аналитика и т. д. Различные SQS могут подписаться на этот SNS для прослушивания событий.
  8. SQS. Мы используем сервис AWS Simple Queue, который подпишется на SNS для загрузки событий, а сервис создания каналов будет прослушивать этот SQS для обработки событий.
  9. Служба создания фидов. Эта служба отвечает за создание фидов пользователей. Он будет прослушивать события загрузки пользователя через SQS и запускать процесс создания пользовательского фида. Этот сервис будет обрабатывать миллионы событий, и о низкоуровневом дизайне для этого сервиса может быть отдельный разговор. Мы расскажем об этом в следующей статье.
  10. Feed DDB. Мы используем Dynamo DB для хранения данных пользовательского фида. Служба генерации фидов будет взаимодействовать с DDB для обновления пользовательских фидов.
  11. Redis Cache. Чтобы сократить задержку чтения для наших пользователей, мы реализуем слой кэширования между нашей службой создания каналов и DDB. Когда придет запрос на получение фида пользователя, он сначала проверит кэш Redis, если он недоступен, то извлечет его из DDB и вернет ответ.

Узкие места и будущие расширения

  1. Создайте страницу исследования пользователя, на которой загрузки из общедоступных учетных записей могут отображаться на странице пользователя в зависимости от предпочтений пользователя и прошлых данных.
  2. Генерация фидов пользователей. Текущее поколение пользовательских фидов имеет узкое место: в настоящее время оно прослушивает все события обновления и обновляет фид для всех подписчиков этого конкретного. Это создаст проблему, когда будет обновление для горячего пользователя (пользователя, у которого огромное количество подписчиков). Мы обсудим это в следующих статьях.
  3. Более расширенный поиск на основе различных параметров, таких как теги, местоположение, подпись, заголовок и т. д.

Ресурсы

  1. Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения
  2. Проектирование приложений, интенсивно использующих данные

Надеюсь, эта статья окажется для вас полезной, следите за новостями и следите за новыми статьями в будущем.