Ответ
Напрямую отправлять сообщения конкретному инстансу Consumer нельзя. Сообщения в Kafka всегда отправляются в топики.
По умолчанию, если несколько Consumer'ов состоят в одной Consumer Group, Kafka автоматически распределяет партиции топика между ними для балансировки нагрузки. Однако, добиться доставки сообщения конкретному получателю можно несколькими способами:
-
Уникальная
Consumer Groupдля каждогоConsumer'а- Это самый простой способ для реализации паттерна "broadcast". Если каждый
Consumerнаходится в своей собственной группе, то каждый из них получит все сообщения из топика.
- Это самый простой способ для реализации паттерна "broadcast". Если каждый
-
Явное назначение партиций (
consumer.Assign)- Вместо подписки на топик (
Subscribe),Consumerможет явно запросить чтение из конкретной партиции. Если вы знаете, что нужныйConsumerдолжен обрабатывать партициюN, вы можете назначить её ему напрямую. - Пример на Go (confluent-kafka-go):
consumer.Assign([]kafka.TopicPartition{ {Topic: &topic, Partition: 0}, }) - Минусы: Этот подход отключает автоматическую балансировку и обработку сбоев. Если этот
Consumerупадёт, партицию никто не подхватит.
- Вместо подписки на топик (
-
Кастомный
Partitionerна сторонеProducer'аProducerможет определять, в какую партицию отправить сообщение, на основе ключа сообщения. Вы можете реализовать свою логику партиционирования, которая будет стабильно направлять сообщения с определённым ключом в одну и ту же партицию. Зная, какойConsumerслушает эту партицию, вы можете управлять доставкой.
Ответ 18+ 🔞
Да ты посмотри, какая дичь! Напрямую в инстанс Consumer'а сообщение запихнуть — это как пытаться накормить супом через замочную скважину. Не, ну ты попробуй, конечно. Ага, щас. Сообщения в Kafka — они всегда, блядь, в топики летят. Точка.
Ну ладно, сидишь ты такой, думаешь: «Как же мне этот пакет данных впихнуть именно Васе, а не Пете?». Автоматическая балансировка, эти ваши Consumer Group — они ж всех перемешают, как салат оливье. Петя съест то, что для Васи.
Но выходы есть, ёпта! Не то чтобы идеальные, но работают.
1. Уникальная группа для каждого чувака (Consumer Group)
Самый простой способ, если тебе нужно, чтобы все всё получили (broadcast, блядь). Просто сажаешь каждого Consumer'а в свою, отдельную, персональную группу. Как в армии: у каждого своя миска, и всем накладывают из одного котла. Все получат полную порцию. Проще некуда, но групп будет — овердохуища.
2. Жёсткое назначение партиции (consumer.Assign)
А вот это уже поинтереснее. Ты говоришь кафке: «Слушай сюда, дружок-пирожок. Этот вот мой потребитель — он будет читать только из партиции номер ноль. И ни с какой другой хуйни. Понял?».
На Go (confluent-kafka-go) это выглядит примерно так:
consumer.Assign([]kafka.TopicPartition{
{Topic: &topic, Partition: 0},
})
Выглядит-то круто, да? Прямой указатель! Но тут, блядь, подвох, как в дешёвой водке. Ты отключаешь всю магию Кафки! Автобалансировка? Хуй! Если твой спец-потребитель накроется медным тазом — партиция так и будет лежать мёртвым грузом, никто её не подхватит. Сам виноват, распиздяй.
3. Свой, кастомный Partitioner на стороне отправителя (Producer)
А вот это уже хитрая жопа. Ты настраиваешь того, кто отправляет (Producer), чтобы он сам решал, в какую партицию класть сообщение. Ключ сообщения — это как адрес на конверте. Сделаешь свой алгоритм, который будет всегда для «ключа-Васи» выбирать, скажем, партицию 2. И если ты заранее знаешь, что Вася слушает именно партицию 2 — то всё, блядь, схема сработала. Сообщение упорхнуло прямиком к нему в пасть.
Короче, напрямую — низя. Но можно накрутить такие схемы, что все будут думать, что ты волшебник. Главное — не обосраться с тем подходом, где отключается балансировка, а то потом будешь сидеть и думать: «Ну и нахуя я это сделал?».