Киносервис — это платформа для управления пользователями, ролями и получения контента онлайн-кинотеатра. Проект построен на микросервисной архитектуре с использованием современных технологий.
🔥➡️Описание дипломного проекта в отдельном документе⬅️🔥
- 🎥 KINOSERVICE
- 🚀 Запуск проекта
- 👤 Создание суперпользователя
- 🛠 Сервисы проекта
- 📂 Структура проекта
- 🛠 Используемые технологии
- 👥 Ролевая модель
- 🗺️ Архитектурный ландшафт
- Основной сценарий авторизации пользователя
- 🌟 Интеграция авторизации через Yandex
- 📖 Полезные команды
- 👥 Авторы
- Создайте
.env, скопировав содержимое.env.exampleв.env. - В корневой директории проекта выполните команду:
docker compose up -d --build
Для создания суперпользователя выполните следующие шаги:
-
Запустите Docker Compose:
docker compose up --build -d
-
Создайте суперпользователя через терминал:
bash scripts/create_superuser.sh
или
docker compose exec auth-api python manage.py createsuperuserили
docker compose exec admin-panel python manage.py createsuperuser
Сервис управления пользователями и пользовательскими сессиями.
Сервис для получения контента кинотеатра.
Сервис админ-панели проекта.
Сервис метрик предоставляет возможность отправки пользовательских событий в колоночную БД (ClickHouse) через брокер Kafka для дальнейшей аналитики.
Перед реализацией сервиса необходимо выявить функциональные и нефункциональные требования к сервису, также рассмотреть сценарий взаимодействия клиента и сервиса.
Функциональные требования:
- Сервис должен позволять принимать события клиента как от авторизованных пользователей, так и от анонимных пользователей.
- Доступ к метрикам должен предоставляться строго администраторам или аналитикам системы.
- Сервис должен позволять обрабатывать данные в реальном времени.
- Сервис должен проводить валидацию принимаемых данных, включая:
- Проверку наличия обязательных полей: event_type, timestamp(пользователя).
- Проверку корректности формата timestamp (ISO 8601).
- Проверку допустимых значений event_type (лайк, комментарий, просмотр фильма и др.).
- Каждое событие должно содержать обязательные поля event_type(лайк, коммент, просмотр фильма), timestamp(пользователя), если пользователь авторизован - поле с jwt.
- Сервис должен быть документирован в формате OpenAPI.
- Сервис должен сохранять события в колоночную бд, для дальнейшей аналитики.
- В брокере сообщений необходимо предусмотреть разделение данных(топиков) по конкретным событиям на основе event_type (лайки, просмотры, комментарии и тд.)
Нефункциональные требования:
- API для сбора метрик должна предусмотреть использование CORS для предотвращения подделки запросов.
- API для сбора метрик должна позволять ограничивать количество запросов Rate limiting (1000 запросов/мин с одного IP или устройства), для избегания спама.
- API принимает события только в формате JSON.
- Обработка одного события не превышает 100мс, без учёта сетевых взаимодействий.
- Валидация запроса не должна превышать 15 мс.
- API должен поддерживать асинхроное взаимодействие, для обеспечения быстрого отклика системы.
- API должен взаимодействовать с брокером сообщений по стилю One-Way и использовать гарантию доставки At Most Once (для обеспечения быстрого взаимодействия между компонентами).
- Подразумевается что активных пользователей в день 1.000.000 (DAU), каждый пользователь посещает сайт ~3 раза в сутки, совершая ~25 действий, отсюда следует, что средний RPS системы будет равен: (1.000.000 * 3 * 25) / 24 часа = 75.000.000 / 86.400 = 868 RPS. Для расчета пиковой нагрузки используем правило 80/20, согласно которому 80% трафика приходится на 20% времени. То есть, пиковая нагрузка будет в 5 раз выше средней: 868 * 5 = 4340 RPS
Сценарий взаимодействия клиента и сервиса метрики:
- Пользователь на стороне клиента совершает какое-либо событие (лайк, комментарий).
- Клиент фиксирует событие пользователя.
- Клиент выполняет POST запрос в сервис.
- Сервис валидирует входящее событие, направляет в очередь (брокер сообщений)
- Сервис отдает статус 200 при успешном запросе, без тела ответа ИЛИ статус 400 с описанием ошибки
Аналитическое сравнение приводится в следующем README
Аналитическое сравнение приводится в следующем README
В проекте присутствует Jaeger для трассировки запросов. Его UI доступен по ссылке.
Для визуализации данных из Elasticsearch используется Kibana. Ее интерфейс доступен по ссылке.
Для визуализации логов из Elasticsearch-logs используется Kibana. Ее интерфейс доступен по ссылке.
- Перейти в раздел "Manage spaces" кликнув на иконку пространства.
- Перейти в раздел "Data Views" в левом боковом меню.
- Нажать "Create data view".
- Создать новый "data view" с "Index pattern" = "docker-logs*".
- Перейти в раздел "Discover" кликнув на соответствующий раздел в боковом меню.
- Делать запросы, настраивать фильтры, наслаждаться.
- Необходимо запустить сервисы командой make content-service-up там поднимутся auth-api и content-api.
- Далее необходимо перейти на localhost:8005 откроется веб интерфейс GlitchTip
- После перехода выполни все действия как в видео
- После того как добавишь dns в
.envобязательно замениlocalhost:8005наglitchtip-web:8000(в .env.example указан пример в комментариях) - В
.envУкажиIS_GLITCHTIP_ENABLED=True - Далее необходимо перезапустить контейнер content-api
docker compose up -d --build content-actions-api - Для теста создал эндпоинт который вызывает исключение при делении на 0 /private/glitchtip-test. Дерните его, сервис отдаст 500, а в логах можно будет увидеть что сообщение отправлено, гляньте в веб интерфейс GlitchTip там появится новое сообщение с исключением.
На нашей платформе пользователи могут активно взаимодействовать с контентом, создавая уникальный пользовательский опыт (UGC). Основные возможности:
- Рецензии на фильмы: Пишите развернутые отзывы о просмотренных фильмах, делитесь впечатлениями и обсуждайте их с сообществом.
- Оценки фильмов: Ставьте рейтинги фильмам, чтобы влиять на их популярность и помогать другим пользователям в выборе.
- Закладки: Сохраняйте понравившиеся фильмы в личный список, чтобы легко вернуться к ним позже. Эти функции делают платформу живой и интерактивной, позволяя каждому пользователю стать частью кинематографического сообщества!
С сервисами контекста можно ознакомиться на диаграмме.
Контекст решает следующие задачи:
- Административная панель (event-generator) API для создания рассылок менеджерами проекта.
- Сервис нотификаций (notification-processor) реализующий:
- Обработка поступающих фиксированных событий в проекте:
- Регистрация пользователя.
- Лайк на комментарий пользователя к фильму.
- Массовая рассылка уведомлений всем пользователям.
- Обогащение поступающих запросов на отправку нотификации дополнительными данными.
- Управление временем отправки уведомления в соответствии с таймзоной пользователя и приоритетом.
- Уведомления отправляются с 9 до 20 часов по таймзоне пользователя (по умолчанию МСК).
- Управление жизненным циклом уведомления.
- Обработка поступающих фиксированных событий в проекте:
- Воркеры:
- WebSocket воркер (websocket-sender) - отправляет уведомления в активную сессию пользователя в приложении.
- Email воркер (email-sender) - отправляет уведомление в виде письма на email.
- Сервис сокращения ссылок (short-link-service) - реализует функционал сокращения ссылок и управления жизненным циклом сокращённой ссылки.
.env.exampleпереименовать в.env- Из корня проекта выполнить:
make up-notification-context - Выполнить регистрацию пользователя:
http://127.0.0.1/auth/openapi:- Метод:
POST: /auth/api/v1/sessions/register
- Метод:
- В логах notification сервиса будет сообщение об отправке уведомления о регистрации на email.
- Перейти к API сервиса нотификаций:
http://127.0.0.1/notification/openapi- Указать user_id зарегистрированного пользователя в атрибутах:
liked_by_user_id, user_idв методе:POST: /notification/api/v1/notifications/single-notificationи отправить запрос.- В логах notification сервиса будет сообщение об отправке уведомления о лайке на комментарий пользователя к фильму.
- Отправить массовую рассылку, также указав
user_idзарегистрированного пользователя:POST /notification/api/v1/notifications/mass-notification- В логах notification сервиса будет сообщение об обработке массовой рассылки.
- Сервис получит user_id всех пользователей по API Auth сервиса и для каждого создаст единичное уведомление.
- В логах notification сервиса будет сообщение об обработке массовой рассылки.
- Указать user_id зарегистрированного пользователя в атрибутах:
- Перейти к API сервиса сокращения ссылок:
http://localhost/link/openapi- Запросить сокращение любой http ссылки в методе:
POST: /link/api/v1/link/shorten - Перейти по ссылке из атрибута ответа:
short_url
- Запросить сокращение любой http ссылки в методе:
- Перейти в Админ панель менеджера
http://localhost/event-generator/openapi- Получить список шаблонов:
GET: /event-generator/api/v1/admin/templates - Отправить массовую нотификацию на всех пользователей:
POST: /event-generator/api/v1/notify/create-mass-notify
- Получить список шаблонов:
- Перейти в MailHog
http://localhost:8025/проверить доставку писем до адресатов. - Протестировать доставку WebSocket уведомлений можно с по адресу
ws://localhost/ws-notification/api/v1/ws-sender - Подключиться к БД и посмотреть жизненный цикл экземпляров уведомлений и коротких ссылок:
jdbc:postgresql://localhost:5432/pg_db
креды: postgres@postgres
yandex_kinoservice/
├── backup/ # Скрипты и данные для резервного копирования
│ ├── clickhouse_init_struct/ # Инициализация структуры ClickHouse БД
│ ├── elastic_dump/ # Дамп данных для Elasticsearch
│ │ ├── dump/ # Сырые дампы данных Elasticsearch (фильмы, жанры, персоны)
│ │ ├── dump_extractor/ # Скрипты для извлечения данных из Elasticsearch
│ │ └── dump_loader/ # Скрипты для загрузки данных в Elasticsearch
│ └── postgres_dump-auth/ # Дамп данных для PostgreSQL (пользователи, роли, права)
│ └── dumps/ # CSV-файлы с данными для импорта в PostgreSQL
├── docs/ # Документация проекта
│ ├── comparison_column_db/ # Аналитическое сравнение ClickHouse и Vertica
│ │ └── conf_clickhouse/ # Конфигурационные файлы ClickHouse для тестирования
│ ├── compare-mongodb-vs-postgres # Аналитическое сравнение Postgres и MongoDB
│ │ ├── docker-compose.compare-db.yml # Конфигурационные файлы для тестирования Postgres и MongoDB
│ │ ├── init_mongodb # Конфигурационные файлы для тестирования Postgres и MongoDB
│ │ ├── init_postgres # Конфигурационные файлы для тестирования Postgres и MongoDB
│ │ ├── README.md # Результаты исследования
│ │ ├── research/ # Конфигурационные файлы для тестирования Postgres и MongoDB
│ ├── kafka_usage_examples/ # Примеры использования Kafka в проекте
│ ├── test_tools/ # Инструменты для тестирования (создание пользователей и т.д.)
│ └── use_cases/ # Сценарии использования и UML диаграммы
├── infra/ # Инфраструктурные компоненты
│ ├── clickhouse/ # Конфигурация колоночной БД ClickHouse
│ ├── elk/ # ELK стек для логирования и мониторинга
│ │ └── config/ # Конфигурации Filebeat и Logstash
│ ├── glitchtip # Сервис для мониторинга ошибок (GlitchTip)
│ ├── kafka/ # Брокер сообщений Apache Kafka
│ ├── mongodb/ # Документоориентированная БД MongoDB
│ ├── nginx/ # Веб-сервер и обратный прокси
│ │ └── configs/ # Конфигурационные файлы Nginx
│ └── rabbit # Брокер сообщений RabbitMQ
│ └── queue_builder # Скрипты для создания очередей RabbitMQ
├── libs/ # Общие библиотеки для переиспользования
│ ├── auth_utils # Библиотека для авторизации и аутентификации
│ │ └── auth_utils # Исходный код библиотеки авторизации
│ ├── rate_limite_utils # Библиотека для ограничения частоты запросов (Rate Limiting)
│ │ └── rate_limite_utils # Исходный код библиотеки rate limiting
│ └── tracer_utils # Библиотека для трассировки запросов (Jaeger)
│ └── tracer_utils # Исходный код библиотеки трассировки
└── services # Микросервисы приложения
├── admin-panel # Административная панель Django
│ └── src # Исходный код админ-панели
├── async-api # Асинхронный API для получения контента (FastAPI)
│ ├── src # Исходный код async-api сервиса
│ └── tests # Функциональные и интеграционные тесты
├── auth-service # Сервис авторизации и управления пользователями (FastAPI)
│ ├── src # Исходный код auth-service
│ └── tests # Тесты для сервиса авторизации
├── content-actions-service # Сервис действий с контентом (лайки, закладки, рецензии)
│ ├── src # Исходный код content-actions-service
│ └── tests # Тесты для сервиса действий с контентом
├── email-sender # Сервис отправки email
│ ├── src # Исходный код email-sender
├── event-generator # Сервис генерации событий
│ └── src # Исходный код сервиса генерации событий
├── metric-service # Сервис метрик и аналитики пользовательских событий
│ ├── etl # ETL процессы для обработки метрик из Kafka в ClickHouse
│ ├── metric-api # API для сбора пользовательских событий (FastAPI)
│ └── tests # Тесты для сервиса метрик
├── notification-service # Сервис для обработки и отправки уведомлений
│ └── src # Исходный код сервиса уведомлений
├── short-link-service # Сервис сокращения ссылок
│ └── src # Исходный код сервиса сокращения ссылок
├── embedding-etl # ETL-процесс для обогащения данных фильмов эмбеддингами
│ └── src # Исходный код ETL-процесса
├── embedding-service # Сервис для генерации эмбеддингов
│ └── src # Исходный код сервиса эмбеддингов
├── nl-consumer # Сервис для обработки запросов на естественном языке
│ └── src # Исходный код сервиса обработки запросов
└── recs-profile # Сервис для формирования и обновления профилей рекомендаций
└── src # Исходный код сервиса профилей рекомендаций
- FastAPI — быстрый и асинхронный веб-фреймворк для создания API.
- Django — фреймворк для быстрой разработки веб-приложений.
- Flask — минималистичный веб-фреймворк для создания простых приложений.
- PostgreSQL — реляционная база данных для хранения структурированных данных.
- MongoDB — документоориентированная база данных для хранения данных о действиях пользователей.
- ClickHouse — колоночная база данных для аналитики и хранения метрик о действиях пользователей.
- Redis — система кэширования и управления сессиями для повышения производительности.
- Elasticsearch — поисковый движок для хранения, поиска фильмов и логирования данных.
- Logstash — инструмент для сбора, обработки и маршрутизации логов.
- Filebeat - сборщик логов для docker контейнеров.
- Docker & Docker Compose — контейнеризация и управление сервисами.
- Pydantic — валидация моделей.
- async_fastapi_jwt_auth — работа с JWT-токенами для аутентификации и авторизации пользователя.
- Nginx — веб-сервер и прокси-сервер.
- Pytest — фреймворк для тестирования.
- Kafka — распределенная платформа потоковой обработки данных для асинхронного обмена сообщениями между сервисами.
- RabbitMQ - брокер сообщений для асинхронной передачи событий. В проекте реализован кластер. Модель использования Pub-Sub.
- CI/CD — непрерывная интеграция и доставка с использованием инструментов GitHub Actions для автоматизации тестирования, сборки и развертывания.
- ollama3 - локальная модель для анализа пользовательского запроса на естественном языке.
- paraphrase-multilingual-MiniLM-L12-v2 - модель для генерации эмбеддингов по смысловой связи текста.
В системе реализована следующая ролевая модель:
- CRUD_ROLE - Управление ролями (создание, чтение, обновление, удаление)
- ASSIGN_ROLE - Назначение ролей пользователям
- FREE_FILMS - Доступ к бесплатным фильмам
- PAID_FILMS - Доступ к платным фильмам
- CRUD_FILMS - Полный доступ к управлению фильмами
- PAID_FILMS - Доступ к платным фильмам
- FREE_FILMS - Доступ к бесплатным фильмам
- FREE_FILMS - Доступ только к бесплатным фильмам
- FREE_FILMS - Доступ только к бесплатным фильмам
- CRUD_FILMS - полный административный доступ к контенту
- PAID_FILMS - доступ к премиум контенту (требуется подписка)
- FREE_FILMS - базовый уровень доступа, доступен всем пользователям
- Для проверки отзыва токенов пользователя используется локальная библиотека auth_utils:
- Библиотека реализует проверку с помощью запроса в Redis. Данное решение принято осознанно, так как использование HTTP-запросов к сервису авторизации на каждый запрос к сервису бизнес-логики мы посчитали неоптимальным с точки зрения производительности.
- Риски интеграции сервисов через БД приняты на данном этапе проекта.
- В ходе развития проекта планируется добавить событийную схему передачи факта отзыва сессии пользователя и избавиться от интеграции через БД.
- Библиотека реализует проверку с помощью запроса в Redis. Данное решение принято осознанно, так как использование HTTP-запросов к сервису авторизации на каждый запрос к сервису бизнес-логики мы посчитали неоптимальным с точки зрения производительности.
- Проверка прав пользователя реализована с помощью записи текущих прав непосредственно в JWT-токен:
- Полезная нагрузка токена:
{
"sub": "bf48004a-549c-4c83-ac84-f69ad1229d63",
"iat": 1746186562,
"nbf": 1746186562,
"jti": "7dd19a81-cc2a-40e5-9dd7-8c6e3322297d",
"exp": 1746187762,
"type": "access",
"fresh": false,
"user_id": "8b541aeb-9f82-4b2c-ac6f-fde3707262a7",
"session_id": "bf48004a-549c-4c83-ac84-f69ad1229d63",
"username": "dimaa",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"role_code": "ADMIN",
"permissions": [
"ASSIGN_ROLE",
"CRUD_FILMS",
"CRUD_ROLE",
"FREE_FILMS",
"PAID_FILMS"
]
}- При создании токена используется асимметричный алгоритм RS256:
- Приватный ключ известен только auth-api, который выпускает токены.
- Библиотека auth_utils использует только публичный ключ для верификации подписи.
- Модель фильма была доработана. Фильмы разделены на 3 группы:
- FREE - доступны всем пользователям, включая неавторизованных
- PAID - доступны пользователям, обладающим правами CRUD_FILMS / PAID_FILMS
- ARCHIVED - доступны пользователям с правами CRUD_FILMS
В проекте используется хэш-партиционирование для таблицы user_sessions_hist. Этот метод позволяет равномерно распределять данные между партициями на основе хэш-функции, применяемой к значению ключа партиционирования. В данном случае ключом партиционирования является поле user_id.
- Равномерное распределение данных: Хэш-функция обеспечивает равномерное распределение записей между партициями, что минимизирует дисбаланс.
- Ускорение запросов: Запросы, использующие ключ партиционирования, выполняются быстрее, так как они обращаются только к одной партиции. В рамках нашего бизнесс процесса получение истории сессий выполняется для одного пользователя по user_id
- Масштабируемость: Легко добавлять новые партиции при увеличении объема данных.
В ходе тестирования было проверено распределение данных между партициями. Результаты показали равномерное распределение записей:
| Партиция | Количество записей |
|---|---|
user_sessions_hist (total) |
35491 |
user_sessions_hist_p0 |
8935 |
user_sessions_hist_p1 |
8808 |
user_sessions_hist_p2 |
8851 |
user_sessions_hist_p3 |
8897 |
Тестовый запрос на получение данных
explain analyze select * from session.user_sessions_hist where user_id='5e3047c4-9910-4fbe-b414-bac5ced680ca'| QUERY PLAN |
|---|
| Index Scan using idx_user_sessions_hist_p2_user_id on user_sessions_hist_p2 user_sessions_hist (cost=0.29..8.30 rows=1 width=84) (actual time=0.020..0.021 rows=1 loops=1) |
| Index Cond: (user_id ='5e3047c4-9910-4fbe-b414-bac5ced680ca'::uuid) |
| Planning Time: 0.061 ms |
| Execution Time: 0.041 ms |
Результаты тестирования подтверждают, что выбранная методика хэш-партиционирования обеспечивает равномерное распределение данных между партициями. Это позволяет эффективно использовать ресурсы базы данных и ускоряет выполнение запросов.
Реализация OAuth2-авторизации через Yandex позволяет пользователям аутентифицироваться в сервисе с использованием учетных данных Yandex. Система поддерживает:
- Привязку аккаунта Yandex к существующему профилю.
- Отвязку сервиса в любое время.
- Авторизация и регистрация через сервис Yandex.
- Создайте приложение в Yandex ID для получения: Client ID, Client Secret
- Настройте Redirect URI
https://ваш-домен/auth/social/callback - Укажите полученные ключи в конфигурации сервиса
.env.
Получите параметры OAuth:
-
Вызовите
GET /auth/social, найдите в ответеauth_urlдля Yandex. -
Перейдите по
auth_url→ пользователь подтверждает доступ → Yandex перенаправляет наredirect_uriсcodeиstateв URL. -
Завершите авторизацию: Отправьте
POST /login/yandexс полученнымиcodeиstate. -
Получите токен: В ответе будет
access_tokenдля доступа к API
Makefile — это инструмент автоматизации, который позволяет упрощать выполнение часто используемых команд. В данном проекте Makefile используется для управления контейнерами и тестами.
Пример вызова команды с параметром:
make up srv=auth-api- Запускает все контейнеры в фоновом режиме с пересборкой образов. Можно указать
srvдля запуска конкретного сервиса.make up
- Останавливает все контейнеры. Можно указать
srvдля остановки конкретного сервиса.make down
- Останавливает все контейнеры и удаляет связанные тома. Можно указать
srvдля удаления томов конкретного сервиса.make down-v
- Запускает контейнеры и сразу выводит логи. Можно указать
srvдля просмотра логов конкретного сервиса.make up-logs
- Выводит логи всех сервисов или указанного через
srv.make logs
- Запускает тесты для сервиса async-api.
make test-async-api
- Запускает тесты для сервиса auth-api.
make test-auth-api
Запуск тестов async-api:
docker-compose -f docker-compose-tests.yml --profile async-api-test up --build -d && docker-compose -f docker-compose-tests.yml logs -f tests-async-api && docker-compose -f docker-compose-tests.yml --profile async-api-test down -vЗапуск тестов auth-api
docker-compose -f docker-compose-tests.yml --profile auth-api-test up --build -d && docker-compose -f docker-compose-tests.yml logs -f tests-auth-api && docker-compose -f docker-compose-tests.yml --profile auth-api-test down -vdocker compose down -v