Add the broker-comparison module
Kafka, RabbitMQ and Pulsar measured side by side on ordering, replay and consumer scaling by driving the three client libraries directly, plus an operational-footprint measurement of each broker's own distribution. Nine tests, three brokers started without Docker, and every number in the documentation regenerated by scripts/run-all.sh.
This commit is contained in:
66
broker-comparison/docs/02-ordering.md
Normal file
66
broker-comparison/docs/02-ordering.md
Normal file
@@ -0,0 +1,66 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user