> В каких случаях лучше использовать брокер сообщений для взаимодействия между сервисами (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Wildberries
Стек: Go
> Пример ответа
Короткий ответ
Брокер сообщений оправдан при асинхронной, слабосвязанной коммуникации между сервисами: фоновые задачи, fan-out события, буферизация пиковых нагрузок, гарантированная доставка и отказоустойчивость. Для синхронных запрос-ответных взаимодействий с низкой задержкой (например, API gateway → backend) лучше использовать HTTP/gRPC. Ключевой критерий - нужна ли вам немедленная обработка результата или можно отложить её без потери бизнес-логики.
Подробное объяснение
Брокер сообщений (RabbitMQ, Kafka, NATS) решает задачи, которые HTTP-вызовы решают плохо:
- Асинхронность и развязывание по времени - producer не ждёт ответа, consumer может обработать позже. Это критично для email-рассылок, генерации отчётов, обработки медиа.
- Множественные потребители - одно событие (например,
order.created) может потреблять несколько сервисов независимо: аналитика, уведомления, инвентаризация. С HTTP пришлось бы делать N вызовов или оркестрацию. - Буферизация и сглаживание пиков - брокер выступает очередью: при всплеске запросов сервисы не падают, а накапливают сообщения и обрабатывают их в своём темпе.
- Гарантия доставки - брокер хранит сообщения до подтверждения от consumer (ack), что невозможно при простом HTTP POST.
- Retry и dead-letter - встроенные механизмы повторной обработки и карантина для ошибочных сообщений.
- Backpressure - consumer сам контролирует скорость потребления, не блокируя producer.
Не стоит использовать брокер, когда:
- нужен синхронный ответ (например, проверка баланса перед оплатой) - здесь брокер добавит задержку и сложность;
- трафик низкий и нет требований к гарантиям доставки - проще REST;
- требуется строгий порядок обработки с транзакционностью - брокер не даёт ACID, нужна идемпотентность и компенсация.
В Go с брокером часто работают через библиотеки: github.com/segmentio/kafka-go, github.com/rabbitmq/amqp091-go, github.com/nats-io/nats.go.
На практике
Типичные сценарии в Go-микросервисах:
- Event-driven архитектура - сервис заказов публикует события, остальные подписываются. Это даёт слабую связанность: добавление нового потребителя не требует изменения producer.
- Задачи с долгим выполнением - конвертация файлов, отправка push-уведомлений. HTTP-запрос вернёт 202 Accepted, а реальная работа уйдёт в очередь.
- Интеграция с внешними системами - брокер как буфер между нашим сервисом и медленным/нестабильным внешним API.
- CQRS и materialized views - команды пишут в основную БД, события через брокер обновляют read-модели.
Важно проектировать контракты сообщений версионированными (например, event.v1), предусматривать идемпотентность consumer (повторная доставка возможна), и настраивать мониторинг очередей (lag, error rate).
Пример кода
Пример публикации и потребления в Go с RabbitMQ:
GO// producerfunc publishOrderCreated(ch *amqp.Channel, order Order) error {body, _ := json.Marshal(order)err := ch.Publish("orders", // exchange"order.created", // routing keyfalse, false,amqp.Publishing{ContentType: "application/json",Body: body,DeliveryMode: amqp.Persistent,},)return err}// consumerfunc consumeOrderCreated(ch *amqp.Channel) {msgs, _ := ch.Consume("orders_queue", "", false, false, false, false, nil,)for msg := range msgs {var order Orderif err := json.Unmarshal(msg.Body, &order); err != nil {msg.Nack(false, true) // retrycontinue}processOrder(order)msg.Ack(false)}}
Как отвечать на собеседовании
Начните с чёткого разделения: синхронное vs асинхронное взаимодействие. Приведите 2-3 конкретных сценария из практики, где брокер решал проблему (пиковая нагрузка, множественные подписчики, гарантия доставки). Упомяните trade-off: сложность эксплуатации, необходимость идемпотентности, отсутствие транзакций. Если спросят про Kafka vs RabbitMQ - сравните по модели потребления (log vs queue), порядку сообщений, throughput.
Покажите, что понимаете, когда брокер - антипаттерн: например, для CRUD-операций с немедленным ответом. Хорошо добавить про backpressure и dead-letter - это признак senior-уровня.
Что проверяет интервьюер
- Понимание разницы между синхронной и асинхронной коммуникацией.
- Умение обосновать выбор инструмента под конкретные требования (latency, reliability, throughput).
- Знание паттернов: event-driven, competing consumers, publish-subscribe.
- Понимание ограничений брокеров: отсутствие транзакций, возможные дубликаты, сложность отладки.
- Практический опыт: как вы проектировали контракты, обрабатывали ошибки, настраивали retry.
Типичные ошибки
- Предлагать брокер для всего подряд - без анализа требований к задержке и синхронности.
- Игнорировать идемпотентность - не учитывать, что сообщение может прийти дважды.
- Не упоминать dead-letter и мониторинг - признак отсутствия production-опыта.
- Путать Kafka и RabbitMQ - не понимать, что Kafka - это лог с offset, а RabbitMQ - очередь с ack.
- Забывать про версионирование событий - при изменении структуры сообщения ломаются все потребители.
- Утверждать, что брокер гарантирует порядок - в общем случае это не так, нужен partitioning или single queue.
> Похожие задачи по Go
Для чего используется синтаксис срезов в Go
Зачем создавать слайс с длиной и емкостью вместо использования append в Go
Как называется операция переноса данных из нескольких таблиц в одну для оптимизации запросов
Что происходит при передаче данных между сервисами с брокером сообщений если сервис недоступен
> Похожие задачи по backend
Для чего используется синтаксис срезов в Go
Зачем создавать слайс с длиной и емкостью вместо использования append в Go
Как называется операция переноса данных из нескольких таблиц в одну для оптимизации запросов
Что происходит при передаче данных между сервисами с брокером сообщений если сервис недоступен
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью