Прежде чем добавлять RabbitMQ и Worker, важно понять: зачем вообще нужна асинхронная коммуникация? Синхронный HTTP работает — почему бы не продолжать его использовать? Event-Driven Architecture не только решает конкретные проблемы, но создаёт новые. Понимание сильных и слабых сторон подхода — ключевой навык архитектора.
YouTube — когда вы загружаете видео, оно не появляется мгновенно. YouTube принимает файл и ставит его в очередь на обработку: конвертация в разные разрешения (360p, 720p, 1080p, 4K), создание миниатюр, проверка на копирайт. Это занимает минуты или даже часы, но пользователь не ждёт — он может закрыть страницу и вернуться позже.
Instagram — при публикации фото оно сразу появляется в ленте, но в низком качестве. В фоне Instagram создаёт версии для разных устройств, применяет CDN-кэширование, обновляет ленты подписчиков. Всё это происходит асинхронно.
Яндекс GO — когда вы заказываете такси, приложение не блокируется на 30 секунд, пока система ищет водителя. Заказ создаётся мгновенно, а поиск водителя происходит в фоне. Вы видите анимацию "Ищем водителя...", а система тем временем рассылает уведомления ближайшим водителям.
Ozon, WB — при оформлении заказа вы не ждёте, пока склад проверит наличие товара, курьерская служба назначит доставку, а платёжная система обработает транзакцию. Заказ принимается мгновенно, остальное — в фоне.
В синхронной архитектуре вызывающий сервис ждёт ответа от вызываемого. Это создаёт несколько проблем:
1. Таймауты и каскадные сбои
Пользователь → API → Сервис A → Сервис B → Сервис C
↓
(таймаут 30с)
Если Сервис C медленно отвечает, вся цепочка блокируется. Пользователь ждёт 30 секунд и получает ошибку. Хуже того: пока он ждёт, занят один thread/goroutine в каждом сервисе. При высокой нагрузке это приводит к исчерпанию ресурсов.
2. Tight Coupling (тесная связанность)
Сервис A знает адрес Сервиса B и зависит от его доступности. Если Сервис B упал — Сервис A не может работать. Это противоречит идее независимых сервисов.
3. Блокировка ресурсов
HTTP-соединение занято, пока идёт обработка. Если обработка длится 10 секунд — 10 секунд занят сетевой ресурс. При 1000 параллельных запросах нужно 1000 соединений.
4. Плохой UX для долгих операций
Пользователь не хочет смотреть на спиннер 30 секунд. Лучше показать "Запрос принят, результат будет готов через минуту" и освободить пользователя.
В Event-Driven Architecture сервисы общаются через посредника — Message Broker. Вместо прямого вызова сервис публикует сообщение (event) в очередь, а другой сервис его забирает и обрабатывает.
Синхронно:
Сервис A ──HTTP──► Сервис B (A ждёт ответа)
Асинхронно:
Сервис A ──►[Очередь]──► Сервис B (A не ждёт)
Преимущества:
Loose Coupling (слабая связанность) — сервисы не знают друг о друге напрямую. Сервис A публикует сообщение "Загружено изображение", ему всё равно, кто его обработает.
Отказоустойчивость — если Сервис B упал, сообщения накапливаются в очереди. Когда он поднимется — обработает всё. Ничего не потеряно.
Масштабирование — можно запустить 10 workers для обработки очереди. Message Broker сам распределит сообщения.
Fire-and-Forget — сервис отправил сообщение и забыл. Не нужно ждать ответа, держать соединение, обрабатывать таймауты.
Пиковые нагрузки — очередь сглаживает пики. Если пришло 1000 запросов в секунду, они встанут в очередь и обработаются постепенно.
/ Message Broker — посредник, который принимает сообщения от одних сервисов и доставляет другим. Примеры: RabbitMQ, Apache Kafka, Amazon SQS, Redis Streams. Это как почтовое отделение: отправитель оставляет письмо, получатель забирает когда удобно.
(отправитель) — сервис, который отправляет сообщения в очередь. В нашем случае books-service будет producer: он публикует сообщение "Нужно обработать изображение".
(потребитель) — сервис, который читает сообщения из очереди и обрабатывает их. В нашем случае worker-service будет consumer: он забирает сообщения и обрабатывает изображения.
Queue (очередь) — место хранения сообщений. Сообщения хранятся в очереди, пока consumer их не заберёт. Очередь гарантирует, что сообщение не потеряется.
Event-Driven Architecture — не серебряная пуля. Есть сценарии, где синхронный подход лучше:
Нужен немедленный ответ
Пользователь логинится — ему нужен токен прямо сейчас, а не через 5 минут. Здесь синхронный запрос к auth-service оправдан.
Простой CRUD без тяжёлой обработки
Создание записи в базе занимает миллисекунды. Зачем городить очередь?
Транзакционная целостность
Нужно атомарно обновить несколько таблиц. С очередями это сложнее (нужны паттерны Saga, Outbox).
Маленькая команда и простая система
Message Broker добавляет операционную сложность: мониторинг очередей, обработка проваленных сообщений, настройка политики ретраев. Для простого приложения это overkill.
В этом проекте мы используем Event-Driven Architecture для обработки обложек книг:
Пользователь не ждёт обработки — он сразу видит "Обложка обрабатывается" и может продолжить работу.
Зачем: Зафиксировать архитектуру асинхронной обработки в README до написания кода — чтобы понимать, какие компоненты добавляются и как они взаимодействуют.
Что делаем:
Обновите README.md проекта. Добавьте в него:
RabbitMQ — очередь сообщений для асинхронных задачMinIO — S3-совместимое хранилище для файлов (обложки книг)worker-service — фоновый обработчик задач из очередиПримерная структура обновлённого README:
## Асинхронная обработка ### Новые компоненты - **RabbitMQ** — очередь сообщений для асинхронных задач - **MinIO** — S3-совместимое хранилище для обложек книг - **worker-service** — фоновый обработчик задач из очереди ### Сценарий обработки обложки 1. Пользователь загружает изображение → books-service сохраняет оригинал в MinIO 2. books-service публикует сообщение в RabbitMQ 3. worker-service забирает сообщение, обрабатывает изображение (resize) 4. worker-service загружает результат в MinIO и обновляет статус в БД ### Почему асинхронно? Обработка изображений — тяжёлая операция (1-5 секунд). Если делать синхронно, пользователь будет ждать. Асинхронный подход: пользователь сразу получает ответ "обложка обрабатывается", а результат появляется в фоне.
README.md существует в корне проекта и содержит описание асинхронной архитектурыREADME.md описаны 3 новых компонента: RabbitMQ (очередь сообщений), MinIO (хранилище файлов), worker-service (фоновая обработка)README.md описан сценарий обработки обложки: загрузка → очередь → обработка → сохранение