How does the destination property map onto Kafka vs RabbitMQ, especially once a consumer group is involved?
answer
- destination default = binding name (set it!)
- Kafka: destination -> topic; group -> consumer group
- Rabbit: destination -> topic exchange; queue = destination.group
- No group -> broadcast (Kafka latest / Rabbit auto-delete)
- group = durability + competing consumers
basics
~20 sThe destination is the logical target name. On Kafka it becomes a topic. On RabbitMQ it becomes a topic exchange; adding a consumer group creates a durable queue named destination.group bound to that exchange, so the same config means different physical objects per broker.
solid answer
~40 sdestination is set per binding via spring.cloud.stream.bindings.<name>.destination and names the logical target. The Kafka binder maps it directly to a topic. The RabbitMQ binder maps it to a Topic Exchange, and the queue is derived from the consumer group: with group=g the binder declares a durable queue <destination>.<g> bound to the exchange, so all instances in that group share the queue and compete for messages (load balancing). Without a group, Kafka assigns an anonymous consumer group per instance (each instance gets every message, starting at latest), and RabbitMQ declares an anonymous auto-delete exclusive queue per instance. So the same destination + group yields a shared Kafka consumer group vs. a shared durable Rabbit queue — the abstraction is uniform, the physical objects differ. Groups also give you durability and competing-consumer semantics on both brokers.
code
yaml · 15 linesspring:
cloud:
function:
definition: handleOrder
stream:
bindings:
handleOrder-in-0:
destination: orders # Kafka topic 'orders' | Rabbit exchange 'orders'
group: fulfilment # Kafka group 'fulfilment' | Rabbit queue 'orders.fulfilment'
consumer:
# Kafka-only knob (ignored by Rabbit binder):
# start-offset applies when the group has no committed offset
start-offset: earliest
handleOrder-out-0:
destination: shipmentsgo deeper
Should know destination names the target and that Kafka=topic, Rabbit=exchange.
Should explain the group -> durable-queue-vs-consumer-group distinction and the no-group broadcast pitfall.
Should cover partitioning emulation on Rabbit and start-offset/provisioning gotchas.
Should reason about prod provisioning policy (disable auto-create), and where the uniform model breaks down operationally.
**The `destination` property** is the core mapping knob. You set it per binding: `spring.cloud.stream.bindings.<bindingName>.destination=orders`. If you omit it, the destination defaults to the **binding name** itself (e.g. `process-in-0`), which is rarely what you want — always set it explicitly. **Kafka binder mapping.** `destination` becomes a **topic** of that name. The binder can auto-create it (`spring.cloud.stream.kafka.binder.auto-create-topics=true`, default true) with configurable partition count. A **consumer group** (`spring.cloud.stream.bindings.<in>.group=g`) maps directly to a **Kafka consumer group** — Kafka's native mechanism where partitions are distributed across instances so each message is processed once per group (competing consumers). **No group** ⇒ SCS assigns a unique anonymous group id per instance, so every instance receives every message, and the default start offset is **latest** (you miss messages published while down). This is the pub/sub broadcast style. **RabbitMQ binder mapping.** RabbitMQ has no topics; it routes via **exchanges** and **queues**. `destination` becomes a **Topic Exchange** named `orders` by default. The actual message store is a **queue**: - **With group `g`:** the binder declares a **durable** queue named `<destination>.<group>` (e.g. `orders.g`) and binds it to the exchange. All instances sharing that group consume from the one queue → competing consumers / load balancing, and messages survive restarts because the queue is durable. - **Without group:** the binder declares an **anonymous, auto-delete, exclusive** queue per instance (name like `orders.anonymous.<uuid>`). Each instance gets its own copy → broadcast. The queue vanishes when the instance disconnects, so undelivered messages are lost. **The unifying concept: consumer group = durability + competing consumers.** On both brokers, giving a binding a `group` means "these instances are one logical consumer; deliver each message once across the group, and keep messages while we're down." The physical realization differs (a Kafka consumer group vs. a durable Rabbit queue) but the SCS semantics are identical — that's the abstraction's payoff. **Partitioning.** SCS also abstracts partitioning: producers set `producer.partition-key-expression`/`partition-count`; consumers set `consumer.partitioned=true` and `instance-count`/`instance-index`. Kafka maps this to native topic partitions. RabbitMQ has no native partitions, so the binder emulates them by creating multiple partitioned queues (`orders.g-0`, `orders.g-1`, …) with routing keys. Again: same config, different physical implementation. **Gotchas.** - Forgetting `group` on a consumer is the classic bug: you scale to 3 instances expecting load balancing but each processes every message (Kafka anonymous group) — or worse, lose messages across restarts (Rabbit auto-delete queue). - Kafka anonymous consumers default to `latest`; set `startOffset=earliest` if you need history. - Auto-provisioning (topics/exchanges/queues created for you) is convenient in dev but many teams disable it in prod and provision infrastructure explicitly.
- You deploy 3 instances of a consumer with no group set. On Kafka, how many times is each message processed?Three times — one per instance. Without a group, each instance gets its own anonymous consumer group, so all three receive every message. Set a shared group for competing-consumer/load-balanced processing.
- On RabbitMQ, what is the name of the queue created for destination=orders, group=billing?orders.billing — a durable queue bound to the orders topic exchange. All instances in the billing group consume from it.
saying these in an interview costs you the question
- Assuming multiple instances auto-load-balance without setting a group
- Thinking RabbitMQ has topics like Kafka — it has exchanges + queues
- Believing destination alone guarantees message durability (durability comes from group/durable queue)