- 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 |
- Создание, редактирование, просмотр профиля;
- Публикация фото и видео с продолжительностью не более 60 секунд;
- Возможность поставить лайк и оставить комментарий к посту;
- Возможность подписаться на пользователя;
- Возможность просматривать ленту с подписками.
- Месячная аудитория: 2 биллиона [1];
- Дневная аудитроия: 500 миллионов [2];
- Среднее время онлайна пользователя - 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 Гб/сутки
Уже по полученным данным посчитаем кол-во запросов в секунду в среднем:
- Регистрация/Авторизация:
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 |
- Пользователи (users) - таблица со всеми необходимыми данными о пользователе.
- Primary key: id пользователяj
- Посты (posts) - таблица с постами пользователями, которая включает в себя все необходимое для отображения поста.
- Primary key: id поста;
- Foreign key: user_id.
- Лайки (likes) - таблица с информацией, что i-й пользователь поставил лайк j-му посту.
- Foreign key: user_id, post_id.
- Комментарии (comments) - таблица с информацией, что i-й пользователь поставил лайк j-му посту с непустым сообщением.
- Foreign key: user_id, post_id.
- Подписки (subscriptions) - таблица с информацией о том, что i-й пользователь подписан на j-го.
- Foreign key: creator_id, follower_id.
- Сессии (sessions) - таблица со всеми сессиями пользователей.
- Foreign key: user_id.
-
Сессии пользователей
Сессии пользователей будут очень часто изменяться по очевидным причиам. Из-за этого нужно осуществить быстрый доступ на получение текущих пользователей, быстрое удаление и добавление. Таким образом их лучше всего хранить в оперативной памяти, с чем прекрасно будет справляться нереляцонная in-memory база данных -
Redis
. В данном случае, ключом будет значение сессии, а значением - id пользователя и дата истечения сессии. -
Пользователи и посты
Пользователи же будут находиться в реляционной базе
PostgreSQL
, так как она представляет возможность делать сложные запросы, устанавливать отношения для легкой организации и связывания данных, а также поддерживает обширный функционал для масштабирования. Однако аватарки пользователей хранить там же не представляется возможным за счет большого размера картинок всех пользователей, что будет заметно замедлять работу базы. Поэтому для хранения аватарок будет использоватьсяS3-хранилище
, который имеет высокую скорость чтения, высокую доступность и долговечных данных. В самой же реляционной базе будем хранить ссылку на картунку в S3.Аналогично пользователям данные постов будем хранить в
PostgreSQL
, а картинки/видео вS3-хранилище
. -
Комментарии, лайки, подписки
Данные хорошо ложатся на реляционную модель, поэтому будем хранить их в
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.
-
Authorization microservice
Этот микросервис будет отвечать за сессии пользователей. Как говорилось выше, он будет ходить в кластер Редиса. Сам редис будет реплицировать данные для поддержания отказоустойчивости и быстро возвращать сессии нужному узлу микросервиса. Микросервис будет определять к какому шарду нужно будет обратиться.
Все микросервисы будут управляться Kubernetes, метрики отправляются в свой кластер Prometheus. У каждой базы тоже будет свой сборщик метрик. Все метрики в последствии будут отпрвляться в Grafana.
-
Users microservice
Будет хоить в кластер базы Постгреса, особенности работы которой были описаны выше. На основе range-based шардирования определит, в какой узел ему идти. Сам микросервис будет ходить в базу для получения всех метаданных пользователя.
-
Posts microservice
Также ходит в Постгрес. В зависимости от запроса будет обращаться к шарду по принципу времени создания или по ранжированию. Стоит учесть, что в базу он будет ходить лишь за метаданными постов, сам контент будет получаться в микросервисе Attachments.
-
Attachment microservice
Ходит в кластер S3-хранилища. Для более быстрой работы будет настроена контентная адресация, позволяящая определить, к какому узлу обратиться. Внутри него в базе Редиса будет проверяться кэш. Если в кэше ничего нет, ищем информацию в хранилище S3.
Для загрузки фото/видео на базу стоит поставить брокер очередей
RabbitMQ
. За счет него сможем выполнять запросы отложенно. Это важно, потому что загрузка контента занимает какое-то время, а сам пост отобразиться, когда обработается и сохранится. -
Feed microservice
В силу того, что система имеет ключевой функционал, являющийся генерацией ленты, нужен сервис, отвечающий за это. В нем будет происходить логика формирования ленты индивидуально для каждого полдьзователя.
Так как загрузка ленты является самым большим по rps запросу, стоит продумать, как она будет формироваться. Опишу общую логику на получение ленты в архитектуре:
-
Когда пользователь запрашивает свою ленту, запрос сначала попадает на API Gateway.
-
API Gateway проверяет авторизацию пользователя, используя микросервис Authorization. Если пользователь не авторизован, возвращается ошибка.
-
После успешной авторизации API Gateway отправляет запрос на микросервис Feed. На этом этапе сервис ходит в базу, проверяет наличие id пользователя в ней. Это так называемый кэш, в котором будут находиться предопределенные id постов, которые нужно подгрузить в ленте.
-
В случае, если в кэше ничего не нашлось, сервис пойдет в сервис пользователей, где возьмет всех пользователей, на которых подписан человек (по схеме, описанной выше). Полученные данные пойдут в сервис постов, где возьмутся посты людей за определенный промежуток времени (за оптимальность также отвечает индекс для даты, описанный выше) и отсортируются по дате. Полученная инфорация сохраниться в кэш ленты.
-
После получения id постов, которые нужно получить, идем сначала в сервис постов для получения метаданных, а затем в сервис attachments, где и получим сам контент. Результат возвращается клиенту.
Для наглядности представлю ключевую часть схемы генерации ленты:
Опишу ключевые моменты. Начну с добавления поста. Как видно на схеме, запрос, проходя через слой Gateway, идет в сервис постов, а затем добавляет метаданные в базу, потом запрос кладется в брокер очереди, который будет идти в сервис attachments для загрузки контента, а также в сервис ленты, чтобы уведомить сервис о том, что у пользователя N появилась новая фотография. Далее этот сервис будет ходить в базу Memcached, чтобы добавить всем пользователям, которые подписаны на человека только что загрузившего пост, id этого поста.
Брокер очередей для загрузки поста нужен для отложенной обработки, так как нет необходимости подгружать пост моментально всем. Автору же пост подгрузится моментально на уровне фронтенда.
Таким образом при генерации ленты у пользователя будет смотреться кэш текущих id постов и затем идти в базу для отдачи этих постов. Учитывая, что запросы к постам пойдут с большой вероятностью на разные шарды. Можно это ускорить с помощью параллельных вычислений, но этодовольно тяжело реализовать программно.
Опишу логический план запроса для каждого типа запроса с клиента.
-
Запрос на создание нового поста
- Клиент отправляет запрос на создание нового поста через API Gateway.
- API Gateway перенаправляет запрос к микросервису Attachments.
- Далее идем в S3 хранилище и ставим запрос в брокер очередей.
- После сохранения изображения возвращаемся в Gateway и идем в Posts.
- Микросервис Posts сохраняет информацию о посте и формирует ответ с идентификатором созданного поста и отправляет его обратно клиенту через API Gateway.
-
Запрос на получение информации о пользователе
- Клиент отправляет запрос на получение информации о пользователе через API Gateway.
- API Gateway перенаправляет запрос к микросервису Users.
- Микросервис Users получает информацию о пользователе из базы данных с учетом шардирования.
- Микросервис Users формирует ответ с информацией о пользователе и отправляет его обратно клиенту через API Gateway.
-
Запрос на получение списка подписок/подписчиков пользователя
- Клиент отправляет запрос на получение списка подписок или подписчиков пользователя через API Gateway.
- API Gateway перенаправляет запрос к микросервису Users.
- Микросервис Users получает информацию о подписках/подписчиках пользователя из базы данных с учетом шардирования.
- Микросервис Users формирует ответ со списком подписок/подписчиков и отправляет его обратно клиенту через API Gateway.
-
Запрос на поиск пользователя
- Клиент отправляет запрос на поиск пользователя через 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 |
Задача 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 |
-
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 -
Users microservice
В этот компонент будут попадать следующие значимые запросы: поиск пользователей, поиск подписок/подписчиков, получение пользователя по id и т. д. Стоит учесть, что каждый запрос на пост сопровождается походом в users для получения автора поста. Из этого сделаем вывод, что нагрузка на пользователей будет больше, чем на посты, так как будут учитываться дополнительно поиск пользователя, переход на него из поста и т.д. Таким образом все типы запросов кроме авторизации будут использовать этот микросервис. Так как уже было посчитано кол-во серверов для обработки всех запросов, возьмем чуть меньше -
260
серверов с 32 CPU, 64 Гб. RAM и 16 Гб. сетевой емкости.Кол-во CPU RAM, Гб. Disk Network, Гбит/с 260 32 64 128 Гб. 16 -
Posts microservice
Считаем запросы, которые связаны только с постами: просмотр ленты, проставление лайков, оставление комментариев, публикация фото/видео - 950 000 rps. Таким образом выделяем при учете бенчмарков, учитывая, что 32 ядра смогут обрабатывать 5 000 запросов в секунду, 950 000 / 5 000 = 190 серверов.
Кол-во CPU RAM, Гб. Disk Network, Гбит/с 190 32 64 128 Гб. 32 -
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
-
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
Запросов будет поступать 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 |
Кэшируем только табличные данные. Возьмем для каждой таблицы 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 |
Размер фотографий = 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 сервера. Выделим список стран и кол-во серверов, где их будем размещать исходя из ананлиза аудитории:
Страна | Суммарный трафик, Гбит/с |
---|---|
США | 0.16 * 1 892 = 302 |
Индия | 0.11 * 1 892 = 208 |
Бразилия | 0.1 * 1 892 = 189 |
Япония | 0.01 * 1 892 = 19 |
Австралия | 19 |
Турция | 19 |
Британия | 10 |