Архитектура продакшн-проекта: полный стек
Ключевые тезисы:
Обзор реальной архитектуры работающей платформы с микросервисами, интеграциями и мониторингом.
Фундаментальные концепции (клиент-сервер, stateful/stateless, масштабирование, кэширование, наблюдаемость) применимы к любому стеку.
Каждая затронутая тема глубока и требует отдельного изучения.
Практический пример построения системы на 13 микросервисах (.NET/C#), но принципы универсальны.
Обзор проекта и инфраструктура
Текущий стек:
- Сервер: Одна VPS (8 ядер, 11 ГБ RAM).
- Оркестрация: Пока
Docker Compose, планируется переход на Kubernetes для серьёзного масштабирования. - Шлюз:
Nginxкак API Gateway для проксирования и балансировки запросов. - Фронтенд: Два отдельных приложения на Next.js:
- Основное SPA-приложение (клиентский рендеринг).
- Лендинг/маркетинговая часть (использует ISR для скорости и SEO).
- Бэкенд: 13 микросервисов на .NET/C#, разделённых по доменам (аутентификация, контент, прогресс, уведомления, AI, файлы и т.д.).
- Базы данных и хранилища:
PostgreSQL(основная БД, разделена на 13 схем по микросервисам).Redis(кэш, rate-limiting, временные данные).TypeSense(полнотекстовый поиск).RabbitMQ(брокер сообщений для асинхронной коммуникации).S3(Яндекс.Облако) для хранения файлов.Kinescope(для хранения и стриминга видео с CDN).
- Мониторинг: Стек Grafana (Prometheus для метрик, Tempo для трассировок, Loki для логов).
- CI/CD: Отдельный сервер с
GitLabи раннерами. - Внешние интеграции: Платёжная система,
Unisenderдля email, AI-провайдеры (DeepSeek, OpenAI Whisper).
Клиент-серверное взаимодействие и домены
Базовые концепции:
- Запрос-ответ: Браузер → Сервер → Браузер.
- Домены и DNS: Доменное имя преобразуется DNS в IP-адрес сервера.
Nginxанализирует хост-заголовок для маршрутизации.
Зачем несколько доменов/поддоменов?
- Разделение ответственности (лендинг vs. основное приложение vs. админка).
- Возможность использовать разные стеки, типы рендеринга (SSR, SSG, ISR) и требования к безопасности.
- Пример: Лендинг (
site.com) – статика, скорость, SEO. Основное приложение (app.site.com) – SPA, rich-взаимодействие.
Архитектура бэкенда: от монолита к микросервисам
1. Монолит
- Одно приложение, весь код в одном процессе.
- Риск превращения в "кашу" со слабым разделением ответственности.
2. Модульный монолит
- Одно приложение, но с чётко изолированными модулями внутри.
- Модули общаются через контракты/интерфейсы.
- Общая БД, но разделённая на схемы (логическая изоляция).
- Используются паттерны микросервисов (события через брокер), но масштабируется вся единица целиком.
3. Микросервисная архитектура
- Каждый модуль – отдельное, независимое приложение.
- Высокая степень изоляции (можно иметь отдельную БД или схему на сервис).
- Позволяет независимо масштабировать и развёртывать части системы.
- Выбор автора: Комбинация. Ключевая бизнес-логика в модульном монолите, а специализированные сервисы (файлы, аутентификация, AI) – как отдельные микросервисы.
Stateful vs Stateless сервисы
- Stateful сервис – хранит состояние (данные, сессии) в памяти процесса. Проблемы при масштабировании: если инстанс упадёт или запрос попадёт на другой инстанс, состояние будет потеряно.
- Stateless сервис – не хранит состояние внутри. Все данные сохраняются во внешнем хранилище (БД, кэш, S3). Любой инстанс может обработать запрос, обратившись к общему состоянию.
- Идеал: Делать сервисы stateless для горизонтального масштабирования. Исключения (например, сервис, держащий долгоживущие SSE-соединения) требуют специальных решений (хранение состояния соединений в Redis).
Организация кода: Чистая архитектура и Vertical Slice Design
Чистая архитектура:
- Набор принципов для разделения приложения на слои с чёткими направлениями зависимостей.
- Слои (от центра к периферии):
- Домен (ядро, бизнес-сущности и правила).
- Сценарии использования (Use Cases) – бизнес-логика.
- Адаптеры/Инфраструктура (работа с БД, внешними API).
- Зависимости идут от внешних слоев к внутренним. Домен ничего не знает о БД.
Vertical Slice Design (используется автором):
- Приложение делится не по слоям, а по фичам (вертикальным срезам).
- Вся логика одной фичи (endpoint, валидация, бизнес-логика, вызов репозитория) может быть сгруппирована вместе (даже в одном файле).
- Комбинация: Чистая архитектура + Vertical Slice =
Feature-Sliced Design(FSD). Принципы применяются и на фронтенде.
Структура проекта (пример):
- Отдельные проекты:
Domain,Core(Use Cases + Адаптеры),Infrastructure.Persistence,Infrastructure.Redis,Contracts(DTO для коммуникации),Tests.
Масштабирование
1. Вертикальное (Scale Up)
- Увеличение мощности сервера (CPU, RAM). Имеет физические и финансовые пределы.
2. Горизонтальное (Scale Out)
- Добавление нескольких экземпляров stateless-сервисов за балансировщиком нагрузки.
- Позволяет распределить нагрузку (30% на инстанс 1, 30% на инстанс 2 и т.д.).
- Требует инфраструктуры (Kubernetes) и тщательного проектирования (работа с транзакциями, репликация БД).
Коммуникация между микросервисами
1. Синхронная (HTTP, gRPC)
- Прямой запрос-ответ. Микросервис A ждёт ответа от микросервиса B для формирования своего ответа.
- Минус: Цепочка вызовов увеличивает задержку и создаёт tight coupling. Сбой одного сервиса ломает всю цепочку.
2. Асинхронная (через брокер: RabbitMQ, Kafka)
- Событийно-ориентированный подход. Сервис публикует событие ("задание выполнено") в брокер.
- Другие сервисы (нотификации, AI-проверка) подписываются и обрабатывают событие в фоне.
- Плюсы: Отвязка сервисов, повышение отказоустойчивости, пользователь не ждёт долгих операций.
- Паттерны: Для надёжности используется Outbox Pattern (чтобы события не терялись).
Аутентификация и авторизация
Базовая схема:
- Отдельный микросервис
Auth Service, реализующий OAuth 2.0 / OpenID Connect. - Генерация JWT-токенов (access token, refresh token).
- Flow: Браузер →
Auth Service→ Получает токены → Отправляет токен с каждым запросом к другим сервисам → Сервисы проверяют токен. - Хранение сессий/кодов: Для временных данных (коды подтверждения, access-листы) используется Redis.
- Альтернатива: Использование готовых Identity-провайдеров (Clerk, Auth0, Keycloak).
Работа с файлами и медиа
Принципы:
- В БД (PostgreSQL) хранятся только метаданные о файле (название, размер, путь, ID).
- Сами файлы хранятся в S3-совместимом объектном хранилище (Яндекс.Облако).
- Видео – в специализированном сервисе (Kinescope) для обработки, трансформации и CDN.
Механика отдачи файлов:
- Фронтенд запрашивает файл у
File Service. File Serviceгенерирует Presigned URL – временную ссылку напрямую в S3.- Ссылка отдаётся фронтенду, и файл загружается напрямую из S3, минуя бэкенд (эффективно и быстро).
- Загрузка больших файлов происходит чанками (мультипарт-загрузка).
Кэширование
Концепция Cache-Aside:
- Запрос при