R8.06.1 · Operating EchoMQ — dive 1
Cluster colocation.
A single-node Valkey lets a Lua script touch any keys at all. A Valkey Cluster does not — a command may only touch keys in one of 16384 slots, or it is refused. A queue's keys must all land on one slot, and the keyspace makes them.
Grounding: EchoMQ.Keyspace.slot/1 and hashtag/1 (echo/apps/echo_mq/lib/echo_mq/keyspace.ex) · the vector slot("123456789") == 12739 · the engine is Valkey 9. The braced keyspace figure is bcs.3.md.
{q} hashtag, so the slot is computed from q alone and
all three land on the same slot.Static verdicts — all three keys carry the {q} hashtag, so
slot/1 computes the same slot for each; the whole queue is colocated, and a script over it stays in
one slot.
The hashtag and the slot
keyspace.ex · slot/1, hashtag/1Valkey Cluster gives applications one lever over placement: a hashtag. If a key contains a
{…} substring, the slot is computed from the bytes inside the braces alone, not the whole
key. So emq:{orders}:pending and emq:{orders}:active both hash on orders
— the same slot — even though the full keys differ. EchoMQ builds every queue key braced: the queue
name is the hashtag, every key of one queue shares it, and so every key of one queue lands on one slot.
EchoMQ.Keyspace.slot/1 computes that slot client-side: hashtag/1
returns the substring inside the first {…} when present and non-empty, else the whole key;
slot/1 is rem(crc16(hashtag(key), 0), 16384) — CRC16-XMODEM over the hashtag,
modulo 16384, the cluster specification's exact algorithm. Computing it client-side means the connector can
route a key to its node, and partition by slot, without a server round trip. The source pins one known vector:
slot("123456789") == 12739 (CRC16 0x31C3).
# Cluster slot of a key, computed client-side: CRC16-XMODEM over the # hashtag % 16384. Known vector: slot("123456789") == 12739 (0x31C3). def slot(key) when is_binary(key), do: rem(crc16(hashtag(key), 0), 16384) def hashtag(key) do with [_, rest] <- :binary.split(key, "{"), [tag, _] when tag != "" <- :binary.split(rest, "}") do tag ← the substring inside the first {…} else _ -> key ← no brace: the whole key hashes end end
Notes on ValkeyValkey Cluster splits the keyspace into 16384 hash
slots, and a key is mapped to a slot by CRC16(key) mod 16384; when a key holds a
{hashtag}, only the substring inside the braces is hashed, so an application can force related keys
onto one slot — valkey.io/topics/cluster-spec.
A queue's keys are colocated by construction: every key carries the queue name as its
{q} hashtag, so slot/1 places them all on one of 16384 slots from the same few bytes.
Why the braced keyspace keeps Lua legal
CROSSSLOT · the atomic stepThe braced keyspace is not decoration — it is what keeps a queue's multi-key Lua legal at cluster
scale. A claim reads emq:{q}:pending, writes emq:{q}:active, and touches the job HASH
emq:{q}:job:<JOB>. All three keys share the {q} hashtag, so all three hash to
one slot, so the EVAL touches one slot and the cluster accepts it. Drop the brace and the three
keys scatter across slots; the same EVAL answers CROSSSLOT and the operation cannot
run atomically.
Select an operation below and read whether its keys share a slot — the same script is legal braced and rejected unbraced.
CROSSSLOT.Static verdicts — claim and complete carry the {q} hashtag on every key, so
one slot, so the EVAL runs; unbraced keys scatter across slots, so CROSSSLOT.
Notes on ValkeyIn cluster mode a single command, including a Lua
script, may only access keys that hash to the same slot; touching two slots returns
CROSSSLOT Keys in request don't hash to the same slot, so colocation is the precondition for an
atomic multi-key script — valkey.io/topics/cluster-spec.
Colocation is what makes a multi-key script a single atomic step on a cluster. The brace pins a
queue's keys to one slot, so a claim or a complete stays one EVAL — no CROSSSLOT,
no manual sharding.
Colocation and the gate are one rule
born braced, branded, declaredThe braced key is the same key the keyspace requires for the gate. A JOB id is gated at the key
builder, every key is born braced, and every key a Lua script touches is declared in its KEYS[].
Colocation and the gate are two readings of one rule: every key of a queue draws from one braced grammar. The
slot is computed from the brace; the gate is enforced at the brace; the script declares the braced keys it
touches. One discipline serves placement and safety at once.
# the queue name is the hashtag — every key of one queue shares it. emq:{orders}:pending emq:{orders}:active emq:{orders}:job:JOB0N… # the branded JOB id, gated at the key builder # slot("orders") is the same for all three → one slot → one atomic EVAL.
The bridge — hashtag to colocation
pattern → applicationColocate related keys on one cluster slot: a hashtag forces a key family onto one of 16384 slots, so a multi-key command stays in one slot and runs atomically.
EchoMQ.Keyspace.slot/1 is rem(crc16(hashtag(key), 0), 16384) over the
{q} hashtag; every key of a queue shares the brace, so a queue's multi-key Lua EVAL
is always CROSSSLOT-safe in cluster mode.
The hashtag is the shard key. EchoMQ braces the queue name into every key, so a queue's keys are one slot and its scripts are one atomic step — the colocation the bus depends on, by construction.
The production angle
deploy on a clusterDeploy the bus on a Valkey Cluster and nothing in the application changes. Each queue's keys already carry
the {q} hashtag, so each queue already lands on one slot; the cluster spreads queues across slots
and nodes for you, and each queue's scripts stay legal because they never leave their slot. The hashtag is the
shard key, and the operator chose it the moment the queue was named.
Where the colocation runs
For codemojex, the cm queue's keys share the {cm} brace — one slot — and
the bot workers draining cm all address that one slot; the colocation is automatic, the same as
any queue. The deeper protocol — the full Lua inventory, the lane and lease mechanics that run on those
colocated keys — is the dedicated EchoMQ Queue pillar. For the braced keyspace
as the architecture, see the bus; for where it runs in production,
Codemojex on Fly.
Colocation is a deployment property the keyspace already guarantees. Name a queue and its keys are one slot on any cluster — the operator gets atomic multi-key scripts with no manual sharding.
Recap — the brace is the shard key
next → R8.06.2 · prometheus-and-opentelemetryEchoMQ.Keyspace.slot/1 is rem(crc16(hashtag(key), 0), 16384) over the
{q} hashtag, vector slot("123456789") == 12739. Because every key of a queue shares
the brace, all land on one slot, so a multi-key Lua EVAL over a queue is always
CROSSSLOT-safe — colocation by construction. That is the placement move of operating the bus.
Next, the observability move: the telemetry tree a standard exporter attaches to.
References
sources · relatedSources
- Valkey — Cluster specification — the 16384 hash slots, the
{hashtag}rule, and theCROSSSLOTconstraint on multi-key commands. - Valkey — CLUSTER KEYSLOT — the command that returns a key's slot, the server-side counterpart to
slot/1's client-side CRC16. - Redis — Keyspace — key naming conventions and the hash-tag mechanism the braced keyspace builds on.
- Redis — Documentation — the cluster and scripting topics the colocation rule draws on.
Related in this course
- R8.06 · Operating EchoMQthe module hub
- R8.06.2 · Prometheus and OpenTelemetryobserving the colocated bus
- R8.06.3 · The polyglot fleetscaling a fleet over the same wire
- /echomq · the Queue pillarthe lanes and leases on the colocated keys
- /bcs · The busthe braced keyspace and the BCS law on the wire
- /bcs · Production on Flywhere the colocated bus runs