rabbitmq consistent-hash exchange harness
rabbitmq consistent-hash exchange harness
This harness runs a digest-pinned RabbitMQ 4.0 broker with the
rabbitmq_consistent_hash_exchange plugin enabled and measures what the
x-consistent-hash exchange actually does: it hashes each message’s routing key
onto a ring and routes it to exactly one bound queue, so the same key always lands
on the same queue, and adding a queue reshuffles only a small slice of the keys
instead of almost all of them.
Three experiments, all against the real broker via pika:
- A. Distribution evenness — 8 equally-weighted queues (binding key
"1"), publish ~100k messages over ~50k distinct routing keys (user-<n>), then read each queue’s depth and report the spread against the idealtotal/8. - B. Rebalance cost — map K=10k distinct keys across 8 queues, add a 9th queue, and count how many keys changed queue. Then, on the same keys, compute a naive
hash(key) % 8vshash(key) % 9in Python and count how many changed. Consistent hashing should remap ~1/9 (~11%); modulo churns almost everything (~87%). - C. Affinity — send several copies of each key on the 8-queue ring and confirm every key coalesces to exactly one queue.
These are laptop measurements demonstrating the mechanism, not a throughput or
capacity benchmark. The queue weight is left at "1" (equal weight) as the plugin
intends; the plugin places many ring points per binding, so even at weight 1 the
distribution is close to even and the 8→9 remap lands near the theoretical 1/9.
Run it
Docker with Compose v2, plus Python 3.9+.
cd benchmarks/rabbitmq-consistent-hash
docker compose up -d --wait # AMQP on :6672, management on :16672 (loopback)
python3 -m venv /tmp/chx-venv && source /tmp/chx-venv/bin/activate
pip install -r requirements.txt
python benchmark.py | tee results/summary.txt
docker compose down -v
The plugin is enabled by mounting enabled_plugins
([rabbitmq_management,rabbitmq_consistent_hash_exchange].) into
/etc/rabbitmq/. The broker binds to loopback on non-default host ports (6672 /
16672) to avoid clashing with a local RabbitMQ. The image is multi-arch and runs
natively on arm64.
Env overrides: RABBITMQ_HOST (127.0.0.1), RABBITMQ_PORT (6672),
RABBITMQ_MGMT_PORT (16672), RESULTS_DIR (./results).
Results
summary.txt— the captured console run used in the post (RabbitMQ 4.0.9).distribution.csv— per-queue message counts, ideal, and deviation from experiment A.rebalance.csv— consistent-hash vs modulo remap counts and percentages from experiment B.run_metadata.csv— RabbitMQ version, pinned image digest, ports, and the headline numbers.
The mechanism (a routing key hashes to one queue on a ring; adding a queue only moves the keys in the new queue’s arc) is not version-specific. What you’re measuring here is that the real broker’s ring behaves like textbook consistent hashing: even spread and a ~1/9 remap on scale-out, against a modulo baseline that remaps nearly everything.