Skip to content

Replication ​

Last updated 

A spool is the storage unit that holds your queues: every queue lives in exactly one spool, and every account starts with one named default. Replication is what happens to a spool's data beyond one node.

Everything on this page is observable with an API key and curl, given two numbers set in the console when a spool is created. Both are immutable afterwards:

  • numReplicas – how many nodes hold the spool's data, primary included. The plan's replicas limit caps it – see limits.
  • numSync – how many of the other copies must confirm a write before the response; at most numReplicas-1. The default spool takes the plan's replicas and the largest numSync that keeps it writable with one node lost: numReplicas-2, so none on two replicas and one on three – see staying writable with a node lost.

What a response promises ​

Every write response – for example, a send's 201 or an ack's 204 – makes one promise: the primary wrote it to disk and synced, and numSync other copies confirmed it. The remaining copies catch up on their own; the response does not wait for them.

numReplicasnumSyncthe write is on
10one node
nn-1every node holding the spool
n0the primary; the other copies follow, unconfirmed

Losing a node ​

A spool is served by one node at a time, its primary. When that node is lost, requests answer 503 until the spool has a primary again; retry them.

  • One copy. Nothing else holds the data. The spool waits for its node to return; losing that node's storage loses the spool's data.
  • Synchronous copies. A copy's confirmation covers every write before it, so the copy furthest ahead holds every acknowledged write; it becomes the primary. No acknowledged write is lost.
  • Asynchronous copies (numSync of 0). A copy becomes the primary with whatever it had received. Writes acknowledged after that point are lost. This is the price of not waiting.

A primary change never preserves in-flight leases: their messages are redelivered, and a settle presenting an old lease answers 410stale_token – see delivery.

Losing a copy ​

A write on a spool with numSync above zero does not return until that many copies confirmed it. While fewer are reachable, sends and settles wait; receives keep working – a lease is not durable state, as a primary change dropping every in-flight lease already shows. A client that gives up waiting must treat the write as unconfirmed: it may still take effect. The rule is the one for operation_unconfirmed – retry a send only on a queue with a dedup window, carrying the same key; see deduplication.

Staying writable with a node lost ​

A write waits for numSync of the other copies. With one of the spool's nodes lost – a copy, or a primary that a copy replaced – numReplicas-2 other copies remain to confirm. Writes keep returning while that is at least numSync, that is, while numReplicas >= numSync + 2.

numReplicasnumSyncwith one node lost
20writes return; the lost copy catches up when it is back
21sends and settles wait: no other copy is left to confirm
31writes return on the remaining copy's confirmation
32sends and settles wait until two copies confirm again

With every copy synchronous, each acknowledged write is on every node, and sends and settles stop for as long as any node is unreachable. A spool of three replicas with one synchronous keeps every acknowledged write through the loss of a node and keeps accepting writes through it. Two replicas cannot do both: with one synchronous they wait; with none they can lose acknowledged writes.

Choosing ​

  • numReplicas of 1 for development, tests, and data you can regenerate.
  • numReplicas of at least numSync+2 when sends and settles have to keep returning while a node is unreachable.
  • Every copy synchronous when a 201 has to mean the write is on every node. Each write waits for the confirmations, and all writes wait while a node is unreachable; that is the cost.
  • numSync of 0 when the writes acknowledged in the moments before a node is lost are worth less than the wait. On two replicas the default spool chooses this: a primary change can lose the writes acknowledged since the other copy last caught up. Set numSync to 1 when that is unacceptable, and accept that sends and settles wait while the other copy is unreachable.

Copies add durability, not throughput: the primary serves every request.