> Как передать данные от одного сервиса к множеству читателей с брокером сообщений (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:
GOimport "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:
GOreader := 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 консьюмеров в одной группе.
> Похожие задачи по Go
Как называется операция переноса данных из нескольких таблиц в одну для оптимизации запросов
Что происходит при передаче данных между сервисами с брокером сообщений если сервис недоступен
Что такое consumer group в брокерах сообщений
Насколько знаком с Kubernetes на уровне пользователя
> Похожие задачи по backend
Как называется операция переноса данных из нескольких таблиц в одну для оптимизации запросов
Что происходит при передаче данных между сервисами с брокером сообщений если сервис недоступен
Что такое consumer group в брокерах сообщений
Насколько знаком с Kubernetes на уровне пользователя
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью