Skip to content

themilchenko/design_highload

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 

Repository files navigation

Highload Instagram

Методические указания

Содержание

Тема и целевая аудитория

Instagram — американская социальная сеть для обмена фотографиями и видео, основанная Кевином Систромом и Майком Кригером.

Факты про целевую аудиторию

Целевой аудиторией являются люди, имеющие отношение к бизнесу, большие компании, общеизвестные деятели и просто люди, которые хотят делиться своей жизнью в социальных сетях.

  • В среднем количество активных пользователей достигает 2-х биллионов;
  • Пользователи проводят в среднем 11 часов в месяц в соц. сети;
  • 30.8% аудитории - люди от 18 до 24 лет, а 30.3% - люди от 25 до 34 года.

Страны лидеры по размеру аудитории на момент января 2023 года:

Страна Пользователей в год, млн.
Индия 229.25
США 143.35
Бразилия 143.35
Индонезия 89.15
Турция 48.65
Япония 45.7
Мексика 36.7

Распределние пользователей за последний месяц (Январь 2023):

Страна Пользователей в месяц, млн. Пользователей в месяц, %
CША 435 16.65
Индия 403.7 10.90
Бразилия 200.2 10.22
Турция 162.4 3.55
Индонезия 161.5 3.50
Остальные страны 1 500 55.18

Минимально жизнеспособный продукт

  1. Создание, редактирование, просмотр профиля;
  2. Публикация фото и видео с продолжительностью не более 60 секунд;
  3. Возможность поставить лайк и оставить комментарий к посту;
  4. Возможность подписаться на пользователя;
  5. Возможность просматривать ленту с подписками.

Расчет нагрузки

Продуктовые метрики

  1. Месячная аудитория: 2 биллиона [1];
  2. Дневная аудитроия: 500 миллионов [2];
  3. Среднее время онлайна пользователя - 3 мин. 6 сек [2]. За это время пользователю удается просмотреть 10 страниц.

Регистрация

Перейдем к регистрации: за 2021 год было насчитано 1.28 биллиона пользователей, когда за 2022 1.32 биллиона [3]. Это значит, что за год прибавилось 40 000 000 пользователей. Значит, грубой оценкой можно посчитать среднее количество регистраций в день: 4 * 10^7 / 365 = 108 089. То есть количество регистраций в день достигает 108 тыс.

Авторизация

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

Предположим, что седьмая часть пользователей от дневной аудиторий из тех, кто уже зарегестрирован, будет логиниться на сервисе, что будет сопровождаться выдачей сессионного ключа. Итого, количество авторизаций:

108 000 + 0.14 x (500 000 000) = 70 млн.

Лайки и комментарии

Информация о лайках и комментариях была найдена в источнике [4]:

  • Среднее количество лайков, оставляемых под постом: 1 261, но всего среднее кол-во лайков в день 2 биллиона;

Суммарное количесво лайков:

50 000 000 000 x 1 261 = 63 050 000 млн.

  • Среднее количество комментариев, оставляемых под постом: 24.5, но всего среднее кол-во комментариев в день 38 миллиона.

Суммарное количество комментариев:

50 000 000 000 x 24.5 = 1 225 000 млн.

Лента

Считаем в среднем: имеем число пользователей в день, теперь считаем каджого. Основываясь на статистике о среднем времени (53 минуты), проведенным пользователем на сервисе [5], будем предполагать, что большую часть времени он проводит за скроллингом ленты (80%).

Далее нужно понять, сколько времени занимет у пользователя на один пост (просмотр, чтение описания, лайк, комментирование). Мозг может обрабатывать изображение, которое глаз видел только в течение 13 миллисекунд, но человек не сможет сознательно регистрировать эти кадры, поэтому возьмем 2-5 секунды на просмотр фото поста или видео - длина видео (в среднем 10 секунд) и еще 2-5 на проставление лайка и просмотра/написания комментариев. Получаем, что на один пост пользователь будет тратить:

Формула: [время пользователя за скроллиногом ленты] / [время на один пост]\

0.7 x [(0.8 x 53 x 60) / 10] + 0.3 x [(0.8 x 53 x 60) / 15] = 228 постов в день на пользователя

Стоит учитывать, что посты с фото и видео относятся как 7:3. Посты будут загружаться каждые 30 постов. Тогда для одного пользователя всего будет 228 / 30 = 76 загрузок ленты на пользователя в день. Для всех пользователей:

76 x 500 000 000 = 38 000 000 000

Сводная таблица по среднему количеству действий пользователя по типам в день

Тип запроса Среднее количество действий (в день)
Регистрация 219 тыс.
Авторизация 70 млн.
Публикация фото / видео 95 млн.
Проставление лайков 2 000 млн.
Проставление комментариев 38 млн.
Просмотр ленты 38 000 млн.

Технические метрики

Размер хранения в разбивке по типам данных

  • Информация о пользователе

    У пользователя будут следующие поля:

    • Имя, Фамилия, Никнейм: все по 32 символа, каждый из которых весит байт;
    • Почта, Дата рождения: 4 байта;
    • Пароль: в захэшированном виде 32 байта;
    • Описание: 64 симовла по байту каждый;
    • Аватарка: 50 Кбайт.

    На одного пользователя:

    30 + 30 + 30 + 4 x 125 000 + 4 + 4 + 50 000 = 550 098 байт = 4 Мб`

    На всех пользователей понадобится:

    2 000 000 000 x 4 = 8 * 10^9 Мб = 8 000 Тб ~= 8 Пб.

  • Размер постов

    Начну с размера поста с фотографией: средний размер исходной фотографии составляет около 2 Мб. Однако, для хранения на серверах и передачи через сеть, изображение будет сжиматься с использованием алгоритмов оптимизации и сжатия. В результате, средний вес сжатой картинки на платформе составит примерно 300 Кб.

    Размер видео будет зависеть от многих характеристик, но будем брать грубую оценку в среднем. Отталкиваемся от битрейта видео - определяет количество бит, передаваемых в секунду и влияет на качество и размер видеофайла. Обычно на Instagram рекомендуется использовать битрейт от 2 до 5 Mbps [6]. Для примера возьмем средний битрейт видео в 3 Mbps. Расчет объема данных: для определения размера видеофайла в байтах нужно умножить средний битрейт на длительность видео (в секундах) и поделить на 8 для преобразования из мегабитов в байты.

    Размер видео (в байтах) = (Средний битрейт x Длительность видео) / 8

    В нашем случае, длительность видео 10 секунд, а средний битрейт 3 Mbps:

    (3 Mbps x 10 сек) / 8 = 30 Mbps / 8 = 3.75 Мб

    Размер видео (в байтах) = 3.75 Мб

    Описание к посту займет около 150 байт (возьмем в среднем 150 символов по байту). Итого, пост с картинкой будет весить 300 Кб. В случае с видео - возьмем видео в 10 секунд, которое будет весить 3.75 Мб и пост будет уже весить 3.78 Мб.

    С момента запуска приложения было насчитано около 50 миллиардов фотографий [7], в секунду загружается 1 074 фотографий. Значит, возьмем 3/4 постов с фотографией и 1/4 с видео и посчитаем приблизительный суммарный размер базы, которая будет хранить все посты:

    50 000 000 000 x (0.75 x 0.3 + 0.25 x 3.78) = 5 850 000 000 Мб = 58 500 Тб = 58.5 Пб

  • Размер лайков

    Для лайков будут учитываться два целочисленных значения по 8 байт каждый - id пользователя, отсавлющий лайк и id поста, на который ставится лайк. При 50 биллионов постов предположим, среднее количество лайков на пост - 1 261. Тогда произведем расчет:

    50 000 000 000 x 1 261 x 16 байт = 800 Тб

  • Размер комментариев

    В состав комментария будут входить id комментария, id пользователя и поста по 8 байт, содержимое - 1 Кбайт, дата создания 4 байта. Получаем следующее значение:

    50 000 000 000 x 24.5 x 1024 = 1 280 Тб

Итого сводная таблица по выделяемому месту для существенных блоков данных:

Название данных Количество, шт. Место, Тб.
Посты 50 000 млн. 58 500
Пользователи 2 000 млн. 8 000
Лайки 5 000 блн. 800
Комментарии 2 500 блн. 1 280

Сетевой трафик

  • Взглянем на авторизацию и регистрацию и посчитаем нагрузку:

    70 000 000 (в день) x 4 Мб / (24 * 3600) = 12 Гбит/с

    Для пиковой нагрузки умножу показатель в 2 раза:

    88 Гбит/с x 2 = 24 Гбит/с

  • Рассмотрим загрузку поста. Зная, что за секунду загружается 1 074 постов, посчитаем нагрузку на сеть:

    1 074 x (0.75 x 2.2 + 0.25 x 8.2) = 3 973.8 Мб/с = 31 Гбит/с

    Для пиковой нагрузки умножу показатель в 2 раза:

    31 Гбит/с x 2 = 62 Гбит/с

  • Теперь посчитаем загрузку ленты. Ссылаясь на проделанные расчеты выше, получим:

    [38 000 000 000 (в день) x 30 (лимит постов для одной загрузки ленты) x (0.7 x 0.3 + 0.3 x 3.78)] / (24 x 3 600) = 1 773 333 Мб/с = 1 773 Гбит/с

    Для пиковой нагрузки умножу показатель в 2 раза:

    1 773 Гбит/с x 2 = 3 546 Гб/с

Так как остальные запросы будут не настолько дорогие относительно этих двух, заложу на них 5 Гбит/с.

Получу итоговую сетевую нагрузку:

88 + 31 + 1 773 = 1 892 Гбит/с

Тип данных Сетевая нагрузка, Гбит/с Пиковая сетевая нагрузка, Гбит/с
Авторизация & Регистрация 88 176
Загрузка поста 31 62
Лента 1 773 3 546

Суточная нагрузка на сеть - 1 892 Гб/с * 3600 * 24 = 163 468 800 Гб/сутки

RPS в разбивке по типам запросов

Уже по полученным данным посчитаем кол-во запросов в секунду в среднем:

  • Регистрация/Авторизация: 500 000 000 / (24 * 3600) = 5 787 rps
  • Публикация фото / видео: 95 000 000 / (24 * 3600) = 1 099 rps
  • Проставление лайков: 2 000 000 000 / (24 * 3600) = 23 148 rps
  • Добавление комментариев: 38 000 000 / (24 * 3600) = 439 rps
  • Просмотр ленты: 38 000 000 000 / (24 * 3600) = 439 814 rps

Теперь нужно нужно посчитать пиковую нагрузку:

Для авторизации можно умножить среднюю нагрузку на 2, как и с публикацией фото и видео и просмотром ленты. Это объясняется наибольшей активностью пользователей в определенный момент времени.

В случае лайков с комментариями надо умножать среднюю нагрузку на 4. Это обуславливается выкладыванием известной личности какой-либо фотографии - ее начнут активно лайкать и комментировать.

Тип запроса Средняя нагрузка, rps Пиковая нагрузка, rps
Авторизация 5 787 11 574
Публикайия фото / видео 1 099 2 198
Проставление лайков 23 148 92 592
Добавление комментариев 439 1756
Просмотр ленты 439 814 879 628
Итого 470 287 987 748

Логическая схема

Логическая схема

Описание таблиц

  1. Пользователи (users) - таблица со всеми необходимыми данными о пользователе.
    • Primary key: id пользователяj
  2. Посты (posts) - таблица с постами пользователями, которая включает в себя все необходимое для отображения поста.
    • Primary key: id поста;
    • Foreign key: user_id.
  3. Лайки (likes) - таблица с информацией, что i-й пользователь поставил лайк j-му посту.
    • Foreign key: user_id, post_id.
  4. Комментарии (comments) - таблица с информацией, что i-й пользователь поставил лайк j-му посту с непустым сообщением.
    • Foreign key: user_id, post_id.
  5. Подписки (subscriptions) - таблица с информацией о том, что i-й пользователь подписан на j-го.
    • Foreign key: creator_id, follower_id.
  6. Сессии (sessions) - таблица со всеми сессиями пользователей.
    • Foreign key: user_id.

Физическая схема

Физическая схема

Выбор БД

  1. Сессии пользователей

    Сессии пользователей будут очень часто изменяться по очевидным причиам. Из-за этого нужно осуществить быстрый доступ на получение текущих пользователей, быстрое удаление и добавление. Таким образом их лучше всего хранить в оперативной памяти, с чем прекрасно будет справляться нереляцонная in-memory база данных - Redis. В данном случае, ключом будет значение сессии, а значением - id пользователя и дата истечения сессии.

  2. Пользователи и посты

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

    Аналогично пользователям данные постов будем хранить в PostgreSQL, а картинки/видео в S3-хранилище.

  3. Комментарии, лайки, подписки

    Данные хорошо ложатся на реляционную модель, поэтому будем хранить их в PostgreSQL.

Индексы

  • Индекс на поле nickname в таблице users будет нужен в случае того, если пользователь решит найти другого по никнейму. Таким образом индекс увеличит селективность по этому полю;
  • Индекс на поле user_id в таблице posts нужен для быстрого поиска пользователя, пост которого был увиден;
  • Индекс на поле post_id в таблице comments нужен для быстрой подгрузки всех комментраиев к посту;
  • Индекс на поля id и date_created для подгрузки поста по нужной дате;
  • Индексы на поля creator_id и follower_id в таблице subscriptions будут полезны для улучшения селективности подписчиков и подписок соответственно.

Шардирование

  • Users: шардирование будет проводиться по принципу хэширования [hash(nickname) % shurd_num] для более равномерного распределения данных (важно, чтобы хэш-функция действительно могла выполнять это требование). Таким образом, при вычисления хэша мы точно будем знать, к какому узлу обратиться, чтобы гарантированно получить запрашиваемые данные.

    При этом стоит учесть, что будут популярные пользователи, запрос к которым будет чаще, поэтому для них стоит добавить исключение, которое заключается в том, что для списка популярных пользователей будут выделяться узлы, которые будут обрабатывать топ-1000 пользователей. Это позволит отвести больше ресурсов и пропускной способности для обработки запросов, связанных с этими пользователями;

  • Followers: таблица с подписками будем храниться на том же шарде, что и users для согласованности данных.

  • Posts: здесь применяем партиционирование по принципу range-based, а шардировать по разным инстансам по дате создания поста не получится, потому что запросов на новые посты будет куда чаще, чем к старым. Поэтому шардирование будет происходить по полю user_id. В случае, если какой-то шард будет перегужен, система должна суметь динамически расширить вычислительную мощность посредством добавления узлов. Для популярных пользователей стоит также отвести отдельные шарды, как это было описано в предыдущем пункте;

  • Comments, Likes: комментарии будет логично шардировать по такому же принципу, что и посты для согласованности данных, то есть на том же инстансе, что и посты нужной даты.

Репликация

Для PostgreSQL будет сделана Master-Slaves репликация. Таким образом, когда на Master базу будут записываться данные, с Slave баз будет читаться информация. Также при отказе одного Slave узла чтение может продолжится посредством переключения на другой узел. В случае отказа Master узла, главным будет ставновиться один из Slave'ов.

Кэширование

Будем использовать кэширование данных для быстрого доступа к наиболее вероятному запросу.

Для такой задачи подойдет Memcached. Это хранилище ключей и значений в памяти для небольших фрагментов произвольных данных (строк, объектов) из результатов вызовов базы данных. Все данные, хранящиеся в реляционных базах будем кэшировать (в частности самые популярные запросы на посты и пользователей). Таким образом перед походом в базу, будем проходить через узлы и проверять популярные запросы.

Для кэширования изображений/видео нужно использовать CDN сервера.

Технологии

Технология Область применения Мотивация
Golang Backend dev Популярный, быстрый, читаемый, поддерживающий многопоточную и асинхронную работу язык. За счет своей опулярности имеет множество готовых решений для backend-разработки
TS / React Frontend dev TS за счет своей типизации позволит писать более понятный и читаемый код. React фреймворк имеет множество инструментов для эффективной разработки
Swift / Kotlin Mobile dev В силу того, что приложение имеет большую популярность в мобильной версии, нужно разрабатывать его также под IOS и Android
PostgreSQL Database Реляционная база, дающая возможность масштабироваться за счет своего обширного функционала. Одна из лучших среди реляционных баз
Redis Database In-memory база, хранящая данные в оперативной памяти, за счет чего ускоряет доступ к информации. Также предоставляет возможным шардирование и репликацию, что немало важно для высоконагруженного сервиса
Amazon S3 Cloud storage Одно из самых популярных и надежных хранилищ объектов, которое предоставляет масштабируемое, высокодоступное и безопасное хранение данных в облаке
Nginx Web-server Быстро отдает статику, поддерживает функционал кэширование и является отличным балансировщиком нагрузки
GitLab CI/CD CI/CD Обладает широким функционалом, включая интеграцию с Kubernetes, и обеспечивает интегрированную среду разработки (IDE) и контроль версий
Kubernetis Managment Является удобным для управления кластерами. Имеет множество преимуществ: легкое масшатбирование, эффективная отказоустойчивость, удобное управление приложениями и ресурсами
Docker Coneinerization Удобное развертование, изолированное окружение для каждого приложения, безопасность, а также удобство в использовании
Prometheus Monitoring Мониторинг производительности, быстрый сбор метрик, масштабируемость, доступная интеграция с Kubernetis
Grafana Visualizong Большой функционал для визуализации собранных метрик
gRPC RPC Протокол удаленного вызова процедур, подходящих для большого списка нужд, с помощью которого с легкостью можно осуществить взаимодействие микросервисов
RabitMQ Message queue Брокер очередей для асинхронной обработки запроса в случаях, когда быстрый ответ пользователю не нужен

Схема проекта

Схема проекта

Описание

Первоначально запросы поступают от пользователей через DNS-сервер, который по алгоритму Round-robin будет перенапрвлять на один из серверов-балансировщиков. Каждый из них будет перенапрявлять запрос на наименее загруженный сервер-бэкенд. У каждого сервера будет свой кэш запросов для быстрого ответа в случае популярного запроса.

Перейдем к кластеру API Gateway, которые будут обрабатывать запросы, выполнять бизнес логику и ходить дальше в микросервисы за нужными данными. Весь кластер будет управляться Kubernetes. Все метрики будут собираться в базе Prometheus. У бэкендов будут свои балансировщики нагрузки, задача которых будет заключаться в балансировке нагрузки между узлами микросервисов.

Рассмотрим микросервисы:

Каждый микросервис выполенен в виде кластера, чтобы также распределять нагрузку. Общение бэкендов с микросервисами будет осуществялться с помощью протокола gRPS.

  1. Authorization microservice

    Этот микросервис будет отвечать за сессии пользователей. Как говорилось выше, он будет ходить в кластер Редиса. Сам редис будет реплицировать данные для поддержания отказоустойчивости и быстро возвращать сессии нужному узлу микросервиса. Микросервис будет определять к какому шарду нужно будет обратиться.

    Все микросервисы будут управляться Kubernetes, метрики отправляются в свой кластер Prometheus. У каждой базы тоже будет свой сборщик метрик. Все метрики в последствии будут отпрвляться в Grafana.

  2. Users microservice

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

  3. Posts microservice

    Также ходит в Постгрес. В зависимости от запроса будет обращаться к шарду по принципу времени создания или по ранжированию. Стоит учесть, что в базу он будет ходить лишь за метаданными постов, сам контент будет получаться в микросервисе Attachments.

  4. Attachment microservice

    Ходит в кластер S3-хранилища. Для более быстрой работы будет настроена контентная адресация, позволяящая определить, к какому узлу обратиться. Внутри него в базе Редиса будет проверяться кэш. Если в кэше ничего нет, ищем информацию в хранилище S3.

    Для загрузки фото/видео на базу стоит поставить брокер очередей RabbitMQ. За счет него сможем выполнять запросы отложенно. Это важно, потому что загрузка контента занимает какое-то время, а сам пост отобразиться, когда обработается и сохранится.

  5. Feed microservice

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

Логика формирования ленты

Так как загрузка ленты является самым большим по rps запросу, стоит продумать, как она будет формироваться. Опишу общую логику на получение ленты в архитектуре:

  1. Когда пользователь запрашивает свою ленту, запрос сначала попадает на API Gateway.

  2. API Gateway проверяет авторизацию пользователя, используя микросервис Authorization. Если пользователь не авторизован, возвращается ошибка.

  3. После успешной авторизации API Gateway отправляет запрос на микросервис Feed. На этом этапе сервис ходит в базу, проверяет наличие id пользователя в ней. Это так называемый кэш, в котором будут находиться предопределенные id постов, которые нужно подгрузить в ленте.

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

  5. После получения id постов, которые нужно получить, идем сначала в сервис постов для получения метаданных, а затем в сервис attachments, где и получим сам контент. Результат возвращается клиенту.

Для наглядности представлю ключевую часть схемы генерации ленты:

Генерация ленты

Опишу ключевые моменты. Начну с добавления поста. Как видно на схеме, запрос, проходя через слой Gateway, идет в сервис постов, а затем добавляет метаданные в базу, потом запрос кладется в брокер очереди, который будет идти в сервис attachments для загрузки контента, а также в сервис ленты, чтобы уведомить сервис о том, что у пользователя N появилась новая фотография. Далее этот сервис будет ходить в базу Memcached, чтобы добавить всем пользователям, которые подписаны на человека только что загрузившего пост, id этого поста.

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

Таким образом при генерации ленты у пользователя будет смотреться кэш текущих id постов и затем идти в базу для отдачи этих постов. Учитывая, что запросы к постам пойдут с большой вероятностью на разные шарды. Можно это ускорить с помощью параллельных вычислений, но этодовольно тяжело реализовать программно.

Логический план запроса

Опишу логический план запроса для каждого типа запроса с клиента.

  1. Запрос на создание нового поста

    • Клиент отправляет запрос на создание нового поста через API Gateway.
    • API Gateway перенаправляет запрос к микросервису Attachments.
    • Далее идем в S3 хранилище и ставим запрос в брокер очередей.
    • После сохранения изображения возвращаемся в Gateway и идем в Posts.
    • Микросервис Posts сохраняет информацию о посте и формирует ответ с идентификатором созданного поста и отправляет его обратно клиенту через API Gateway.
  2. Запрос на получение информации о пользователе

    • Клиент отправляет запрос на получение информации о пользователе через API Gateway.
    • API Gateway перенаправляет запрос к микросервису Users.
    • Микросервис Users получает информацию о пользователе из базы данных с учетом шардирования.
    • Микросервис Users формирует ответ с информацией о пользователе и отправляет его обратно клиенту через API Gateway.
  3. Запрос на получение списка подписок/подписчиков пользователя

    • Клиент отправляет запрос на получение списка подписок или подписчиков пользователя через API Gateway.
    • API Gateway перенаправляет запрос к микросервису Users.
    • Микросервис Users получает информацию о подписках/подписчиках пользователя из базы данных с учетом шардирования.
    • Микросервис Users формирует ответ со списком подписок/подписчиков и отправляет его обратно клиенту через API Gateway.
  4. Запрос на поиск пользователя

    • Клиент отправляет запрос на поиск пользователя через API Gateway, указывая критерии поиска (например, имя пользователя, электронная почта).
    • API Gateway перенаправляет запрос к микросервису Users.
    • Микросервис Users выполняет поиск по указанным критериям в базе данных с учетом шардирования.
    • Микросервис Users формирует ответ с результатами поиска (список найденных пользователей) и отправляет его обратно клиенту через API Gateway.

Список серверов

Пройдемся по каждому компоненту и определим, какая нагрузка будет на каждом из них. На основе этого определим, соклько и каких серверов нужно иметь.

Балансировщики

На основе бенчмарков, проделанных над nginx, можно расчитать, сколько балансировщиков будет использоваться. Стоит учитывать, что тафик будет поступать по протоколу HTTPS. Для обработки SSL соединений со средним размером 4.5 Мб. (подгрузка ленты из 15 постов по 300 Кб.) оптимально использовать 32-ядерный процессор. Как видно по таблице из представленного источника, при увеличении размера отдаваемого файла, рпс уменьшается экспоненциально. С нашими входными данными RPS будет равен 4 492. Теперь посчитаем, сколько серверов понадобится:

987 748 / 4 492 = 219 серверов

Для расчета сетевой емкости воспользуюсь посчитанными нагрузками на сеть: на пике имеем 3 784 Гбит/с. При 219 серверах 3 784 / 219 = 17 Гбит/с. Берем с запасом и получаем, что сетевая емкость каждого сервера будет 32 Гб. Также выделим 64 Гб RAM.

Также потребуется SSD на 128 Гб. для подгрузки статики и кэширования запросов.

Кол-во CPU RAM, Гб. Disk Network, Гб
219 32 64 128 Гб. 16

Бэкенды (API Gateway)

Задача gateway заключается в прокладке пути к микросервисам на основе входящего запроса. Сам бэкенд написан на Go с использованием многопотчности. Нужно выдерживать 987 748 RPS в сумме.

Исходя из бенчмарков, проделанных в предыдущем пункте, знаем, что на 32 ядра будет приходиться 4 492 rps, 4 492 / 32 = 140 rps на одно ядро. На одно ядро будет приходиться меньше рпс по причине того, что там будет производиться куда больше вычислений в силу сложной бизнес-логики, поэтому уменьшим предполагаем рпс в 2 раза и получим 70 рпс. Посчитаем суммарное количество ядер:

987 748 / 70 = 14 100 CPU

14 100 / 32 (ядер на одной машине) = 440 серверов

Выделю 128 Гб. RAM из-за того, что воркеры будут работать с данными, подтянутыми из микросервисов.

Сетевой трафик для каждой машины - 3 784 / 440 = 9 Гбит/с. Сетевую карту беру с запасом, так как нагрузка может перераспределяться в случае отказа проблемных узлов - 16 Гб. емкостью.

Кол-во CPU RAM, Гб. Disk Network, Гб
440 32 128 128 Гб. 16

Микросервисы

  1. Auth microservice

    Имеем 11 574 rps на пике на запись. Так будут проверяться все запросы, на чтение будет около 1 000 000 rps на пике. Микросервис будет ходить и обрабатывать данные сессий из Redis. Сами запросы будут легковесными. Предположим, что одно ядро сможет обрабатывать 1 000 запросов в секунду. Возьмем 64 CPU. Один сервер будет выдерживать 64 000 rps. Всего серверов: 1 000 000 / 64 000 = 15 серверов.

    Кол-во CPU RAM, Гб. Disk Network, Гб
    14 64 8 128 Гб. 8
  2. Users microservice

    В этот компонент будут попадать следующие значимые запросы: поиск пользователей, поиск подписок/подписчиков, получение пользователя по id и т. д. Стоит учесть, что каждый запрос на пост сопровождается походом в users для получения автора поста. Из этого сделаем вывод, что нагрузка на пользователей будет больше, чем на посты, так как будут учитываться дополнительно поиск пользователя, переход на него из поста и т.д. Таким образом все типы запросов кроме авторизации будут использовать этот микросервис. Так как уже было посчитано кол-во серверов для обработки всех запросов, возьмем чуть меньше - 260 серверов с 32 CPU, 64 Гб. RAM и 16 Гб. сетевой емкости.

    Кол-во CPU RAM, Гб. Disk Network, Гбит/с
    260 32 64 128 Гб. 16
  3. Posts microservice

    Считаем запросы, которые связаны только с постами: просмотр ленты, проставление лайков, оставление комментариев, публикация фото/видео - 950 000 rps. Таким образом выделяем при учете бенчмарков, учитывая, что 32 ядра смогут обрабатывать 5 000 запросов в секунду, 950 000 / 5 000 = 190 серверов.

    Кол-во CPU RAM, Гб. Disk Network, Гбит/с
    190 32 64 128 Гб. 32
  4. Attachments microservice

    Этот компонент будет одним из главным, так как здесь будет находиться работа со всем контентом сервиса. Из запросов сюда будут входить подгрузка ленты, создание аватарки, загрузка контента. Исходя из пиковых нагрузок, сервис должен держать 879 628 + 2 198 = 880 000 rps. Предположим, если gateway слой обрабатывает 1 млн. запросов, attachmets держит 88% от общей нагрузки - 273 x 0.88 = 240 серверов, так как эти серверы работают с тяжелыми данными относительно других. Возьмем дополнительно еще 30, так как это узкое место, работающее с большими данными. Получим 270 серверов. Также выделим 32 CPU и 64 Gb RAM.

    На загрузку приходится 31 Гбит/с трафика, на подгрузку постов 3 546 Гбит/с. Тогда для поддержания стабильного трафика нужно около 16 Гб. сетевой емкости.

    Кол-во CPU RAM, Гб. Disk Network, Гб
    270 32 64 128 Гб. 16

Базы данных

Postgres

  • Users

    По расчетам емкости в предыдущих пунктах было получено, что на хранение пользователей уходит 8 000 Тб. Из них без автарки (то есть для хранения в реляционной базе) 8 000 000 - 50 x 2 000 000 000 = 8000 - 100 = 7 900 Тб.

    Исходя из бенчмарков, предположим, что одно ядро обрабатывают 1 500 запросов. Для 16 * 1 500 = 24 000 запросов используем один сервер. Понадобится 1 000 000 rps / 24 000 = 42 сервера.

    Считаем место шардов: 7 900 Тб. / 42 = 188 Тб. Будем хранить в RAID на HDD. Также берем 128 RAM на индексы.

    Нагрузка на базы пользователей будут 3 784 / 42 ~= 100 Гбит/с. Сетевая карта будет объемом 100 Гб.

    Используем 42 мастера и по 3 реплики на каждый мастер. Итого, имеем 42 + 3 * 42 = 168 серверов на пользователей.

    Кол-во CPU RAM, Гб. Disk Network, Гб.
    168 16 128 188 Тб. HHD 100
  • Subscriptions

    Будем считать, что в среднем у пользователя будет 100 подписчиков и 50 подписок. Мы лишь усредняем значение, так как у каких-то аккаунтов может быть 50 подписчиков, а у других и вовсе 2 миллиона. Каждая подписка весит 16 байт - 2 id: подписчика и автора.

    Для подписчиков 2 000 000 000 x 100 x 16 = 3 200 Гб = 3.2 Тб.

    Для подписок это число в два раза меньше 1.6 Тб.

    Учитывая, что этот сервер работает с легкими данными, предположим, что одно такое ядро обработает 2 000 rps. Возьмем 4 ядра. Тогда для 400 000 rps для подгрузки подписчиков для формирования ленты (просмотра подписок/подписчиков пользователя), понадобится 400 000 / 8 000 = 50 серверов. Всего прийдется хранить 5 Тб. данных. На 1 сервер выходит 5 000 / 50 = 100 Гб. Возьмем с запасом SSD диск на 128 Гб.

    Используем 12 мастеров и 2 реплики на каждого.

    Кол-во CPU RAM, Гб. Disk Network, Гб
    50 8 16 128 Гб. SSD 10
  • Posts

    Всего на посты тратится 58.5 Пб. места. Из 58 Пб. не вложений будут 50 000 000 000 х 0.05 (описание) = 2.5 Пб.

    Исходя из бенчмарков, предположим, что одно ядро обрабатывают 1 000 запросов. Для 16 CPU * 1 000 = 16 000 запросов использует один сервер. Понадобится 900 000 rps / 16 000 = 56 сервера.

    Считаем место шардов: 2 500 Тб. / 56 = 44 Тб. Возьмем 64 Тб. HDD. Также берем 256 RAM на индексы.

    Используем 56 мастера и по 2 реплики на каждый мастер. Итого, имеем 56 * 2 = 112 серверов на посты.

    Кол-во CPU RAM, Гб. Disk Network, Гб
    112 16 256 64 Тб. HDD 10
  • Likes

    Лайков всего на 800 Тб. Будет очень частая запись и более редкое чтение. 100 000 rps.

    Запросы легковесные, предположим, что 1 ядро обработает 2 000 запросов в секунду. 4 ядра обработают 8 000 запросов. 100 000 / 8 000 = 12 серверов.

    На шарды 800 Тб. / 12 = 66 Тб. Имеет смысл взять SSD диск на 128 Гб.

    12 серверов будут на запись - Мастер, 2 реплики на каждый мастер. Итого, выходит 12 + 12 * 2 = 36 сервера.

    Кол-во CPU RAM, Гб. Disk Network, Гб
    36 4 128 128 Гб. SSD 128
  • Comments

    Комментариев на 1.2 Пб. Будет редкая запись и частое чтение. 10 000 rps.

    Запросы чуть тяжелее лайков, предположим, что 1 ядра обработают 1 000 запросов. 10 000 / 1 000 = 10 серверов.

    На шарды 1 200 Тб. / 10 = 120 Тб. Берем 144 Тб. RAID на HDD.

    10 серверов будут на запись - Мастер, 2 реплики на каждый мастер. Итого, выходит 30 серверов. 128 Гб. RAM на индексы, 4 CPU.

    Кол-во CPU RAM, Гб. Disk Network, Гб
    30 4 128 144 Гб. HDD 128

Redis

Запросов будет поступать 1 000 000 в секунду на пике. Redis хранит все в оперативной памяти. Возьмем 256 Гб. RAM, SSD диск на 256 Гб, 32 CPU. Предположим, что один такой сервер сможет справится с нагрузкой в 1 000 rps. Всего понадобится 33 сервера. Также выделим по 2 реплики на каждый сервер. Итого, 33 * 3 = 99 сервера.

Кол-во CPU RAM, Гб. Disk Network, Гб
99 32 256 256 Гб. SSD 64

Memcached

Кэшируем только табличные данные. Возьмем для каждой таблицы 10% от общего объема, чтобы записывать только самые популярные ответы на запросы. Посчитаем место:

0.1 x (2 500 + 7 900 + 800 + 1 280) = 1 248 Гб.

Предположим, что одно ядро обработает 2 000 запросов за секунду. Возьмем 16 - 32 000 запросов в секунду. 900 000 rps / 32 000 ~= 30 серверов. Каждый из них будет хранить 1 248 / 30 = 41 Гб. данных. Храним в оперативке, выделяем 64 Гб. с запасом.

Кол-во CPU RAM, Гб. Disk Network, Гб
30 16 64 128 Гб. 128

S3

Фото

Размер фотографий = 0.0003 х 50 000 000 000 х 0.75 = 11 250 Тб. = 11.25 Пб

Максимальный размер бакета будет 5 Тб. Тогда всего бакетов:

11 250 / 5 = 2250 бакетов

Аватарки

Размер аватарки = 100 Кб. х 2 000 000 000 х 0.8 = 160 Тб. Размер бакетов:

160 / 5 = 32 бакета

Видео

Размер видео = 58.5 - 11.25 = 47.25 Пб. Размер бакетов:

47 250 / 5 = 9 450 бакетов

Резюмируя, представлю полученные данные в таблице:

Кластер Кол-во серверов CPU RAM, Гб Диск, Гб
Nginx 219 32 64 128 (SSD)
Gateway 440 32 128 128 (SSD)
Auth microservice 14 64 64 128 (SSD)
Users microservice 260 32 64 128 (SSD)
Posts microservice 190 32 64 128 (SSD)
Attachments microservice 270 32 64 128 (SSD)

Для БД:

Кластер Кол-во серверов CPU RAM, Гб Диск, Гб
Users PostgreSQL 168 16 128 188 Гб. в RAID (HDD)
Followers PostgreSQL 50 8 16 128 Гб. (SSD)
Posts PostgreSQL 112 16 256 64 Тб. в RAID (HDD)
Likes PostgreSQL 36 4 128 144 Гб. (HDD)
Comments PostgreSQL 30 4 128 144 Гб. (HDD)
S3 100 30 128 Фото: 2 282 бакета, Видео: 9 450 бакетов
Redis 99 32 256 256 Гб (SSD)
Memcached 30 16 64 128 Гб (SSD)

CDN сервера

Для более быстрого доступа к контенту будем использовать CDN сервера. Выделим список стран и кол-во серверов, где их будем размещать исходя из ананлиза аудитории:

Страна Суммарный трафик, Гбит/с
США 0.16 * 1 892 = 302
Индия 0.11 * 1 892 = 208
Бразилия 0.1 * 1 892 = 189
Япония 0.01 * 1 892 = 19
Австралия 19
Турция 19
Британия 10

Источники

  1. Статистика по пользователям
  2. Количество пользователей в месяц
  3. Количесвто пользователей в день
  4. Лайки и комментарии
  5. Среднее время проведенное пользователем
  6. Битрейт видео
  7. Количество постов
  8. Nginx нагрузка

About

Highload Course Project of designing Instagram

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published