Как передать данные от одного сервиса к множеству читателей с брокером сообщений
Что проверяют
Понимаете ли вы разницу между «каждый читатель получает все сообщения» и «читатели делят поток между собой». Это главная развилка вопроса, и в Kafka и RabbitMQ она настраивается по-разному. Следом спрашивают про гарантии: что будет, если читатель упал посреди обработки.
Как отвечать
- Kafka: рассылку дают consumer group. Каждая группа получает топик целиком, а внутри группы партиции делятся между экземплярами. Значит, каждому сервису свой
GroupID, а реплики одного сервиса внутри своегоGroupIDмасштабируют обработку. Параллелизм группы ограничен числом партиций; - RabbitMQ: exchange типа
fanout(илиtopicдля фильтрации по ключу), у каждого сервиса своя очередь, привязанная к нему. Несколько консьюмеров на одной очереди это конкуренция за сообщения, а не рассылка. В Go клиентgithub.com/rabbitmq/amqp091-go; - NATS: обычная подписка на subject даёт рассылку без хранения, для сохранности и повторного чтения нужен JetStream;
- клиенты Kafka для Go:
segmentio/kafka-go,twmb/franz-go,confluent-kafka-go(обёртка над librdkafka, требует cgo),IBM/sarama.
Дальше гарантии. Доставка почти везде at-least-once, поэтому читатель должен быть идемпотентным. В kafka-go ReadMessage с GroupID коммитит оффсет сразу при чтении, и при падении посреди обработки сообщение потеряется. Надёжнее FetchMessage, обработка и только потом CommitMessages. Порядок гарантирован лишь внутри партиции, поэтому ключ сообщения выбирают по сущности, например по id заказа. Чтобы запись в базу и отправка события не разъехались, у отправителя применяют transactional outbox.
Где спотыкаются
Дают всем читателям одинаковый GroupID и удивляются, что каждый видит только часть сообщений.
Публикуют в fanout exchange до того, как созданы и привязаны очереди. RabbitMQ такие сообщения молча отбрасывает, а в Kafka новый читатель может прочитать топик с начала в пределах retention.
Запускают больше реплик консьюмера, чем партиций, и ждут роста пропускной способности. Лишние реплики не получат ни одной партиции и будут простаивать.