Репозиторий курсовой работы по высоконагруженным системам от VK Education (ex. Технопарк)
- HighLoad
- 1. Тема и целевая аудитория
- 2. Расчет нагрузки
- 3. Глобальная балансировка нагрузки
- 4. Локальная балансировка нагрузки
- 5. Логическая схема БД
- 6. Физическая схема БД
- 7. Алгоритмы
- 8. Технологии
- 9. Обеспечение надёжности
- 10. Схема проекта
- 11. Список серверов
- Список использованных источников
Reddit — это крупнейшая социальная платформа и агрегатор новостей, контента и дискуссий, основанная на пользовательских сообществах.
-
Число активных пользователей
-
Целевая аудитория4
-
Требования к функционалу
- MVP:
- Регистрация и авторизация
- Создание и управление сообществами
- Подписка на сообщества
- Публикация и редактирование постов
- Комментарии к постам
- Система голосования (upvote/downvote)
- Рекомендательная лента
- Чат
- MVP:
| Метриика | Значение |
|---|---|
| MAU | 860 млн |
| DAU | 101 млн |
-
В среднем пользователь авторизируется 1 раз в месяц, следовательно в день получается 1 / 30 = 0.03 раза.
-
В 2022 году среднее число ежемесячно созданных сабреддитов было равно 45975 5, значит, если предположить, что в 2024 число такое же, то в день создается примерно 45975 / 30 = 1533 сабреддита, а один пользователь создает 1533 * 10^-6 / 101 = 0.00002 сабреддита в день.
-
В среднем пользователь подписан на 15 сабреддитов 6. Новые пользователи, как правило, подписываются на несколько сабреддитов сразу после регистрации. В 2024 зарегистрировалось 30.2 млн новых пользователей7, следоватлеьно в месяц 30.2:12 = 2.52 млн новых пользователей. Предположим, что новый пользователь подписывается сразу на 10 сабреддитов, тогда 2.52 * 10 = 25.2 млн подписок в месяц от новых пользователей. Число существующих (не новых) пользователей в месяц 860 - 25.2 = 834.8 млн. Предположим, что 10% этих пользователей добавляют 1 новую подписку в месяц, тогда это ещё 834.8 * 0.1 * 1 = 83.48 млн подписок в месяц. Таким образом, общее число подписок на сабреддиты в месяц составляет 25.2 + 83.48 = 108.68 млн. Тогда один пользователь в день совершает 108.68:30:101=0.04 подписок.
-
В 2022 году было опубликовано 492.3 млн постов 6. Допустим в 2024 число такое же, тогда в день 492.3:365 = 1.35 млн постов, следовательно один пользователь создает 1.35 : 101 = 0.01 пост в день.
-
В 2022 году было оставлено 2.72 млрд комментариев 8. Так же допускаем, что в 2024 году число осталось тем же, тогда в день 2720 : 365 = 7.45 млн комментариев, а один пользователь оставляет 7.45: 101 = 0.07 комментария в день.
-
Количество голосов, оставленных пользователями, не разглашается, поэтому, предположим, что каждый пользователь оставляет по 5 голосов в день.
-
Средняя продолжительность сессии пользователя составляет 12.38 минут 9, предположим, что за день пользователь проводит 3 сессии и среднем тратит 0.2 минуты на пост, тогда среднее число просмотренных постов в день составляет 12.38*3:0.2 = 185.7.
-
Среднее количество сообщений, отправляемых ежемесячно, составляет 2.61 млдр 10, соотвественно в день 2610:30=87 млн. Тогда каждый пользователь отправляет 87:101 = 0.86 сообщений ежедневно.
Действие Количество Атворизация 0.03 Создание сабреддита 0.00002 Подписка на сабреддит 0.04 Публикация постов 0.01 Написание комментариев 0.07 Оценка постов и комментариев 5 Просмотр постов 185.7 Отправка сообщений 0.86
- В каждом профиле содержится аватрака и текстовое описание. Аватрака, загруженная пользователем, автоматически рескейлится до разрешения 256 х 256 px, занимая в срденем 10 КБ. Срденяя длина текстового описания составляет 100 символов, в кодировке utf-8 один символ может занимать от 1 до 4 байтов, предположим, что средний размер одного символа равен 2 байтам. Тогда размер одного профиля будет составлять 10 КБ + (100 * 2 / 1024) КБ = 10.19 КБ = 0.001 МБ.
- Для хранения одной подписки требуется около 30 байт. В среднем у пользователя 20 подписок на сабреддиты, значит общий объем памяти, необходимый для их хранения 30 * 20 = 600 байт = 0.0006 МБ.
- Будем считать, что для хранения записи о создателе сабреддита нужно столько же памяти, что и для подписки, то есть 30 байт. Так как узнать среднее количество созданных пользователем сабреддитов нельзя, будем использовать то же соотношение, что в и подписках, то есть 20 / 0.04 = 500, значит в среднем пользователь будет являться создателем 0.00002 * 500 = 0.01 сабреддита. Тогда для хранения потребуется 30 * 0.01 = 0.3 байта = 0.3 * 1024-2 МБ.
- Посты:
- Медиа данные:
- В 35% опубликованных постов содержатся изображения, средний размер которых составляет 350 КБ = 0.34 МБ (для изображения 1920х1080).
- В 15% опубликованных постов содержится видео, средняя продолжительность которого составляет 38 секунд. Одна секунда видео в разрешении 720p занимает примерно 3 Мбит, следовательно полное видео будет занимать 38 * 3 = 114 Мбит = 14.25 МБ.
- Текстовые данные
- В каждом посте есть заголовок, средняя длина которого составляет 50 символов, в кодировке utf-8 один символ может занимать от 1 до 4 байтов, предположим, что средний размер одного символа равен 2 байтам. Тогда размер заголовка будет составлять 50 * 2 = 100 Б = 0.0001 МБ
- В 80% опубликованных постов есть текстовое описание, средняя длина которого составляет 900 символов, каждый из которых кодируется 2 байтами. Тогда размер описания будет составлять 900 * 2 = 1800 Б = 0.002 МБ
- Общий размер поста будет составлять 0.34 * 0.35 + 14.25 * 0.15 + 0.0001 + 0.002 * 0.8 = 2.26 МБ. В среднем каждый пользователь имеет 5 опубликованных постов, значит объем памяти, необходимый для их хранения, составляет 2.26 * 5 = 11.3 МБ.
- Медиа данные:
- Средняя длина комментария составляет 100 символов, каждый из которых кодируется 2 байтами. Тогда размер комментария будет составлять 100 * 2 = 200 Б = 0.0002 МБ. В среднем каждый пользователь имеет 35 комментариев, значит объем памяти, необходимый для их хранения, составляет 0.0002 * 35 = 0.007 МБ.
- Для хранения одного голоса требуется около 31 байт. В среднем у пользователя 1000 голосов, общий объем памяти, необходимый для их хранения 31 * 1000 = 3100 байт = 0.031 МБ.
- Для медиа данных сообщений возьмем те же рассчеты, что и для поста, скорректировав проценты: предположим, что в 2% отправленных сообщений содержатся изображения и в 0.5% видео. Средний размер текста сообщения равен 100 символам, что занимают 0.0002 МБ, как было показано ранее. Тогда общий размер сообщения равен 0.34 * 0.02 + 14.25 * 0.005 + 0.0002 = 0.08 МБ. В среднем у пользователя есть 430 сообщений, тогда общий объем памяти, необходимый для их хранения 0.08 МБ * 430 = 34.4 МБ.
| Тип | Количество | Размер, МБ |
|---|---|---|
| Профиль | 1 | 0.001 |
| Созданные сабреддиты | 0.01 | 0.3 * 1024-2 |
| Подписки | 20 | 0.0006 |
| Посты | 5 | 11.3 |
| Комментарии | 35 | 0.007 |
| Голоса | 1000 | 0.031 |
| Сообщения | 430 | 34.4 |
| Итого | 1491.01 | 45.74 |
В 2024 году количество новых пользователей составили 219 млн человек 7, соответственно, взяв средний размер хранилища пользователя из предыдущего пункта, получим, что ежегодно объем хранилища будет увеличиваться на 219 млн * 45.74 МБ = 10017.68 млн МБ = 10.09 ПБ.
-
Число всех зарегистрированных пользователей равно 1.72 млрд, соответсвенно для хранения всех профилей понадобится 1720 * 0.001 = 1.72 млн МБ = 0.0016 ПБ.
-
Общее число сабреддитов на момент 2022 года составляло 3.4 млн 5, с учетом ежемесясного роста числа сабреддитов на 45975 5, получим, что в 2024 году общее число сабреддитов составит 3.4 млн + (45975 * 12 * 2) = 4.5 млн. Тогда размер памяти для хранения записей о создании сабреддитов будет составлять 4.5 * 0.3 * 1024-2 = 1.29 * 10-6 млн МБ = 1.2 * 10-9 ПБ.
-
Общее число всех подписок неизвестно, поэтому посчитаем его исходя из общего количества зарегистрированных пользователей, равного 1.72 млрд, и предположения, сделанного ранее, что у среднего пользователя объем памяти, необходимый для хранения подписок, равен 0.0006 МБ. Тогда 1720 * 0.0006 = 1.3 млн МБ = 0.001 ПБ.
-
Аналогично предыдущему пункту для постов получим 1720 * 11.3 = 19436 млн МБ = 18.1 ПБ.
-
Для комментариев 1720 * 0.007 = 12.04 млн МБ = 0.011 ПБ.
-
Для голосов 1720 * 0.031 = 53.32 млн МБ = 0.049 ПБ.
-
Для сообщений 1720 * 34.4 = 59168 млн МБ = 51.21 ПБ.
Тип Размер, ПБ Профили пользователей 0.0016 Сабреддиты 1.2 * 10-9 Подписки 0.001 Посты 18.1 Комментарии 0.011 Голоса 0.049 Сообщения 51.21 Итого 69.37
Формула: Среднее потребление = Трафик на действие * RPS
Пиковое потребление = 1.7 * Среднее потребление
Суммарный суточный трафик = Трафик на действие * Количество запросов в день от одного пользователя * DAU
-
Авторизация:
- Среднее потребление: 2.8 КБ * 8 * 35.07 ≈ 785.344 Кбит/с ≈ 0.000785 Гбит/с
- Пиковое потребление: 1.7 * 0.000785 ≈ 0.001335 Гбит/с
- Суммарный суточный трафик: 2.8 КБ * 0.03 * 101000000 ≈ 8484000 КБ ≈ 8.484 ГБ
-
Создание сабреддита:
- Среднее потребление: 2.5 КБ * 8 * 0.02 ≈ 0.4 Кбит/с ≈ 0.0000004 Гбит/с
- Пиковое потребление: 1.7 * 0.0000004 ≈ 0.00000068 Гбит/с
- Суммарный суточный трафик: 2.5 КБ * 0.00002 * 101000000 ≈ 5050 КБ ≈ 0.005 ГБ
-
Подписка на сабреддит:
- Среднее потребление: 1.8 КБ * 8 * 46.76 ≈ 673.344 Кбит/с ≈ 0.000673 Гбит/с
- Пиковое потребление: 1.7 * 0.000673 ≈ 0.001144 Гбит/с
- Суммарный суточный трафик: 1.8 КБ * 0.04 * 101000000 ≈ 7272000 КБ ≈ 7.272 ГБ
-
Публикация постов:
- Среднее потребление: 28.8 КБ * 8 * 11.69 ≈ 2693.376 Кбит/с ≈ 0.002693 Гбит/с
- Пиковое потребление: 1.7 * 0.002693 ≈ 0.004578 Гбит/с
- Суммарный суточный трафик: 28.8 КБ * 0.01 * 101000000 ≈ 28800000 КБ ≈ 28.800 ГБ
-
Написание комментариев:
- Среднее потребление: 5.5 КБ * 8 * 81.83 ≈ 3600.52 Кбит/с ≈ 0.003601 Гбит/с
- Пиковое потребление: 1.7 * 0.003601 ≈ 0.006122 Гбит/с
- Суммарный суточный трафик: 5.5 КБ * 0.07 * 101000000 ≈ 38885000 КБ ≈ 38.885 ГБ
-
Оценка постов и комментариев:
- Среднее потребление: 2.5 КБ * 8 * 5844.91 ≈ 116898.2 Кбит/с ≈ 0.116898 Гбит/с
- Пиковое потребление: 1.7 * 0.116898 ≈ 0.198727 Гбит/с
- Суммарный суточный трафик: 2.5 КБ * 5 * 101000000 ≈ 1262500000 КБ ≈ 1262.500 ГБ
-
Просмотр постов:
- Среднее потребление: 16 КБ * 8 * 14472 ≈ 1852416 Кбит/с ≈ 1.85 Гбит/с
- Пиковое потребление: 1.7 * 1.85 ≈ 3.145 Гбит/с
- Суммарный суточный трафик: 16 КБ * 12.38 * 101000000 ≈ 20006080000 КБ ≈ 20006.08 ГБ
-
Отправка сообщений:
- Среднее потребление: 0.916 КБ * 8 * 1005.32 ≈ 7366.984 Кбит/с ≈ 0.007367 Гбит/с
- Пиковое потребление: 1.7 * 0.007367 ≈ 0.012524 Гбит/с
- Суммарный суточный трафик: 0.916 КБ * 0.86 * 101000000 ≈ 79676560 КБ ≈ 79.677 ГБ
| Действие | Трафик на действие | Среднее потребление, Гбит/с | Пиковое потребление, Гбит/с | Суммарный суточный трафик, ГБ |
|---|---|---|---|---|
| Авторизация | 2.8 КБ | 0.000785 | 0.001335 | 8.484 |
| Создание сабреддита | 2.5 КБ | 0.0000004 | 0.00000068 | 0.005 |
| Подписка на сабреддит | 1.8 КБ | 0.000673 | 0.001144 | 7.272 |
| Публикация постов | 28.8 КБ | 0.002693 | 0.004578 | 28.800 |
| Написание комментариев | 5.5 КБ | 0.003601 | 0.006122 | 38.885 |
| Оценка постов и комментариев | 2.5 КБ | 0.116898 | 0.198727 | 1262.500 |
| Просмотр постов | 16 КБ | 1.85 | 3.145 | 20006.08 |
| Отправка сообщений | 0.916 КБ | 0.007367 | 0.012524 | 79.677 |
Формула: RPS = (Количество запросов в день от одного пользователя * DAU) / 86400 секунд
Пиковое RPS = 1.7 * RPS
-
Авторизация:
- RPS = (0.03 * 101000000) / 86400 ≈ 35.07
- Пиковое RPS: 35.07 * 1.7 ≈ 59.62
-
Создание сабреддита:
- RPS = (0.00002 * 101000000) / 86400 ≈ 0.02
- Пиковое RPS: 0.02 * 1.7 ≈ 0.03
-
Подписка на сабреддит:
- RPS = (0.04 * 101000000) / 86400 ≈ 46.76
- Пиковое RPS: 46.76 * 1.7 ≈ 79.49
-
Публикация постов:
- RPS = (0.01 * 101000000) / 86400 ≈ 11.69
- Пиковое RPS: 11.69 * 1.7 ≈ 19.87
-
Написание комментариев:
- RPS = (0.07 * 101000000) / 86400 ≈ 81.83
- Пиковое RPS: 81.83 * 1.7 ≈ 139.11
-
Оценка постов и комментариев:
- RPS = (5 * 101000000) / 86400 ≈ 5844.91
- Пиковое RPS: 5844.91 * 1.7 ≈ 9936.35
-
Просмотр постов:
- При каждом запросе отправляется по 15 постов, соответственно среднее количество запросов 185.7 / 15 = 12.38
- RPS = (12.38 * 101000000) / 86400 ≈ 14472
- Пиковое RPS: 14472 * 1.7 ≈ 24602.4
-
Отправка сообщений:
- RPS = (0.86 * 101000000) / 86400 ≈ 1005.32
- Пиковое RPS: 1005.32 * 1.7 ≈ 1709.04
| Тип запроса | Среднее RPS | Пиковое RPS |
|---|---|---|
| Авторизация | 35.07 | 59.62 |
| Создание сабреддита | 0.02 | 0.03 |
| Подписка на сабреддит | 46.76 | 79.49 |
| Публикация постов | 11.69 | 19.87 |
| Написание комментариев | 81.83 | 139.11 |
| Оценка постов и комментариев | 5844.91 | 9936.35 |
| Просмотр постов | 14472 | 24602.4 |
| Отправка сообщений | 1005.32 | 1709.04 |
| Итого | 21497.6 | 36545.91 |
- www.reddit.com — основной домен, где находится основная часть контента
- m.reddit.com — мобильная версия сайта
- mod.reddit.com — инструменты для модераторов
- api.reddit.com — API для разработчиков.
- oauth.reddit.com — используется для OAuth-аутентификации.
Чуть больше половины пользователей reddit (57.23%) находятся в северной америке 11, следовательно большая часть ДЦ будет располагаться там. Также большое количество пользователей (~20.14%) располагаются в Европе, а именно в Великобритании, Германии, Франции, Швеции, Испании, Нидерландах, Италии 11. Еще заметное число пользователей (5.18%) находятся в Индии. В Австралии располагается 3.54% пользоватлей. В южной америке, а именно в Бразилии и Аргентине, находится 4.75% пользоватлей 11.
| Регион | Страны | Доля пользователей Reddit |
|---|---|---|
| Северная Америка | США, Канада | 57.23% |
| Европа | Великобритания, Германия, Франция, Швеция, Испания, Нидерланды, Италия | 20.14% |
| Индия | Индия | 5.18% |
| Австралия | Австралия | 3.54% |
| Южная Америка | Бразилия, Аргентина | 4.75% |
Так как большинство пользователей находятся в США, проведем анализ численности населения по штатам 12:
Самые густонасленные штаты:
- Калифорния - 39.5 млн
- Техас - 28.7 млн
- Флорида - 21.3 млн
- Нью-Йорк - 19.5 млн
Для них стоит расположить ДЦ в самых населенных городах. Для менее густонаселенных участков расположим один ДЦ на несколько штатов. Таким образом спсиок городов с ДЦ в США будет иметь вид:
- Лос-анджелес
- Хьюстон
- Маями
- Нью-Йорк
- Денвер
- Сиэтл
- Сент-Луис
Для остальных стран расположим по 1 ДЦ в самых густонаселенных городах:
- Эдмонтон
- Лондон
- Берлин
- Мадрид
- Рим
- Нью Дели
- Сидней
- Бразилиа
Интерактивная карта: https://yandex.ru/maps/?um=constructor%3Abf2ab49a37b44b80fba2b2012349a15d68757823babed98b1eb5aec839e83e00&source=constructorLink
Формула: Пиковый RPS * % всех пользователей / 100
| Страна | % всех пользователей | Суммарный RPS на страну |
|---|---|---|
| США | 50.36 | 15156.60 |
| Великобритания | 9.93 | 2979.69 |
| Германия | 7.64 | 2299.46 |
| Канада | 6.9 | 2076.66 |
| Франция | 6.84 | 1964.74 |
| Индия | 5.18 | 1558.99 |
| Австралия | 4.07 | 1224.93 |
| Бразилия | 3.65 | 1098.53 |
Ввиду масштаба и требования к высокой доступности, производительности и отказоустойчивости для reddit можно применить Geo-based DNS, который должен обеспечить направление пользователя на ближаший ДЦ. Однако данный метод не может гарантировать минимальную задержку, так как не учитывает загруженность ДЦ. Для решения этой проблемы можно использовать Latency-based DNS, который отправляет пользователя на ДЦ с минимальной задержкой.
- Входящий трафик будет балансироваться с помощью Virtual Server via Direct Routing, что позволит значительно снизить трафик, проходящий через балансировщик. CARP (Common Address Redundancy Protocol) объединяет несколько устройств в группу с одинм IP-адресом, определяя master устройство, которое обрабатывет трафик, поступающий на назначенный IP-адрес. Если master выходит из строя, то другое устройство из группы возьмет на себя его обязанности. Чаще всего группы состоят из двух устройств. Также каждый хост одновременно может принадлежать к нескольким группам.
- Далее трафик поступает на Ngnix, который выступает HTTP Reverse Proxy балансировщиком. Nginx предоставляет возможность SSL-терминации, кэширования и сжатия ответов от серверов-источников, облегчая нагрузку внутренних серверов.
- Далее трафик поступает в один из кластеров Kubernetes, где с помощью Ingress nginx направляется к соответствущим сервисам кластера.
Для отказоустойчивости будут применяться инструменты k8s и nginx. Kubernetes с помощью readiness-проб обеспечит исключение из кластера упавших подов и добавление новых, а также сможет автоматически поднимать упавшие сервера. Kubernetes также позволит выполнять удобный auto-scaling, чтобы подстраиваться под актуальную нагрузку. Nginx умеет выполнять retry запросов после падения бэкенда, перезапускать web-сервера без downtime, равномерно распределять запросы по бэкендам, а также незаметно для пользователя перезагружать конфиг при обновлениях.
Среднее время выполнения SSL-рукопожатия может варьироваться от 2 мс при использовании сокращённого рукопожатия до 11 мс при полном рукопожатии 13. Для последующих расчётов будем учитывать, что SSL-рукопожатие занимает 3 мс, так как мы планируем использовать сокращённые рукопожатия в Nginx. Это означает, что сервер и клиент будут переиспользовать ранее установленную защищённую сессию с помощью механизма session tickets, что значительно сокращает время и нагрузку на процессор. Тогда, считая пиковый RPS равным 131355.32, получим, что на терминацию SSL будет затрачиваться 131355.32 * 3 = 394065,96 мс = 394.1 с процессорного времени в секунду.
| Таблица | Размеры данных | Консистентность |
|---|---|---|
| session | (16 token + 16 user_id + 8 expiration_datetime) * 860 млн. MAU = 32.04 ГБ | - |
| users | (16 id + 64 username + 256 email + 128 password_hash + 64 password_salt + 8 created_at + 8 updated_at) * 1720 млн. пользователей = 871.42 ТБ | При удалении пользователя удаляются все его данные: сессии, посты, комментарии, голоса, подписки, сообщения. |
| communities | (16 id + 32 name + 256 description + 16 creator_id + 8 created_at + 8 updated_at) * 4.5 млн сабреддитов = 1.41 ГБ | При удалении сообщества удаляются все связанные посты и подписки. |
| subscriptions | (16 user_id + 16 community_id + 8 created_at) * 1720 млн. пользователей * 20 подписок на пользователя = 1.25 ТБ | - |
| posts | (16 id + 32 title + 1024 content + 16 author_id + 16 community_id + 8 created_at + 8 updated_at) * 1720 млн. пользователей * 5 постов на пользователя = 8.76 ТБ | При удалении поста удаляются его комментарии, голосаи медиафайлы. |
| media | (16 id + 16 post_id + 128 file_url + 8 file_type + 8 created_at) * 8600 млн. постов * 0.5 медиафайла на пост = 704.82 ГБ | - |
| comments | (16 id + 512 content + 16 author_id + 16 post_id + 16 parent_comment_id + 8 created_at + 8 updated_at) * 1720 млн. пользователей * 35 комментария на пользователя = 32.41 ТБ | При удалении комментария удаляются все его голоса. |
| votes_comments | (16 id + 16 user_id + 16 comment_id + 8 vote_type + 8 created_at) * 1720 млн. пользователей * 100 голосов = 8.9 ТБ | - |
| votes_posts | (16 id + 16 user_id + 16 post_id + 8 vote_type + 8 created_at) * 1720 млн. пользователей * 200 голосов = 17.8 ТБ | - |
| messages | (16 id + 16 sender_id + 16 receiver_id + 512 content + 8 created_at) * 1720 млн. пользователей * 430 сообщения на пользователя = 382.07 ТБ | - |
| Таблица | Тип операции | Пиковый QPS |
|---|---|---|
| posts | Чтение | 24602 |
| Запись | 19.87 | |
| comments | Чтение | 12301 |
| Запись | 139.11 | |
| votes_ | Запись | 9936 |
| messages | Чтение | 854.52 |
| Запись | 1709 | |
| subscriptions | Запись | 79.49 |
| users | Чтение | 173.12 |
| Таблица | Индексы | Пояснение |
|---|---|---|
| posts | (community_id, created_at, is_deleted), (created_at, is_deleted) | Поиск постов сообщества. Сортировка постов сообщества по рейтингу. Глобальная лента новых постов. |
| subscriptions | (user_id, community_id), community_id | Быстрое получение сообществ, на которые подписан пользователь. Быстрый подсчет подписок сообщества. |
| comments | (post_id, created_at, is_deleted), (user_id, is_deleted) | Сортировка комментариев к посту по дате создания, рейтингу. Быстрое получение коменнтариев пользователя. |
| votes_comments | (comment_id, is_deleted) | Подсчет голосов для комментария |
| votes_posts | (post_id, is_deleted) | Подсчет голосов для поста |
| messages | (sender_id, receiver_id, created_at, is_deleted), (receiver_id, created_at, is_deleted) | Получение переписки между пользователями, входящих сообщений |
| posts/comments_total_votes | (post/comment_id) | Получение количества голосов поста/комментария |
| Таблица | Денормализованное поле/таблица | Источник | Пояснение | Размер |
|---|---|---|---|---|
| posts | author_username | users.username | Для избегания JOIN c users при отображении автора поста | 64 Б * 8.6 млрд. постов = 550 ГБ |
| community_name | communities.name | Для избегания JOIN c communities при отображении cообщества, в котором опубликован пост | 32 Б * 8.6 млрд. постов = 225 ГБ | |
| media | media.file_url | Для избегания JOIN c media при отправке ссылки на медиа файлы | 128 Б * 4.3 млрд. постов с медиа = 550 ГБ | |
| comments | author_username | users.username | Для избегания JOIN c users при отображении автора комментария | 64 Б * 17.2 млрд. комментариев = 1100 ГБ |
| subscriptions | communtiy_name | communities.name | Для избегания JOIN c communities при отображении cообществ, на которые подписан пользователь | 32 Б * 34.4 млрд. подписок = 1100 ГБ |
| communities | communities_member_count | subscriptions | Для избегания сложного COUNT в subscriptions | (16 + 8) Б * 4.5 млн. сообществ = 0.1 ГБ |
| post/comments | posts/comments_total_votes | votes_posts/comments | Для избегания сложного COUNT в votes | (16 + 8) Б * (8.6 + 17.2) млрд. постов и комментариев = 577 ГБ |
- posts, communities, users, meassages, subscriptions, votes_comments, votes_posts, comments: Данные с очень частой записью/чтением и большим объемом, соответственно, они требуют большой пропускной способности и легкого горизонтального масштабирования, что предоставляет Apache Cassandra.
- session: Очень большая частота обращения к данным для проверки сессии. Необходимо обеспечить минимальную задержку для проверки сессии, желательно иметь механизм автоматического удаления просроченных сессий, под такие тербования идеально подходит Redis.
- search_communities, search_comments, search_users, search_posts: Elasticsearch является стандартом для полнотекствого поиска в виду быстрого и морфологического поиска, удобства масшатибрования.
| Таблица | Шардирование | Резервирование | Пояснение |
|---|---|---|---|
| posts | По community_id (хеш) |
Cassandra RF=3 | Шардирование по сообществам для локализации данных. |
| votes_posts | По post_id (хеш) |
Cassandra RF=3 | Шардирование по постам для локализации данных. |
| votes_comments | По comment_id (хеш) |
Cassandra RF=3 | Аналогично votes_posts. |
| comments | По post_id (хеш) |
Cassandra RF=3 | Шардирование по постам для локализации данных. |
Для взаимодействия с базами данных используются клиентские библиотеки, обеспечивающие высокую производительность и поддержку асинхронных операций:
- Cassandra – gocql (Go)
- Redis – go-redis
Для оптимизации нагрузки на БД реализуются следующие механизмы балансировки:
- Cassandra – балансировка на уровне драйвера (Token-aware routing), встроенные механизмы распределения нагрузки
- Redis – Redis Cluster с автоматической маршрутизацией запросов, балансировка через Sentinel
Резервное копирование данных выполняется с учетом особенностей каждой СУБД:
- Cassandra – snapshot-based бэкапы, incremental SSTable бэкапы, резервное копирование commitlog
- Redis – кластерное резервирование
Этот алгоритм позволяет:
- Поднять свежее, пока его не «перелистали»
- Удержать то, что понравилось многим
- Затухать интерес к старому
- Дать шанс нишевому посту обойти шумный, если тот собирает и апвоуты, и даунвоуты
Сам алгоритм работает так:
- Берется разница между врменем публикации поста A и B - "нулевым" днем 8.12.2005 7:46:43 (1134028003 в секундах)
$$t_s = A - B$$ - Также находится разница между апвоутами U и даунвоутами D
$$x = U - D$$ - "Нормируем" оценку x
$$z= |x|, если |x| \geq 1; z = 0, если |x|=0$$ - Итоговый рейтинг вычисляется как
$$R = \log_{10}z + \frac{sign(x)t_s}{45000}$$
Анализируя данный алгоритм, можно выделить несколько особенностей:
- Время публикации имеет большое влияние на рейтинг и алгоритм будет ставить выше новые посты, а не старые
- При этом рейтинг не уменьшается при течении времени, но новые посты получат более высокий рейтинг, чем старые. Данный подход отличается от множества алгоритмов, где рейтинг уменьшается при течении времени.
Вот визуализация ретйинга для постов с одинаковыми голосами, но разным временем публикации:
Также в алгоритме используется десятичный логарифм, что приводит к тому, что первые 10 голосов будут иметь тот же вес, что и следующие 100, которые будут иметь тот же вес, что и следущие 1000 и тд. Без испольования логарифмичесокго масштаба рейтинг рассчитывался бы как:
А с использованием логарифма:
Такой подход позволяет не самым популярным постам все равно попадать в ленту, при этом сохраняя наивысший рейтинг у самых популярных постов. Также можно визуализировать влияние даунвоутов:
То есть на итоговый рейтинг влияет только разница апвоутов и даунвоутов, что делает популярные посты, понравившиеся далеко не всем пользователям, менее рейтинговыми. Соответственно лучше публиковать безобидные посты, которые, теоритически, не получат много отрицательных оценок.
Данная сортировка отличается от Hot для постов, так как ее создатель считал, что время публикации комментария не должно сильно влиять на его ранг. Рассмотрим действия алгоритма:
- Для начала находим общее число голосов, складывая апвоуты U и даунвоуты D:
$$n = U + D$$ - Если n = 0, то сразу возвращаем рейтинг 0. Иначе переходим к следующему шагу
- Далее определяем отношения числа апвоутов к общему числу голосов:
$$\hat{p} = \frac{U}{n}$$ - Обозначаем квантиль стандартного нормального распределения с уровнем 90% за z:
$$z=U_{0.9}=1.282$$ - Итоговый ретйинг будет считаться по формуле:
$$R = \frac{\hat{p} + \frac{1}{2n}z^2 - z\sqrt{\frac{\hat{p}(1-\hat{p})}{n} + \frac{z^2}{4n^2}}}{1+\frac{1}{n}z^2}$$
Данный алгоритм использует доверительный интервал Вилсона, который:
- Наказывает «тонкие выборки». Один лайк из 1 → 100 % апвоутов, но при n=1 интервал настолько широкий, что нижняя граница ≈0.20 — и комментарий не вылетает в топ. Но если у комментария 10 апвоутов и только 1 даунвоут, алгоритм может быть достаточно уверен в том, что его можно поставить выше комментария с 40 апвоутами и 20 даунвоутами - полагая, что к тому времени, когда он также получит 40 апвоутов, почти наверняка у него будет меньше 20 даунвоутами. И самое приятное, что если он неверен (а это случается в 10% случаев), он быстро получит больше данных, поскольку комментарий с меньшим количеством данных находится ближе к топу.
- Не завязан на время. В отличие от Hot, возраст комментария в рейтинг не входит: в ветке все одинаково «свежие».
- Просто считает, нет внешнего состояния, кроме ups/downs; формула O(1).
Можно также визуализировать рейтинг комментариев с разным соотношением голосов:
Как можно заметить, рейтинг комментария зависит не от общего числа полученных голосов, а от отношения числа апвоутов к числу голосов.
| Технология | Область применения | Мотивация |
|---|---|---|
| Фронтенд | ||
| TypeScript | Язык программирования | Строгая типизация, расширенный фугкционал по сравнению с JS |
| React | Веб-интерфейс | Компонентный подход, высокая производительность, поддержка SSR для SEO |
| React Native | Мобильные приложения | Кроссплатформенность, повторное использование кода, нативная производительность |
| GraphQL | Запросы данных | Оптимизация запросов, уменьшение перегрузки сети, строгая типизация |
| Бэкенд | ||
| Go (Golang) | Основной язык сервисов | Высокая производительность, низкое потребление памяти, встроенная поддержка многопоточности |
| Apache Cassandra | Основное хранилище данных | Горизонтальное масштабирование, отказоустойчивость, высокая пропускная способность записи |
| Redis | Кеш/сессии | Низкая задержка, поддержка структур данных, автоматическое удаление TTL-записей |
| Elasticsearch | Поиск и аналитика | Полнотекстовый поиск, агрегации данных, горизонтальное масштабирование |
| Инфраструктура | ||
| Docker | Контейнеризация | Изоляция сервисов, переносимость, интеграция с оркестраторами |
| Kubernetes | Оркестрация контейнеров | Автомасштабирование, self-healing, управление распределенными системами |
| Nginx | Reverse Proxy / Load Balancer | Терминация SSL, кеширование, балансировка L7-трафика |
| Jenkins | CI/CD пайплайны | Автоматизация сборки и деплоя, поддержка плагинов, распределенные сборки |
| Terraform | IaC | Декларативное управление инфраструктурой, поддержка multi-cloud |
| Ansible | Конфигурация серверов | Идемпотентность, автоматизация рутинных задач |
| Мониторинг | ||
| Prometheus | Сбор метрик | Многоразмерные данные, интеграция с Grafana, pull-модель |
| Grafana | Визуализация метрик | Гибкие дашборды, поддержка множества источников данных |
| Сфера | Меры обеспечения надежности |
|---|---|
| Уровень ДЦ | Tier IV |
| Серверы | • Горячая замена компонентов (диски, БП, вентиляторы) • RAID 10 для хранилищ • Размещение в разных стойках/зонах ДЦ |
| Сеть | • Двойные маршрутизаторы (VRRP/HSRP) • BGP multihoming (≥2 провайдера) • Раздельные физические кабельные трассы |
| Электропитание | • Источники бесперебойного питания (5-15 мин автономии) • Дизель-генераторы (24+ ч топлива) • ATS для автоматического переключения |
| Охлаждение | • Системы CRAC • Горячие/холодные коридоры • Фальшполы с вентиляцией |
| Безопасность | • Биометрический доступ + видеонаблюдение • Газовое пожаротушение • Датчики задымленности/протечек |
| Мониторинг | • DCIM-системы в реальном времени • Автоскрипты переключения при отказах |
| Слой / компонент | Способ резервирования / отказоустойчивости | Примечание |
|---|---|---|
| Kubernetes control‑plane | 3 master‑ноды в разных AZ, etcd RF = 3, регулярные snapshots → S3 | Кворум 2/3; потеря узла/AZ без простоя |
| Kubernetes worker‑nodes | Auto‑Scaling Groups по 3 AZ, HPA, pod‑anti‑affinity | Замещение узла + автоматическое масштабирование |
| Cassandra cluster | Multi‑DC, Replication Factor = 3, LOCAL_QUORUM, incremental SSTable‑backups | Потеря узла/целого DC — данные и сервис доступны |
| Redis Cluster / сессии | 3 masters + 3 replicas, Sentinel‑quorum = 3, AOF + RDB, anti‑affinity | Авто‑фейловер ≤ 3 s, сохранность данных |
| Elasticsearch | 3 master‑eligible + N data‑nodes, Replica = 1, ежедневные snapshots → S3 | Шарды пересинхронизируются, поиск непрерывен |
| Object‑storage | Erasure coding 8/4, versioning, cross‑region replication | Потеря диска/узла/региона без утраты объектов |
| Message broker (Kafka) | RF = 3, ISR‑контроль, daily topic‑level backups → S3 | Exactly‑once semantics + DR‑восстановление |
| CI/CD (Jenkins) | 2 controllers (active/passive), агенты в k8s, nightly backup $JENKINS_HOME | Переключение ≤ 1 min, сохранность history |
Graceful Shutdown: механизм корректного завершения работы сервиса, при котором:
- Прекращается прием новых запросов, но уже обрабатываемые завершаются.
- Сохраняются данные (кеш, сессии, транзакции).
- Закрываются соединения с БД, очередями и другими сервисами.
Graceful Degradation: механизм перехода к более простой бизнес-логике или делегирования запросов при отвале сервиса или его части (БД, очереди и тд)
- Поиск - даем пользователю выбрать, что именно будем искать: сообщества, посты, пользователей и тд, далее идем напрямую в нужную БД и используем встроенный поиск.
- Сообщества - в отображении постов используем заглушку (например r/community), при попытке перейти в сообщество сообщаем об ошибке и просим подождать.
- Посты - выдаем везде одни и те же посты (с пометкой о том, что другие посты сейчас недоступны), хранящиеся в специальной БД base_posts, в которую иногда добавляем посты от имени reddit. Если и она недоступна, сообщаем пользователю об ошибке и просим подождать.
- Комментарии - в отображении постов счетчик комментариев показывает 0, отключаем возможность писать комментарии.
- Голоса - тоже в отображении постов счетчик голосов обнуляем, при этом если пользователь создает голос, пишем об этом в LocalStorage, откуда, при восстановлении сервиса, отпрпавляем запросы.
- Пользователи - при отображении постов, комментариев и сообществ заменяем пользователей заглушкой, при попытке зайти в профиль сообщаем об ошибке.
- Рекомендации - отдаем посты сообществ и пользователей, на которые подписан пользователь.
Также опишем работу некоторых сервисов для снижения нагрузки:
- Посты - вместо моментальной подгрузки информации об авторе и сообществе, которая требует получения соответствующей инфорамции с сервера, используем технику lazy-loading, согласно которой запрос информации происходит только тогда, когда это действительно нужно, в нашем случае при наведении пользователем курсора на поле автора или сообщества. Изначально будут показываться только денормализованные поля названия сообщества и имени пользователя, которые хранятся в табличке постов. Такой подход позволит существенно снизить нагрузку на сервер и улучшит пользовательский опыт и SEO за счет снижения времени загрузки отедльных постов и, соответственно, ленты.
- Комментарии - аналогичный подход с использованием lazy-loading, где изначально информация об авторе комментария будет ограничена его именем - денормализованном полем, хранящемся в табличке комментариев, так же позволит значительно уменьшить объем потока запросов на сервер, что усовершенствует UX и SEO.
CQRS (Command Query Responsibility Segregation) - архитектурный паттерн, который разделяет пайплайны для чтения и записи в БД. Дает возможность управлять нагрузкой на запись в БД, а также обеспечивает независимость запросов чтения от записывающих команд. Исопльзуется в таких микросервисах, как сообщества, комменатрии и голоса для выдерживания огромного RPS, поступающего на соответствующие БД каждого микросервиса.
Отбивка статистики - каждый сервис асинхронно пишет события в prometheus
Outbox - гарантия доставки всех событий в соответствующую очередь для дальнейшей записи в БД событий, используемую для создания рекомендаций с помощью ML модели.
Посчитаем RPS каждого сервиса:
- Поиск:
- RPS = (5 * 101000000) / 86400 = 5844.9
- Пиковый RPS = 5844.9 * 1.7 = 9936.3
- Авторизация:
- Запросы от других сервисов на валидацию сессии = Создание сабреддита (0.03) + подписка на сабреддит (79.49) + публикация поста (19.87) + написание комментария (139.11) + оценка постов и комментариев (9936.35) + отправка сообщений (1709.04) = 11883.89
- Общий пиковый RPS сервиса = Запросы от других сервисов на валидацию сессии + Авторизация = 11883.89 + 59.62 = 11943.51
- Сообщества:
- пиковый RPS = Создание сабреддита + подписка на сабреддит = 0.03 + 79.49 = 79.52
- Посты:
- пиковый RPS = Публикация постов + просмотр постов = 19.87 + 24602.4 = 24622.27
- Комментарии:
- пиковый RPS = запрос комментариев + написание комментариев = 12301.2 + 139.11 = 12440.31
- Голоса:
- пиковый RPS = Запросы на получение количества лайков на посте/комментарии + создание голоса = 24602.4 + 12301.2 + 9936.35 = 46839.95
- Пользователи:
- пиковый RPS = проверка существования пользователя от сервиса Авторизации при авторизации + просмотр профиля = 59.62 + 173.12 = 232.74
- Сообщения:
- пиковый RPS = отправка + получение сообщений = 1709.04 + 854.52 = 2563.56
- Рекомендации:
- RPS = DAU / 86400 = 101000000 / 86400 = 1168.98
- Пиковый RPS = 1168.98 * 1.7 = 1987.26
Оценка потребления ресурсов со степенью сложности на одно ядро:
| Сложность сервиса | RPS | RAM |
|---|---|---|
| Тяжелая | 10 | 100 Mb |
| Средняя | 100 | 100 Mb |
| Легкая | 5000 | 10 Mb |
| Сервис | Пиковый RPS | Сложность | CPU (vCPU) | RAM (ГБ) | Трафик (Гбит/с) |
|---|---|---|---|---|---|
| Поиск | 9936.3 | Средняя | 100 | 9.9 | 0.49 |
| Авторизация | 11943.51 | Легкая | 24 | 1.2 | 0.266 |
| Сообщества | 79.52 | Средняя | 1 | 0.08 | 0.001 |
| Посты | 24622.27 | Легкая | 50 | 2.5 | 3.149 |
| Комментарии | 12440.31 | Легкая | 25 | 1.2 | 1.59 |
| Голоса | 46839.95 | Легкая | 94 | 3.5 | 0.89 |
| Пользователи | 232.74 | Легкая | 1 | 0.02 | 0.002 |
| Сообщения | 2563.56 | Легкая | 1 | 0.26 | 0.001 |
| Рекомендации | 1987.26 | Тяжелая | 199 | 198.7 | 19.87 |
Таблица posts (11.06 ТБ данных)
-
(community_id, created_at, is_deleted)- Размер ключа:
16 (community_id) + 8 (created_at) + 1 (is_deleted) = 25 байт. - Размер индекса:
(25 + 16) × 8.6 млрд × 1.1 ≈ 361 ГБ.
- Размер ключа:
-
(created_at, is_deleted)- Размер ключа:
8 + 1 = 9 байт. - Размер индекса:
(9 + 16) × 8.6 млрд × 1.1 ≈ 220 ГБ.
- Размер ключа:
Итого: 581 ГБ
Таблица subscriptions (2.35 ТБ данных)
-
(user_id, community_id)- Размер ключа:
16 + 16 = 32 байта. - Размер индекса:
(32 + 16) × 17.7 млрд × 1.1 ≈ 870 ГБ.
- Размер ключа:
-
community_id- Размер ключа:
16 байт. - Размер индекса:
(16 + 16) × 17.7 млрд × 1.1 ≈ 580 ГБ.
- Размер ключа:
Итого: 1.45 ТБ
Таблица comments (33.51 ТБ данных)
-
(post_id, created_at, is_deleted)- Размер ключа:
16 + 8 + 1 = 25 байт. - Размер индекса:
(25 + 16) × 17.2 млрд × 1.1 ≈ 832 ТБ.
- Размер ключа:
-
(user_id, is_deleted)- Размер ключа:
16 + 1 = 17 байт. - Размер индекса:
(17 + 16) × 17.2 млрд × 1.1 ≈ 581 ТБ.
- Размер ключа:
Итого: 1.41 ТБ
Таблица votes_comments (8.9 ТБ данных)
-
(comment_id, is_deleted)- Размер ключа:
16 + 1 = 17 байт. - Размер индекса:
(17 + 16) × 172 млрд × 1.1 ≈ 5.84 ТБ.
Итого: 5.84 ТБ
- Размер ключа:
Таблица votes_posts (17.8 ТБ данных)
-
(post_id, is_deleted)- Размер ключа:
16 + 1 = 17 байт. - Размер индекса:
(17 + 16) × 344 млрд × 1.1 ≈ 11.63 ТБ.
Итого: 11.63 ТБ
- Размер ключа:
Таблица messages (382.07 ТБ данных)
-
(sender_id, receiver_id, created_at, is_deleted)- Размер ключа:
16 + 16 + 8 + 1 = 41 байт. - Размер индекса:
(41 + 16) × 740 млрд × 1.1 ≈ 46.43 ТБ.
- Размер ключа:
-
(receiver_id, created_at, is_deleted)- Размер ключа:
16 + 8 + 1 = 25 байт. - Размер индекса:
(25 + 16) × 740 млрд × 1.1 ≈ 33.37 ТБ.
- Размер ключа:
Итого: 79.8 ТБ
Общий размер индексов: ~100.7 ТБ.
Cassandra: С учетом перечисленных в пункте 9 средств обеспечения надежности для cassandra, получим, что общий размер хранения увеличится в ~3.2 раза (3 реплики + overhead ~20%), то есть общий размер для одного ДЦ составит
- RAM: 100.7 ТБ * 3.2 = 322.2 ТБ
- Disk: 1313.71 ТБ * 3.2 = 4203.87 ТБ
Redis: 3 мастера и 3 реплики, значит объем RAM увеличивается в 6 раз. RDB (снапшот) и AOF (лог операций) хранятся в постоянной памяти и занимают примерно 2.5 * RAM. В итоге получаем
- RAM: 32.04 ГБ * 6 = 192.24 ГБ
- Disk: 192.24 ГБ * 2.5 = 480.6 ГБ
Elasticsearch: В этом случае посчитаем объем каждой таблицы с учетом реплик
| Таблица | Оценка размера текстов | Оценка индекса (×3) | С репликами (×2) |
|---|---|---|---|
| search_posts | ~6 ТБ | 18 ТБ | 36 ТБ |
| search_comments | ~25 ТБ | 75 ТБ | 150 ТБ |
| search_users | ~100 ТБ | 300 ТБ | 600 ТБ |
| search_communities | ~0.5 ГБ | 1.5 ГБ | 3 ГБ |
В сумме - 787 ТБ постоянной памяти + 105.3 ТБ RAM
ClickHouse: Если считать, что почти все запросы это события, то их получается около 99000 в секунду. Допустим, размер одного события равен 350 байт, тогда
- Событий в день: 99000 * 60 * 60 * 24 = 8.55 млрд
- Исходный объем без сжатия: 8.55 млрд * 350 Б = 3.12 ТБ/день
- Сжатый объем: 3.12 / 5 = 624 ГБ/день
- За 30 дней хранения: 624 ГБ * 30 = 18.72 ТБ
- С учетом репликации: 18.72 ТБ * 2 = 37.44 ТБ
- Необходимое количество RAM ~312 ГБ
Для расчета QPS примем размер входящих батчей равным 1000 событиям, тогда QPS получается 99000 / 1000 = 99.
S3: Из расчетов, что в каждом втором посте есть изображение и в каждом седьмом посте есть видео со средними размерами 0.35 МБ и 14.25 МБ соответственно, также в 2% сообщений есть изображения и в 0.5% видео, тогда получим, что объем S3 должен быть: 8.6 млрд постов * (0.5 * 0.35 + 0.15 * 14.25) + 1.72 млрд пользователей * 430 сообщений/пользователя * (0.02 * 0.35 + 0.005 * 14.25) = 65.66 ПБ
CPU возьмем из расчета 1000 QPS/CPU
| БД | Пиковый QPS | CPU | RAM | Disk |
|---|---|---|---|---|
| Cassandra | 88765.6 | 89 | 322.2 ТБ | 4203.87 ТБ |
| Elasticsearch | 9936.3 | 10 | 105.3 ТБ | 787 ТБ |
| Redis | 3212.1 | 4 | 195.24 ГБ | 480.6 ГБ |
| ClickHouse | 99 | 1 | 312 ГБ | 37.44 ТБ |
С учетом роста размера хранилища за год на 10.09 ПБ, получим прирост за год 10.09 / 69.37 = 0.145. Предположим, что такой темп роста сохранится, тогда за 5 лет каждая БД увеличится в (1 + 0.145)5 = 1.97 раз. Также нужно выбирать ресурсы с запасом в 40%, чтобы не возникало проблемных ситуаций.
Таким образом итоговая таблица БД выглядит как
| БД | Пиковый QPS | CPU с запасом | RAM с запасом | Disk с запасом |
|---|---|---|---|---|
| Cassandra | 174868.2 | 245 | 888.63 ТБ | 11602.68 ТБ |
| Elasticsearch | 19574.5 | 28 | 290.62 ТБ | 2172.12 ТБ |
| Redis | 6327.8 | 12 | 538.86 ГБ | 1326.45 ГБ |
| ClickHouse | 195.03 | 1 | 861.11 ГБ | 103.33 ТБ |
Для S3 получаем 65.66 ПБ * 1.97 * 1.4 = 181.1 ПБ
В пункте 3 был проведен расчет рапсределения нагрузки по странам, приведем таблицу с распределением нагрузки по ДЦ:
| Страна | Количество ДЦ | % общей нагрузки |
|---|---|---|
| США | 7 | 7.19 |
| Великобритания | 1 | 9.93 |
| Германия | 1 | 7.64 |
| Канада | 1 | 6.9 |
| Франция | 1 | 6.84 |
| Индия | 1 | 5.18 |
| Австралия | 1 | 4.07 |
| Бразилия | 1 | 3.65 |
Сгруппируем страны по типу нагрузки для расчета определенных конфигураций для каждой группы:
| Тип нагрузки на ДЦ | % общей нагрузки на ДЦ | Страны |
|---|---|---|
| Высокая | ~10 | Великобритания |
| Средняя | 7-8 | Германия, Канада, США |
| Средне-низкая | 6-7 | Франция, Индия |
| Низкая | 4-5 | Австралия, Бразилия |
Таикм образом таблицы ресурсов для каждого типа нагрузки под k8s и БД примут вид
Высокая:
k8s:
| Сервис | CPU/r | CPU/l | RAM/r | RAM/l |
|---|---|---|---|---|
| Поиск | 14 | 28 | 1.4 ГБ | 2.74 ГБ |
| Авторизация | 3 | 6 | 0.14 ГБ | 0.20 ГБ |
| Сообщества | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Посты | 7 | 14 | 0.42 ГБ | 0.78 ГБ |
| Комментарии | 5 | 8 | 0.14 ГБ | 0.20 ГБ |
| Голоса | 13 | 26 | 0.56 ГБ | 1.18 ГБ |
| Пользователи | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Сообщения | 2 | 2 | 0.04 ГБ | 0.08 ГБ |
| Рекомендации | 28 | 55 | 27.86 ГБ | 54.68 ГБ |
БД:
| БД | Пиковый QPS | CPU с запасом | RAM с запасом | Disk с запасом |
|---|---|---|---|---|
| Cassandra | 17486.82 | 25 | 888.63 ТБ | 11602.68 ТБ |
| Elasticsearch | 1957.45 | 3 | 290.62 ТБ | 2172.12 ТБ |
| Redis | 632.78 | 2 | 538.86 ГБ | 1326.45 ГБ |
| ClickHouse | 19.5 | 1 | 861.11 ГБ | 103.33 ТБ |
Средняя:
k8s:
| Сервис | CPU/r | CPU/l | RAM/r | RAM/l |
|---|---|---|---|---|
| Поиск | 12 | 22 | 0.98 ГБ | 1.96 ГБ |
| Авторизация | 3 | 6 | 0.14 ГБ | 0.20 ГБ |
| Сообщества | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Посты | 6 | 12 | 0.28 ГБ | 0.59 ГБ |
| Комментарии | 3 | 6 | 0.14 ГБ | 0.20 ГБ |
| Голоса | 10 | 20 | 0.42 ГБ | 0.78 ГБ |
| Пользователи | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Сообщения | 2 | 2 | 0.03 ГБ | 0.06 ГБ |
| Рекомендации | 21 | 42 | 20.86 ГБ | 40.96 ГБ |
БД:
| БД | Пиковый QPS | CPU с запасом | RAM с запасом | Disk с запасом |
|---|---|---|---|---|
| Cassandra | 13115.12 | 20 | 888.63 ТБ | 11602.68 ТБ |
| Elasticsearch | 1468.09 | 3 | 290.62 ТБ | 2172.12 ТБ |
| Redis | 474.59 | 1 | 538.86 ГБ | 1326.45 ГБ |
| ClickHouse | 14.63 | 1 | 861.11 ГБ | 103.33 ТБ |
Средне-низкая:
k8s:
| Сервис | CPU/r | CPU/l | RAM/r | RAM/l |
|---|---|---|---|---|
| Поиск | 10 | 20 | 0.84 ГБ | 1.57 ГБ |
| Авторизация | 3 | 6 | 0.14 ГБ | 0.20 ГБ |
| Сообщества | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Посты | 5 | 8 | 0.28 ГБ | 0.59 ГБ |
| Комментарии | 3 | 6 | 0.14 ГБ | 0.20 ГБ |
| Голоса | 9 | 16 | 0.28 ГБ | 0.59 ГБ |
| Пользователи | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Сообщения | 2 | 2 | 0.03 ГБ | 0.06 ГБ |
| Рекомендации | 19 | 36 | 18.06 ГБ | 35.48 ГБ |
БД:
| БД | Пиковый QPS | CPU с запасом | RAM с запасом | Disk с запасом |
|---|---|---|---|---|
| Cassandra | 11366.43 | 17 | 888.63 ТБ | 11602.68 ТБ |
| Elasticsearch | 1272.34 | 2 | 290.62 ТБ | 2172.12 ТБ |
| Redis | 411.31 | 1 | 538.86 ГБ | 1326.45 ГБ |
| ClickHouse | 12.68 | 1 | 861.11 ГБ | 103.33 ТБ |
Низкая:
k8s:
| Сервис | CPU/r | CPU/l | RAM/r | RAM/l |
|---|---|---|---|---|
| Поиск | 7 | 14 | 0.70 ГБ | 1.37 ГБ |
| Авторизация | 2 | 2 | 0.14 ГБ | 0.20 ГБ |
| Сообщества | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Посты | 3 | 6 | 0.14 ГБ | 0.20 ГБ |
| Комментарии | 2 | 2 | 0.14 ГБ | 0.20 ГБ |
| Голоса | 7 | 14 | 0.28 ГБ | 0.59 ГБ |
| Пользователи | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Сообщения | 2 | 2 | 0.01 ГБ | 0.02 ГБ |
| Рекомендации | 13 | 26 | 12.46 ГБ | 24.50 ГБ |
БД:
| БД | Пиковый QPS | CPU с запасом | RAM с запасом | Disk с запасом |
|---|---|---|---|---|
| Cassandra | 7869.07 | 12 | 888.63 ТБ | 11602.68 ТБ |
| Elasticsearch | 881.85 | 2 | 290.62 ТБ | 2172.12 ТБ |
| Redis | 285.75 | 1 | 538.86 ГБ | 1326.45 ГБ |
| ClickHouse | 8.78 | 1 | 861.11 ГБ | 103.33 ТБ |
Для всех типов нагрузки будем использовать одни и те же спецификации, отличия будут только в их количестве
Конфигурация серверов для k8s:
| Node-pool | Процессор | CPU | RAM | Disk | Аренда $/мес | Покупка $ |
|---|---|---|---|---|---|---|
| general-64G | AMD EPYC 7452 | 32 | 64 GB | 960 GB | 168 | 5127 источник |
| memory-128G | AMD EPYC 9535 | 64 | 128 GB | 960 GB | 450 | 13300 источник |
| Кластер БД | Ключевые узловые ресурсы |
Покупка «на землю» ≈ стоимость комплекта |
Типовой-«облачный» эквивалент | Аренда / месяц |
|---|---|---|---|---|
| Cassandra | 2 × Xeon 6-6980P, 4 ТБ DDR5, 12 ТБ CXL, 8 × 30,7 ТБ NVMe | CPU $24,9 k (TechPowerUp) + DDR5 $37 k (ServerSupply.com) + CXL ≈ $120 k ((TechRadar)) + NVMe $35,9 k (Sabrent) + прочее $5 k ⇒ ≈ $223 k | AWS u-18tb1.112xlarge (18 ТиБ RAM) | ≈ $119,6 k / мес (Economize Cloud) |
| Elasticsearch | 2 × EPYC 9754, 12 ТБ DDR5, 4 × 30,7 ТБ NVMe | CPU $23,8 k (AMD) + DDR5 $110,9 k (ServerSupply.com) + NVMe $18 k (Sabrent) + прочее $5 k ⇒ ≈ $158 k | AWS u-12tb1.112xlarge (12 ТиБ RAM) | ≈ $79,7 k / мес (Vantage) |
| Redis Hi-Freq | 1 × Xeon Gold 6448Y, 128 ГБ DDR5, 1,92 ТБ NVMe | CPU $3,6 k (TechPowerUp) + DDR5 $1,2 k (ServerSupply.com) + NVMe $0,35 k (Sabrent) + прочее $2 k ⇒ ≈ $7 k | Tier-Net «AMD Titanium Plus» (EPYC 9754 / 512 ГБ RAM)** | $629 / мес (Tier) |
| ClickHouse | 2 × EPYC 9354, 256 ГБ DDR5, 8 × 15,4 ТБ NVMe | CPU $6,8 k (AMD) + DDR5 $2,3 k (ServerSupply.com) + NVMe $19,5 k (Sabrent) + прочее $5 k ⇒ ≈ $34 k | AWS i4i.32xlarge (≈ 60 ТБ NVMe, 1 ТБ RAM) | ≈ $8,0 k / мес (Economize Cloud) |
| Cassandra | ES | Redis | ClickHouse | |
|---|---|---|---|---|
| Купив железо (развёртывание on-prem) окупаемость против AWS (On-Demand) | < 2 месяцев | ≈ 2 мес | > 9 лет | ≈ 4 мес |
Footnotes
-
https://www.businessdasher.com/how-many-subreddits-are-there/ ↩ ↩2 ↩3
-
https://www.statista.com/forecasts/1143622/reddit-users-in-the-world ↩ ↩2
-
https://www.statista.com/forecasts/1309805/reddit-users-comments-votes ↩
-
https://worldpopulationreview.com/country-rankings/reddit-users-by-country ↩ ↩2 ↩3
-
https://www.ibm.com/docs/en/cics-ts/6.x?topic=performance-ssl-handshake-overhead ↩













