Skip to content

Latest commit

 

History

History
545 lines (373 loc) · 40.9 KB

README.md

File metadata and controls

545 lines (373 loc) · 40.9 KB

Проектирование высоконагруженного сайта объявлений

Курсовая работа в рамках 3-го семестра программы по Веб-разработке ОЦ VK x МГТУ им. Н.Э. Баумана (ex. "Технопарк") по дисциплине "Проектирование высоконагруженных сервисов"

Содержание:

  1. Тема, функционал и аудитория
  2. Расчёт нагрузки
  3. Глобальная балансировка нагрузки
  4. Локальная балансировка нагрузки
  5. Логическая схема базы данных
  6. Физическая схема базы данных
  7. Алгоритмы
  8. Технологии
  9. Схема проекта
  10. Обеспечение надёжности
  11. Расчёт ресурсов
  12. Список источников

Часть 1. Тема и целевая аудитория

Тема курсовой работы - "Проектирование сайта объявлений"

В качестве примера и аналога выбран ведущий в России сайт объявлений - Avito

Ключевой функционал сервиса

  • Создание / редактирование / поиск / просмотр объявлений
  • Создание / просмотр отзывов

Ключевые продуктовые решения

  • Поиск по названию, категориям, диапазону цены, расстоянию от покупателя

Целевая аудитория

  • 61 млн активных пользователей в месяц в странах СНГ 1
  • В среднем пользователи проводят на Авито 11 минут в месяц 1
  • 97% трафика поступает на Авито из России 1
  • Демография: 56.79% мужчин и 43.21% женщин 1

img.png

Часть 2. Расчёт нагрузки

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

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 и сетевой трафик по типам запросов:

Тип запроса Средний оценочный 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

Часть 3. Глобальная балансировка нагрузки

Для обеспечения минимального latency основную часть дата-центров следует размещать на территории, наиболее близкой к наибольшему количеству пользователей. Так как в случае Авито 97% заказов приходится на российский рынок1, то ЦОДы размещать стоит ближе всего к аудитории приложения.

avito_users.png

Больше 50% всех объявлений находятся в Западной части России. Поэтому ДЦ лучше всего разместить в Москве. Но чтобы обеспечить быстроту ответа для пользователей с востока - стоит также использовать ДЦ в Новосибирске. Также ДЦ в Новосибирске будет покрывать Среднюю Россию, тем самым нагрузка на дата-центры будет приблизительно равная.

population.png

  • Москва
  • Новосибирск

Также эти города находятся на магистралях сети

image

Нагрузка на ЦОД-ы

ЦОД Область покрытия Приблизительный % пользователей Нагрузка (RPS)
Москва Западная часть России 55 1013
Новосибирск Средняя и Восточная часть России 45 829

Методы глобальной балансировки

Будем балансировать запросы с помощью Routing - BGP Anycast. Когда клиенты отправляют запросы, BGP маршрутизаторы автоматически выбирают ближайший и наиболее доступный маршрут к нему.

Часть 4. Локальная балансировка нагрузки

Схема балансировки

Так как в проекте используется роутинг с помощью BGP Anycast, балансировка на L4 может быть полезна в минимальном количестве сценариев, так как роутинг считается эффективнее, чем LVS, а список их задач существенно пересекается. Поэтому балансировка будет на L7 с помощью Nginx.

Топология балансировщика - Промежуточный прокси3

image

Так как 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 в связке обеспечат нам высокий уровень отказоустойчивости сервиса.

Нагрузка по терминации SSL

Для более быстрой повторной аутентификации будем использовать Session tickets.

Часть 5. Логическая схема базы данных

Диаграмма

image

Размер данных и нагрузка на чтение / запись

Название таблицы Количество строк Объем записи, байт Объем данных, 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, этого хватит с запасом.

Часть 6. Физическая схема базы данных

Выбор СУБД

Для хранения данных в качестве СУБД выбран PostgreSQL.

Причины:

  1. Нагрузка на базу данных будет не более 3000 PRS, что позволяет использовать PostgreSQL. Транзакционная модель позволит не переживать за консистентность данных.
  2. Наличие модуля для работы с географическими данными5, что существенно ускорит поиск в радиусе от пользователя.
  3. Надежность.
  4. Встроенный функционал для создания дампов базы и их выгрузки.

Клиентские библиотеки

PgBouncer6 для мультиплексирования подключений.

PostGiST5 для работы с геоданными.

Индексы

  1. B-tree (для всех FK): Feedback.user_id, Feedback.user_writer_id, User_rating.user_id, Announcement.user_id
  2. GiST: Announcement.point

Репликация

Будет использоваться физическая репликация всей БД в СУБД PostgreSQL. В случае падения одного из серверов, запросы будут идти на второй сервер.

Схема репликации master-master:

image

Шардинг

Так как таблицы в PostgresSQL не очень большие, то все индексы можно поместить в память одной машины7. Поэтому шардинг для PostgresSQL можно не использовать.

Для остальных хранилищ ситуация аналогична.

Хранение фото и превью

Сетевая файловая система (CEPH) по следующим причинам:

  1. На хранение всех фото и превью нужно до 251 TB, использование S3 может быть слишком дорогим в долгосрочной перспективе.
  2. Масштабируемая, отказоустойчивая и гибкая распределенная файловая система, подходит для хранения больших объемов данных.
  3. Можно настраивать систему под свои нужды.

Поисковая система

Таблица Name_search будет расположена в Elasticsearch, что обеспечит более эффективнй поиск.

Рекомендации и аналитика

Clickhouse, куда будут писаться нужные данные для аналитики (например, различная активность пользователей). На основе этих данных будут строиться рекомендации. ML вектора для рекомендаций будут храниться в LanceDB.

Часть 7. Алгоримты

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

Нейронная сеть: Рекомендательная модель, которая будет обучаться на основе данных о предпочтениях клиентов и характеристиках товаров. Будет использоваться Модель на основе LSTM TensorFlow8.

image

Рабочий процесс:

  1. Читатель нажимает на главную страницу / заходит в приложение
  2. Веб-сервер перенаправляет запрос в службу Rec
  3. Служба Rec вызывает службу model и передает user_id и top N элементов в качестве параметров
  4. Model service пересылает запрос одному из воркеров, который использует модель для прогнозирования, и возвращает 20 announcement_id в качестве рекомендаций
  5. Затем служба Rec обращается к базе данных Postgres, чтобы получить информацию

Хранение векторов

По каждому пользователю будет храниться вектор в СУБД LanceDB9.

image

Конфигурации

  • Обучаем модель на мощном сервере с GPU
  • При открытии главной страницы выполняется запрос в нейро сервис.
  • К базе с user_search ~ 100 RPS. На один запрос процессорного времени сервера с базой данных: 100 ns доступ к памяти + 10 ms получение N элементов, значит достаточно 2-х серверов с Postgres со следущими конфигурациями 2x6338/16x32GB/2xSSD4T/2x25Gb/s, на этих же серверах будут работать воркеры, предоставляющие API для взаимодействия с нейронной сетью.
  • Время ответа нейронной сети - 100 ms, поэтому нужно будет запустить 20 воркеров, которые будут балансироваться с помощью NGINX.

Часть 8. Технологии

Технология Применение Обоснование
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 Масштабирование, отказоустойчивость, оптимальная утилизация ресурсов

Часть 9. Схема проекта

image

Сервисы:

  1. DataAPI сервис отвечает за простые CRUD операции. Также при удалении объявлений этот сервис отправляет в кафку сообщение для удаления изображения из хранилища изображений.
  2. Поиск отвечает за поиск объявлений. В случае поиска по названию - ищет id объявлений в Elasticsearch. Затем формирует запрос с нужными фильтрами и через API Gateway запрашивает нужные объявления из DataAPI сервис.
  3. Рекомендации создают и пересчитывают вектора пользователей для рекомендаций. Действия пользователей (просмотр и поиск) попадают в neuro модель для пересчета векторов. Когда пользователь запрашивает рекомендуемые объявлений, то сервис рекомендаций на основе вектора пользователя через API Gateway запрашивает нужные объявления из DataAPI сервис.

Часть 10. Обеспечение надёжности

Система должна быть устойчива к сбоям, тогда её можно назвать отказоустойчивой.

Аппаратные сбои

Дата-центры

  • Резервирование физических линии связи
  • Резервирование охлаждения
  • Распределённые и независимые ДЦ
  • Периодические учения с отключением ДЦ
  • Две линии питания
  • Аварийные дизель-генераторы
  • Бесперебойное питание
  • В случае отказа одного из ДЦ нагрузка на другой может быть равна пиковой нагрузке всего приложения, поэтому конфигурации каждого ДЦ должны позволять единолично выдерживать всю нагрузку.

Сервисы

  • Резервирование ресурсов (CPU, RAM)
  • Резервирование физических компонентов (сервера, диски и т.д.)
  • Резервирование хранилищ — схема реплецирования
  • ClickHouse — внутренняя система реплицирования12
  • Наличие реплик для каждого сервиса, а также балансер, который распределяет нагрузку между репликами
  • Сбор логов и метрик
  • Отслеживане различных метрик (CPU, RAM и т.д.) с помощью дашбордов
  • Использование брокеров сообщений для асинхронного взаимодействия
  • Использование архитектурных паттернов:
    • Circuit Breaker13 - позволяет перекрыть сервис, который начинает слишком часто возвращать ошибки. В таком случае у сервиса будет время для восстановления
    • Timeout13 - если сервис не отвечает дольше установленного времени, то мы перестаем ждать ответ и отправляем запрос в реплику, если она есть. Если реплики нет, то возвращаем ошибку.
  • Graceful shutdown - механизм, который позволяет понять, что система по какой-то причине намерена завершить процесс, чтобы программа могла очистить ресурсы и завершить все процессы.
  • Graceful degradation - принцип разработки, который предусматривает, чтобы при возникновении проблем или недоступности определенных функций или ресурсов приложение продолжало работать, предоставляя пользователю максимально возможный функционал. То есть, при возникновении проблем приложение может "спадать" до менее функционального состояния, но при этом оставаться работоспособным, вместо полного отказа в работе.

Программные ошибки

  • Сбор логов и метрик
  • Алёртинг инцидентов

Человеческий фактор

  • Тестирование (от модульных до комплексного и ручного)
  • Настроенные CI/CD с тестированием и деплоем + удобное восстановление
  • Подробный и ясный мониторинг
  • Документация системы

Безопасность

  • Виртуальный уровень защиты 14
    • Приложение должно быть устойчиво к уязвимостям из OWASP Top Ten15 и другим рискам безопасности.
    • Доступы к различным компонентам системы должны быть строго разграничены.
  • Физический уровень защиты 14
    • Контроль доступа в дата-центр
    • Дополнительная защита инженерных компонентов
    • Пожарная безопасность ЦОД

Часть 11. Расчёт ресурсов

Конфигурации одного ДЦ

Далее используем пиковую нагрузку по 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

  1. Статистика Авито в 2024 году 2 3 4 5 6 7 8 9 10 11

  2. Авито Playbook

  3. Введение в современную сетевую балансировку и проксирование

  4. Nginx: принципы работы и настройка

  5. Руководство по PostGIS: 4.5. Построение индексов 2

  6. PgBouncer для PostgreSQL

  7. B-Tree индекс и его производные в PostgreSQL

  8. Построение рекомендательных систем с использованием нейронных сетей

  9. Векторные СУБД и другие инструменты для разработки ML-моделей 2

  10. Benchmarking and sizing Elasticsearch

  11. Производительность | ClickHouse Docs

  12. Репликация данных Clickhouse

  13. Паттерн Circuit Breaker 2

  14. Системы защиты центра обработки данных (ЦОД) 2

  15. OWASP Top Ten

  16. Latency Numbers Every Programmer Should Know

  17. NGINX Plus Sizing Guide: How We Tested

  18. Testing the Performance of NGINX and NGINX Plus Web Servers

  19. Rackmount Servers 2

  20. ИТ-Сопровождение компаний 2