Курсовая работа в рамках 3-го семестра программы по Веб-разработке ОЦ VK x МГТУ им. Н.Э. Баумана (ex. "Технопарк") по дисциплине "Проектирование высоконагруженных сервисов"
Автор - Максим Сиканов
Задание - Методические указания
- Тема, функционал и аудитория
- Расчёт нагрузки
- Глобальная балансировка нагрузки
- Локальная балансировка нагрузки
- Логическая схема базы данных
- Физическая схема базы данных
- Алгоритмы
- Технологии
- Схема проекта
- Обеспечение надёжности
- Расчёт ресурсов
- Список источников
В качестве примера и аналога выбран ведущий в России сайт объявлений - Avito
- Создание / редактирование / поиск / просмотр объявлений
- Создание / просмотр отзывов
- Поиск по названию, категориям, диапазону цены, расстоянию от покупателя
- 61 млн активных пользователей в месяц в странах СНГ 1
- В среднем пользователи проводят на Авито 11 минут в месяц 1
- 97% трафика поступает на Авито из России 1
- Демография: 56.79% мужчин и 43.21% женщин 1
MAU - 61 млн пользователей 1
DAU - 2 млн пользователей 1
- В Авито создается ≈
1.4 млн
объявлений в день 1 =>0.0226 объявлений/сут
на человека - В Авито происходит ≈
8
сделок в секунду 1 =>0.0113 сделок/сут
на человека - посещаемость Авито более
384 млн
пользователей в месяц 1 =>0.21 посещений/сут
на человека
Хранимые данные | Оценочный размер на пользователя |
---|---|
Персональные данные (ФИО, почта, пароль и т.д.) | 1 КБ |
Аватар | 256 КБ |
Объявление | 1 МБ |
Отзыв | 1 КБ |
- Объявление в среднем содержит 3-4 фото (размер фото в среднем
256 КБ
) и текстовое описание. Итого ≈1 МБ
- В среднем на одного пользователя приходится 5 объявления и 10 отзывов 1
Возьмём общее оценочное число пользователей с запасом = 80 млн
- будем использовать далее в расчётах.
Тогда общий размер хранилища в худшем
случае: 80 млн пользователей * (5 МБ на объявления + 256 КБ на аватар + 1 КБ персональные данные + 10 КБ отзывы) ≈ 249 TB
За год можно ожидать прирост пользователей до 13 %
=> 249 TB * 0.13 = 32 TB 40 GB
нового пространства может
потребоваться.
Тип запроса | Средний оценочный RPS | Пиковое потребление, Гбит/с | Суммарный суточный трафик, TB/сутки |
---|---|---|---|
Создание отзыва | 5 |
- |
0.0004 |
Создание объявления | 17 |
0.032 |
1.4 |
Редактирование объявления | 139 |
0.28 |
11.45 |
Поиск объявлений | 140 |
0.024 |
1.02 |
Просмотр отзывов | 420 |
0.0008 |
0.034 |
Просмотр объявлений | 1120 |
2.2 |
92.2 |
Расчёты RPS:
- Создание объявления:
1.4 млн объявлений в сутки / (24 * 3600) ~= 17 RPS
- Редактирование объявления:
12 млн объявлений в сутки / (24 * 3600) ~= 139 RPS
2 - Поиск объявлений:
2 млн DAU * 6 / (24 * 3600) ~= 140 RPS
при условии, что каждый сделает 6 запросов(один поисковая выдача ~90 КБ
трафика) - Создание отзыва:
10 сделок/с * 0.5 = 5 RPS
при условии, что каждый второй будет оставлять отзыв - Просмотр отзывов:
140 поиск/с * 3 = 420 RPS
при условии, за один поиск человек откроет отзывы 3 раза
Расчёты трафика:
- Средний: API + Статика:
RPS * средний размер в GB = X Гбит/с
- Пиковый (Пиковый коэф трафика от среднего с запасом = 2): API + Статика:
2 * X Гбит/с
- Суммарный суточный: API + Статика:
(X / 1024) * (24 * 3600) с/сут = Y TB/сут
Суммарный RPS | Суммарное пиковое потребление, Гбит/с | Суммарный суточный трафик, TB/сутки | |
---|---|---|---|
Итог | 1841 |
2.62 |
115.2 |
Для обеспечения минимального latency основную часть дата-центров следует размещать на территории, наиболее близкой к наибольшему количеству пользователей. Так как в случае Авито 97% заказов приходится на российский рынок1, то ЦОДы размещать стоит ближе всего к аудитории приложения.
Больше 50% всех объявлений находятся в Западной части России. Поэтому ДЦ лучше всего разместить в Москве. Но чтобы обеспечить быстроту ответа для пользователей с востока - стоит также использовать ДЦ в Новосибирске. Также ДЦ в Новосибирске будет покрывать Среднюю Россию, тем самым нагрузка на дата-центры будет приблизительно равная.
- Москва
- Новосибирск
Также эти города находятся на магистралях сети
ЦОД | Область покрытия | Приблизительный % пользователей | Нагрузка (RPS) |
---|---|---|---|
Москва | Западная часть России | 55 | 1013 |
Новосибирск | Средняя и Восточная часть России | 45 | 829 |
Будем балансировать запросы с помощью Routing - BGP Anycast. Когда клиенты отправляют запросы, BGP маршрутизаторы автоматически выбирают ближайший и наиболее доступный маршрут к нему.
Так как в проекте используется роутинг с помощью BGP Anycast, балансировка на L4 может быть полезна в минимальном
количестве сценариев, так как роутинг считается эффективнее, чем LVS, а список их задач существенно пересекается.
Поэтому балансировка будет на L7 с помощью Nginx
.
Топология балансировщика - Промежуточный прокси
3
Так как Nginx может одновременно держать достаточно запросов 4, то в каждом ЦОДе будем использовать 2 nginx сервера, на которые будут приходить запросы
Мы будем применять Nginx для следующих процессов:
- Равномерная балансировка запросов между бэкендами с помощью Least Connection
- Мультиплексирование TCP соединений с бэкендом
- Реализация API-Gateway (функциональная балансировка)
- Разрешение задачи медленных клиентов
- Терминация SSL
- Отдача статики
- Кеширование запросов
- Сжатие контента с помощью gzip
- Retry идемпотентных запросов с помощью парсинга оригинального протокола (HTTP)
- Простановка HTTP-заголовков на уровне web-сервера, например, X-Real-IP - настоящий IP клиента
Далее для оркестрации сервисов будем использовть Kubernetes, который будет обеспечивать:
- Auto-scaling
- Service discovery
- Распределение stateless сервисов по кластеру
- Управление deployment-циклом приложений
Nginx и k8s в связке обеспечат нам высокий уровень отказоустойчивости сервиса.
Для более быстрой повторной аутентификации будем использовать Session tickets.
Название таблицы | Количество строк | Объем записи, байт | Объем данных, GB | Чтение, RPS | Запись, RPS |
---|---|---|---|---|---|
User | 80.000.000 |
200 |
15 |
420 |
4 |
User_rating | 80.000.000 |
6 |
0.5 |
420 |
5 |
User_vector | 80.000.000 |
1204 |
89.7 |
23 |
23 |
User_actions | 1.000.000.000.000 |
16 |
14901.1 |
1 |
1260 |
Feedback | 350.000.000 |
100 |
32.6 |
420 |
5 |
Announcement | 300.000.000 |
1000 |
280 |
1260 |
17 |
Name_search | 300.000.000 |
40 |
11.9 |
140 |
17 |
P.s: Один вектор в таблице User_vector
будет отражать степень интереса пользователя к каждой из категорий. Значит
длинна такого вектора будет равна количеству категорий. На Avito сейчас <300 категорий и
подкатегорий. В нашем случае будем считать, что максимальная длинна вектора 300, этого хватит с запасом.
Для хранения данных в качестве СУБД выбран PostgreSQL.
Причины:
- Нагрузка на базу данных будет не более 3000 PRS, что позволяет использовать PostgreSQL. Транзакционная модель позволит не переживать за консистентность данных.
- Наличие модуля для работы с географическими данными5, что существенно ускорит поиск в радиусе от пользователя.
- Надежность.
- Встроенный функционал для создания дампов базы и их выгрузки.
PgBouncer6 для мультиплексирования подключений.
PostGiST5 для работы с геоданными.
- B-tree (для всех FK): Feedback.user_id, Feedback.user_writer_id, User_rating.user_id, Announcement.user_id
- GiST: Announcement.point
Будет использоваться физическая репликация всей БД в СУБД PostgreSQL. В случае падения одного из серверов, запросы будут идти на второй сервер.
Схема репликации master-master:
Так как таблицы в PostgresSQL не очень большие, то все индексы можно поместить в память одной машины7. Поэтому шардинг для PostgresSQL можно не использовать.
Для остальных хранилищ ситуация аналогична.
Сетевая файловая система (CEPH) по следующим причинам:
- На хранение всех фото и превью нужно до
251 TB
, использование S3 может быть слишком дорогим в долгосрочной перспективе. - Масштабируемая, отказоустойчивая и гибкая распределенная файловая система, подходит для хранения больших объемов данных.
- Можно настраивать систему под свои нужды.
Таблица Name_search
будет расположена в Elasticsearch, что обеспечит более эффективнй поиск.
Clickhouse, куда будут писаться нужные данные для аналитики (например, различная активность пользователей). На основе этих данных будут строиться рекомендации. ML вектора для рекомендаций будут храниться в LanceDB.
Рекомендательная система, основанная на нейронной сети, которая будет анализировать запросы клиентов для предложения подходящих товаров.
Нейронная сеть: Рекомендательная модель, которая будет обучаться на основе данных о предпочтениях клиентов и характеристиках товаров. Будет использоваться Модель на основе LSTM TensorFlow8.
- Читатель нажимает на главную страницу / заходит в приложение
- Веб-сервер перенаправляет запрос в службу Rec
- Служба Rec вызывает службу model и передает user_id и top N элементов в качестве параметров
- Model service пересылает запрос одному из воркеров, который использует модель для прогнозирования, и возвращает 20 announcement_id в качестве рекомендаций
- Затем служба Rec обращается к базе данных Postgres, чтобы получить информацию
По каждому пользователю будет храниться вектор в СУБД LanceDB
9.
- Обучаем модель на мощном сервере с GPU
- При открытии главной страницы выполняется запрос в нейро сервис.
- К базе с
user_search
~ 100 RPS. На один запрос процессорного времени сервера с базой данных:100 ns доступ к памяти + 10 ms получение N элементов
, значит достаточно 2-х серверов с Postgres со следущими конфигурациями 2x6338/16x32GB/2xSSD4T/2x25Gb/s, на этих же серверах будут работать воркеры, предоставляющие API для взаимодействия с нейронной сетью. - Время ответа нейронной сети -
100 ms
, поэтому нужно будет запустить 20 воркеров, которые будут балансироваться с помощью NGINX.
Технология | Применение | Обоснование |
---|---|---|
Go | Backend, основной язык сервисов | Производительность, удобен для микросервисной архитектуры, низкий порог входа, популярный, большое количество технологий |
Python | Backend, модель для рекомендаций | Решения из коробки, быстрая и дешевая разработка |
Angular TS | Frontend | Строгая типизация, компонентный подход, быстрая разработка, множество решений из коробки |
Kotlin/Swift | Мобильная разработка | Популярно |
Nginx | Proxy balancer | Многофункциональный, популярный, хорошо конфигурируется |
Kafka | Асинхронный стриминговый сервис, брокер сообщений | Надежный, производительный по сравнению с RebbitMQ, отложенное эффективное выполнение задач, партицирование из коробки |
PostgreSQL | Хранилище SQL, основная БД сервисов | Подходит для реляционного хранения данных большинства CRUD-сервисов, популярный, низкий порог входа |
LanceDB | Хранилище векторов | Производительный9, удобный |
Elasticsearch | Хранилище логов; полнотекстный поиск | Популярный, удобный10 |
ClickHouse | Хранилище аналитических данных | Эффективная работа с OLAP-нагрузкой, производительный11 |
Prometheus | Хранилище метрик и система работы с ними | Популярный, производительный |
CEPH | Хранилище статики: фото, превью | Не дорогой вариант, надежный, масштабируемый |
Vault | Хранилище секретов | Удобный, популярный |
Grafana | Графики, мониторинг и алёрты | Удобный, популярный, гибкий |
Kibana | Просмотр логов | Удобный, популярный, гибкий |
Docker | Контейниризация | Удобно для разработки и работы внутри k8s |
Kubernetes | Deploy | Масштабирование, отказоустойчивость, оптимальная утилизация ресурсов |
Сервисы:
- DataAPI сервис отвечает за простые CRUD операции. Также при удалении объявлений этот сервис отправляет в кафку сообщение для удаления изображения из хранилища изображений.
- Поиск отвечает за поиск объявлений. В случае поиска по названию - ищет id объявлений в Elasticsearch. Затем
формирует запрос с нужными фильтрами и через
API Gateway
запрашивает нужные объявления из DataAPI сервис. - Рекомендации создают и пересчитывают вектора пользователей для рекомендаций. Действия пользователей (просмотр и
поиск) попадают в neuro модель для пересчета векторов. Когда пользователь запрашивает рекомендуемые объявлений, то
сервис рекомендаций на основе вектора пользователя через
API Gateway
запрашивает нужные объявления из DataAPI сервис.
Система должна быть устойчива к сбоям, тогда её можно назвать отказоустойчивой.
- Резервирование физических линии связи
- Резервирование охлаждения
- Распределённые и независимые ДЦ
- Периодические учения с отключением ДЦ
- Две линии питания
- Аварийные дизель-генераторы
- Бесперебойное питание
- В случае отказа одного из ДЦ нагрузка на другой может быть равна пиковой нагрузке всего приложения, поэтому конфигурации каждого ДЦ должны позволять единолично выдерживать всю нагрузку.
- Резервирование ресурсов (CPU, RAM)
- Резервирование физических компонентов (сервера, диски и т.д.)
- Резервирование хранилищ — схема реплецирования
- ClickHouse — внутренняя система реплицирования12
- Наличие реплик для каждого сервиса, а также балансер, который распределяет нагрузку между репликами
- Сбор логов и метрик
- Отслеживане различных метрик (CPU, RAM и т.д.) с помощью дашбордов
- Использование брокеров сообщений для асинхронного взаимодействия
- Использование архитектурных паттернов:
- Circuit Breaker13 - позволяет перекрыть сервис, который начинает слишком часто возвращать ошибки. В таком случае у сервиса будет время для восстановления
- Timeout13 - если сервис не отвечает дольше установленного времени, то мы перестаем ждать ответ и отправляем запрос в реплику, если она есть. Если реплики нет, то возвращаем ошибку.
- Graceful shutdown - механизм, который позволяет понять, что система по какой-то причине намерена завершить процесс, чтобы программа могла очистить ресурсы и завершить все процессы.
- Graceful degradation - принцип разработки, который предусматривает, чтобы при возникновении проблем или недоступности определенных функций или ресурсов приложение продолжало работать, предоставляя пользователю максимально возможный функционал. То есть, при возникновении проблем приложение может "спадать" до менее функционального состояния, но при этом оставаться работоспособным, вместо полного отказа в работе.
- Сбор логов и метрик
- Алёртинг инцидентов
- Тестирование (от модульных до комплексного и ручного)
- Настроенные CI/CD с тестированием и деплоем + удобное восстановление
- Подробный и ясный мониторинг
- Документация системы
- Виртуальный уровень защиты 14
- Приложение должно быть устойчиво к уязвимостям из OWASP Top Ten15 и другим рискам безопасности.
- Доступы к различным компонентам системы должны быть строго разграничены.
- Физический уровень защиты 14
- Контроль доступа в дата-центр
- Дополнительная защита инженерных компонентов
- Пожарная безопасность ЦОД
Далее используем пиковую нагрузку по RPS (коэффициент 1.5)
Система | Объем данных, TB | Чтение, RPS | Запись, RPS | Трафик |
---|---|---|---|---|
ClickHouse | 15 | 1 | 1260 * 1.5 = 1890 | < 1 Mbit/s |
Elasticsearch | 0.017 | 140 * 1.5 = 210 | (17 + 139) * 1.5 = 234 | - |
CEPH | 251 | (1120 + 14000) * 1.5 = 22680 | (17 + 139) * 1.5 = 234 | 2.4 Gbit/s |
PostgreSQL | 1 | 2660 * 1.5 = 3990 | 48 * 1.5 = 72 | < 20 Mbit/s |
LanceDB | 0.1 | 23 * 1.5 = 35 | 23 * 1.5 = 35 | < 2 Mbit/s |
Сервис | CPU, cores | RAM, GB | Disk | Count |
---|---|---|---|---|
ClickHouse | 16 | 32 | 24 TB | 2 |
Elasticsearch - поиск | 8 | 32 | 32 GB | 2 |
CEPH | 64 | 256 | 251 TB | 2 |
PostgreSQL | 16 | 256 | 2 TB | 2 |
LanceDB | 16 | 32 | 256 GB | 2 |
Основной критерий для определения количества ядер - время работы процессора в зависимости от ситуации16
Сервис | Нагрузка, RPS | Net, Mbit/s | Характер сервиса | CPU | RAM | Count |
---|---|---|---|---|---|---|
Поиск | 140 * 1.5 = 210 | 3 | Тяжелая бизнес-логика | 21 | 1 | 2 |
DataAPI сервис | (17 + 139 + 140 + 420 + 1120) * 1.5 = 2754 | 300 | Средняя бизнес-логика | 28 | 2 | 2 |
Рекомендации | (200 + 100) * 1.5 = 450 | 1 | Тяжелая бизнес-логика | 45 | 3 | 2 |
API Gateway | 210 + 2754 + 450 = 3414 | 303 | Легкая бизнес-логика | 8 | 0.2 | 2 |
Все сервисы написаны на Go. Тогда можно предположить:
- 1 ядро CPU выдержит 500 RPS и 1 запрос в среднем 50 кб RAM (в случае легкой бизнес-логики).
- 1 ядро CPU выдержит 100 RPS и 1 запрос в среднем 500 кб RAM (в случае средней бизнес-логики).
- 1 ядро CPU выдержит 10 RPS и 1 запрос в среднем 1 мб RAM (в случае тяжелой бизнес-логики).
Nginx: до 23762 RPS
Согласно тестированию nginx1718 бюджетный
сервер CPU: 4 core | RAM: 32 GB |HDD: 500 GB | NIC: Intel X710 2×10 Gbe
сможет выдерживать нашу нагрузку. Для
обеспечания отказоустойчивости, каждый ДЦ будет содержать 2 nginx сервера.
Сервис | Хостинг | Configuration | Cores | Count | Покупка19, $ | Аренда20, $/мес |
---|---|---|---|---|---|---|
ClickHouse | own | AMD EPYC 7543P / 4x8GB / 12x NVMe 2 TB | 32 | 2 | 5000 | 430 |
Elasticsearch - поиск | own | A2SDi-16C-HLN4F- 16-Core C3955 Atom / 4x8GB / 1x NVMe 32 GB | 16 | 2 | 2000 | 320 |
CEPH | own | AMD EPYC 7713P / 8x32GB / 24x NVMe 12 TB | 64 | 2 | 8000 | 900 |
PostgreSQL | own | AMD EPYC 7543P / 8x32GB / 2x NVMe 1 TB | 32 | 2 | 5500 | 500 |
LanceDB | own | A2SDi-16C-HLN4F- 16-Core C3955 Atom / 4x8GB / 1x NVMe 256 GB | 16 | 2 | 2000 | 320 |
Nginx | own | Intel Xeon E-2314 Processor - / 4x8GB / HDD: 500 GB | 4 | 2 | 1000 | 80 |
ML Service | own | AMD EPYC 7543P / 8x8GB / - / 4 GPU × 16 GB | 32 | 2 | 5000 | 430 |
kubenode | own | 2x6338 / 1x128MB / 1x NVMe 256 MB | 4 | 52 | - | - |
Для всех сервисов нужно 26 kubenode, но у каждого сервиса есть реплика, поэтому берем с запасом x2.
Все kubenode будут разнесены на 4 физических сервера. На каждом сервере будет 13 kubenode (для обеспечения отказоусточивости).
Сервис | Хостинг | Configuration | Cores | Count | Покупка19, $ | Аренда20, $/мес |
---|---|---|---|---|---|---|
kuber | own | AMD EPYC 9634 / 1x4GB / 1x NVMe 8 GB | 52 | 4 | 7000 | 550 |
В нашем случае каждый ДЦ будет содержать перечисленные сервера.
- Стоимость одного датацентра:
2*5000 + 2*2000 + 2*8000 + 2*5500 + 2*2000 + 2*1000 + 2*5000 + 4*7000 = 85000$
- Будем предполагать обновление железа 1 раз в 5 лет, тогда стоимость в год будет:
85000 / 5 = 17000$
- Поскольку у нас 2 датацентра, то общая стоимость железа в год будет
2 * 17000 = 34000$
- Стоимость одного датацентра:
2*430 + 2*320 + 2*900 + 2*500 + 2*320 + 2*80 + 2*430 + 4*550 = 8160$/мес
- Поскольку у нас 2 датацентра, то общая стоимость железа в год будет
8160 * 12 * 2 = 195840$
Выгоднее купить железо, тогда стоимость в год будет 32400$
.
Footnotes
-
Статистика Авито в 2024 году ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11
-
Введение в современную сетевую балансировку и проксирование ↩
-
Построение рекомендательных систем с использованием нейронных сетей ↩
-
Векторные СУБД и другие инструменты для разработки ML-моделей ↩ ↩2
-
Testing the Performance of NGINX and NGINX Plus Web Servers ↩