> Как используется RabbitMQ в проектах (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: InDrive

Стек: Go, Java

> Пример ответа

Короткий ответ

В Go и Java проектах RabbitMQ обычно применяют для асинхронной доставки сообщений между сервисами, разгрузки синхронных вызовов и реализации паттернов work queue, pub/sub, routing и RPC. На senior-уровне важны идемпотентность, подтверждения, dead letter queues, back pressure и порядок обработки. Выбор между RabbitMQ и Kafka определяется trade-off: маршрутизация и низкая задержка против лог-ориентированной потоковой обработки.

Подробное объяснение

RabbitMQ - это message broker с моделью AMQP, где producer публикует сообщение в exchange, exchange маршрутизирует его в queue по routing key или заголовкам, а consumer забирает из queue. В Go типично используют библиотеку amqp091-go, в Java - Spring AMQP или официальный Java client. Основные сценарии: разгрузка HTTP-запросов через фоновую обработку, интеграция микросервисов без жёсткой связности, распределение задач между воркерами, событийные уведомления и отложенные задачи через TTL и dead letter exchange. На senior-уровне обсуждают гарантии доставки: at-least-once достигается через publisher confirms и manual ack, exactly-once в общем случае не гарантируется и требует идемпотентного consumer. Важны prefetch, чтобы не перегружать consumer, и обработка poison messages через DLQ. Также учитывают порядок сообщений: он сохраняется в пределах одной queue и одного consumer, но нарушается при конкурентной обработке. Для RPC используют reply-to и correlation-id, хотя это увеличивает связанность. В высоконагруженных системах применяют quorum queues для репликации и устойчивости, а также шардирование по routing key. Сравнение с Kafka: RabbitMQ лучше для сложной маршрутизации и низкой задержки отдельных сообщений, Kafka - для потоковой обработки и replay.

На практике

В Go consumer запускают в отдельной горутине, настраивают channel с prefetch, обрабатывают сообщения с context timeout и подтверждают ack только после успешной записи в БД или отправки следующего события. При ошибке делают nack с requeue=false, чтобы сообщение ушло в DLQ. В Java аналогично настраивают SimpleMessageListenerContainer с concurrency и manual ack. Для идемпотентности хранят message-id в Redis или в таблице с уникальным индексом. Для отложенных задач используют per-message TTL и dead letter exchange. Мониторинг строят на RabbitMQ management plugin и метриках queue depth, unacked messages, publish rate. При деплое учитывают, что consumer должен быть готов к переподключению и повторной доставке.

Пример кода

GO
package main
import (
"context"
"log"
"time"
amqp "github.com/rabbitmq/amqp091-go"
)
func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
ch, err := conn.Channel()
if err != nil {
log.Fatal(err)
}
defer ch.Close()
q, err := ch.QueueDeclare("tasks", true, false, false, false, nil)
if err != nil {
log.Fatal(err)
}
err = ch.Qos(10, 0, false)
if err != nil {
log.Fatal(err)
}
msgs, err := ch.Consume(q.Name, "", false, false, false, false, nil)
if err != nil {
log.Fatal(err)
}
for msg := range msgs {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
if err := process(ctx, msg.Body); err != nil {
_ = msg.Nack(false, false)
} else {
_ = msg.Ack(false)
}
cancel()
}
}
func process(ctx context.Context, body []byte) error {
return nil
}

Как отвечать на собеседовании

Сначала назовите 2-3 ключевых сценария: асинхронная обработка, интеграция сервисов, распределение задач. Затем объясните модель exchange-queue-binding и гарантии доставки. Упомяните идемпотентность, DLQ, prefetch и publisher confirms. Сравните с Kafka по критериям маршрутизации, порядка и replay. Приведите пример из практики с Go или Java и покажите, как обрабатываете ошибки и повторные доставки. В конце отметьте мониторинг и эксплуатационные аспекты.

Что проверяет интервьюер

Понимание модели AMQP и топологии exchange. Умение выбирать гарантии доставки и обрабатывать повторные сообщения. Знание идемпотентности и DLQ. Опыт настройки prefetch и back pressure. Понимание ограничений порядка и exactly-once. Способность сравнить RabbitMQ с Kafka и обосновать выбор. Практические навыки в Go или Java: подключение, ack, reconnect, мониторинг.

Типичные ошибки

Использовать auto-ack и терять сообщения при падении consumer. Игнорировать идемпотентность при at-least-once. Ставить бесконечный requeue и получать poison message loop. Не настраивать prefetch и перегружать consumer. Ожидать exactly-once без транзакций и идемпотентности. Путать порядок сообщений в разных queue. Забывать про publisher confirms и терять сообщения на стороне producer. Выбирать RabbitMQ для потоковой обработки больших объёмов без оценки trade-off.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью