> Как передать данные от одного сервиса к множеству читателей с брокером сообщений (Go)

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

Компании: Wildberries

Стек: Go

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

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

Для передачи данных от одного сервиса множеству читателей используйте паттерн publish/subscribe: сервис-производитель публикует сообщение в брокер (Kafka, RabbitMQ, NATS), а каждый читатель подписывается на топик/обменник и получает собственную копию сообщения. В Kafka это реализуется через consumer groups - каждая группа читает все сообщения независимо, а внутри группы партиции распределяются между консьюмерами. В RabbitMQ - через fanout exchange или отдельные очереди на каждого подписчика.

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

Ключевое отличие от point-to-point доставки - брокер хранит и размножает сообщения для каждого независимого читателя. В Kafka модель выглядит так: топик разбит на партиции, каждая consumer group получает все партиции топика, но конкретная партиция читается только одним консьюмером внутри группы. Если нужно N независимых читателей - создаётся N consumer groups с одинаковым group.id, но разными именами.

В RabbitMQ используется exchange типа fanout: сообщение копируется во все привязанные очереди, каждая очередь - отдельный читатель. Если нужна фильтрация - topic exchange с routing key.

Важные trade-off:

  • порядок сообщений гарантируется только в пределах партиции/очереди;
  • at-least-once доставка требует идемпотентности обработчиков;
  • при большом числе читателей растёт нагрузка на брокер (копирование данных);
  • retention в Kafka позволяет новым читателям прочитать историю с любого offset.

На практике

Для Go-сервиса с Kafka используйте библиотеку segmentio/kafka-go или confluent-kafka-go. Определите структуру сообщения, сериализацию (JSON/Protobuf), настройте продюсера с acks=all и идемпотентностью. Для читателей - создайте отдельную consumer group на каждого логического потребителя, настройте auto.offset.reset=earliest для чтения с начала.

Для RabbitMQ - amqp091-go. Создайте fanout exchange, каждый читатель объявляет свою эксклюзивную очередь с уникальным именем и биндит её к exchange. Настройте prefetch=1 и manual ack для надёжности.

Практические рекомендации:

  • используйте Protobuf для схемы данных;
  • добавьте correlation_id и trace_id для трассировки;
  • настройте retry и dead-letter queue для ошибок обработки;
  • мониторьте lag потребителей через метрики.

Пример кода

Публикация в Kafka на Go:

GO
import "github.com/segmentio/kafka-go"
writer := kafka.NewWriter(kafka.WriterConfig{
Brokers: []string{"localhost:9092"},
Topic: "orders",
Balancer: &kafka.LeastBytes{},
RequiredAcks: kafka.RequireAll,
})
err := writer.WriteMessages(ctx, kafka.Message{
Key: []byte(orderID),
Value: payload,
})

Чтение в consumer group:

GO
reader := kafka.NewReader(kafka.ReaderConfig{
Brokers: []string{"localhost:9092"},
Topic: "orders",
GroupID: "email-notifier",
Partition: 0,
MinBytes: 1,
MaxBytes: 10e6,
})
for {
msg, err := reader.ReadMessage(ctx)
if err != nil {
log.Fatal(err)
}
processOrder(msg.Value)
// коммит offset происходит автоматически после ReadMessage
}

Для нескольких читателей создайте несколько reader-ов с разными GroupID.

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

Начните с чёткого определения паттерна pub/sub, затем уточните, какой брокер используется. Покажите понимание разницы между Kafka и RabbitMQ: в Kafka читатели - это consumer groups, в RabbitMQ - очереди. Обязательно упомяните гарантии доставки и как обеспечить идемпотентность. Приведите конкретный пример из практики: как масштабировали читателей, как решали проблему дубликатов. Если спросят про порядок - объясните про партиции и ключи. Завершите рассуждением о мониторинге lag и обработке ошибок.

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

  • понимание модели pub/sub и её отличий от point-to-point;
  • знание конкретного брокера и его API;
  • умение рассуждать о гарантиях доставки (at-least-once, at-most-once, exactly-once);
  • понимание масштабирования читателей и партиционирования;
  • знание идемпотентности и обработки ошибок;
  • способность выбрать правильный брокер под задачу.

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

  • путают consumer group с отдельным читателем - одна группа не даёт множественной доставки;
  • забывают про ручной commit offset при необходимости повторной обработки;
  • используют один топик для разных типов событий без ключа - теряется порядок;
  • не настраивают retention и не думают о replay событий;
  • игнорируют dead-letter queue, из-за чего сообщения теряются при ошибках;
  • не учитывают, что при N читателях в Kafka нужно N групп, а не N консьюмеров в одной группе.

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

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