prev: [Three models](01-three-models.md) · [README](../README.md) · next: [Replay](03-replay.md) # 2. Ordering Every broker here is FIFO with one producer and one consumer. The question that matters is what survives the second consumer, because that is the first thing you add. ## Kafka: ordered within a partition, and a key picks the partition Twelve records, three keys, three partitions ([`docs/output/kafka-ordering.txt`](output/kafka-ordering.txt)): ``` F -> partition [2] values [2, 5, 8, 11] A -> partition [1] values [1, 4, 7, 10] D -> partition [0] values [3, 6, 9, 12] ``` Each key's values come back in the order they were produced. The global sequence does not: the consumer drains one partition's buffer before moving to the next, so the delivered order is 2, 5, 8, 11, 1, 4, 7, 10, 3, 6, 9, 12. That is the whole Kafka ordering guarantee, and it is usually enough, because "in order" nearly always means "in order per customer / per account / per device" rather than globally. **A detail worth stealing.** The keys in that transcript are D, A and F, not A, B and C. With three partitions, murmur2 sends A, B *and* C all to partition 1. Picking three obvious keys to demonstrate partitioning would have produced a transcript in which global order was accidentally preserved. Before you conclude that your keys spread evenly, compute `Utils.toPositive(Utils.murmur2(key)) % partitions` for the ones you actually use. ## RabbitMQ: FIFO per queue, and no key at all One consumer sees the queue in order. Two consumers do not ([`docs/output/rabbit-ordering.txt`](output/rabbit-ordering.txt)): ``` one queue, one consumer : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] one queue, two consumers : [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 12] ``` Message 1 went to the slower consumer and finished tenth. There is no key and no partition, so there is nothing to pin related messages to one consumer. Ordering across related messages in RabbitMQ means one queue and one consumer — which means no horizontal scaling of that queue — or the consistent-hash exchange, which is a plugin and effectively reintroduces partitions by hand. ## Pulsar: the subscription type decides, per subscriber Two consumers on a `Shared` subscription and two on `Key_Shared`, same topic, same messages ([`docs/output/pulsar-ordering.txt`](output/pulsar-ordering.txt)): ``` Shared A -> [consumer-1, consumer-2] B -> [consumer-1, consumer-2] C -> [consumer-1, consumer-2] Key_Shared A -> [consumer-2] B -> [consumer-1] C -> [consumer-2] ``` Under `Shared`, every key was handled by both consumers, so two messages with the same key can be in flight at once and no ordering claim survives. Under `Key_Shared`, each key went to exactly one consumer — Kafka's guarantee, but chosen by the subscriber rather than fixed by a partition count someone picked when the topic was created, and recomputed as consumers join and leave. That last property is the strongest single argument for Pulsar: two teams reading the same topic can make different ordering-versus-throughput trades without negotiating. next: [Replay](03-replay.md)