Build a wide-column store (Cassandra / DynamoDB family) (13 scenes)
Scene 06 · Copies on the next N servers
Store each key on the next RF distinct servers clockwise so a node death loses no data.
Previously

Vnodes spread the load evenly, but the dead node's data is still lost — we need copies.

Scene 06
Copies on the next N servers
Diagram
The ring with 8 physical servers (one token each for clarity — vnodes return next scene). The featured key dot sits at its **primary** owner; the next RF-1 distinct servers clockwise glow as additional **replicas**. Together these RF servers are where every copy of the key lives. **Replication factor (RF)** is shown beside the slider — RF=1 means a single point of failure, RF=3 and RF=5 mean the cluster survives 1 or 2 losses with no data lost.
mode: with-replicasABCDEFGHuser-42R1R2R3ARC SIZES (deg)A45°B45°C45°D45°E45°F45°G45°H45°ideal: 45° · range: 4545°RF = 3 · 3 distinct replicasRF=3 · key copied to 3 distinct servers
The ring is back — eight servers, one token each so the replicas are easy to read (vnodes return next scene). Watch the featured key light up its primary owner and then fan to the next two servers clockwise — three copies, three distinct boxes.
Implementation
Replication.replicasFor
walk the ring clockwise picking the next RF distinct nodes
1def replicasFor(key, RF):
2 primary = ring.successor(hash(key))
3 seen = {primary}
4 out = [primary]
5 cursor = primary
6 while len(out) < RF:
7 cursor = ring.successor(cursor.token + 1)
8 if cursor.physical_node not in seen:
9 seen.add(cursor.physical_node)
10 out.append(cursor)
11 return out # RF distinct PHYSICAL nodes, not vnodes
Coordinator.read
answer a read from the first live replica
1def read(key, RF):
2 replicas = replicasFor(key, RF)
3 for r in replicas:
4 if r.alive():
5 return r.get(key) # no failover step
6 raise NoLiveReplicas # all RF copies down
Coordinator.write
write goes to all RF replicas; durable while RF-1 are alive
1def write(key, value, RF):
2 replicas = replicasFor(key, RF)
3 for r in replicas:
4 r.put(key, value) # k* disk, k* network
5 # tolerates RF - 1 simultaneous deaths with zero loss;
6 # at RF=1 a single death takes the only copy with it.