Replication vs erasure coding: same safety, a third the cost

Splitting an immutable object into k data plus m parity fragments lets any k of the k+m fragments rebuild it — tolerating m losses at ~1.2x storage instead of the 3x that plain triple-replication spends to tolerate only 2.

Previously

Now that an object is a sealed, never-changing blob, we can store it durably — and the cheapest safe way is to split it, not to copy it.

Scene 05

Replication vs erasure coding: same safety, a third the cost

  1. Watch
  2. Try it
  3. Predict
  4. Capture
erasure coding · 17+3any k of the k+m fragments rebuild the objectobject{ }immutable blobencoder17+320 fragments · k=17 data + m=3 parityd0d1d2d3d4d5d6d7d8d9d10d11d12d13d14d15d16p0p1p2dataparitySTORAGE OVERHEAD1.18xDURABILITY~11 ninesFAULT TOLERANCEtolerates 3 losses
What to watch for

The sealed object feeds the encoder and comes out as 17 data fragments plus 3 small extra fragments computed from them. The lever kills three fragments; the survivors still rebuild the original byte-for-byte. Watch the two readouts: storage overhead and durability.

Continue unlocks when the animation finishes.
Implementation

Highlighted lines are the ones running in the diagram right now.

Encoder.encode
split the sealed object once into k data + m parity
def encode(blob, k, m):
data = split_into(blob, k) # k data fragments
# parity = matrix-multiply over GF(2^8)
parity = rs_encode(data, m) # m parity fragments
fragments = data + parity # k + m total
# immutable: computed once, never re-touched
for f in fragments:
node = pick_failure_domain(f)
node.write(f)
index.commit(key, locations(fragments))
Storage.read
the GET path — and the degraded read when fragments are dead
def read(key):
locs = index.lookup(key)
alive = [f for f in locs if f.up]
if len(alive) < k:
raise Unrecoverable # fewer than k survive
if all_data_present(alive):
return concat(data_fragments(alive))
# degraded read: rebuild from ANY k survivors
k_subset = alive[:k]
return rs_decode(k_subset) # inverse-matrix solve
Layout.cost
the trade every layout makes: bytes stored vs losses tolerated
def cost(scheme, k, m):
if scheme == 'replicate':
copies = m + 1
overhead = copies # 1 byte stored per copy
tolerated = copies - 1 # lose all-but-one
else: # erasure
overhead = (k + m) / k # thin parity, not copies
tolerated = m # lose any m of k+m
return overhead, tolerated

Where this sits in Build an S3-style distributed object store

Scene 05 of 12, in the Keep it alive act — Erasure coding, placement, the two planes, and repair.. Split into k+m fragments — any k rebuild it — tolerating m losses at ~1.4× instead of 3× replication.

Up next. Splitting into k+m fragments tolerates m losses only if those losses are independent — but real disks fail together, so where you put the fragments decides whether the math is true.

All 12 scenes in Build an S3-style distributed object store · Every curriculum

Built with Arqly
Every scene in Build an S3-style distributed object store builds on the one before it.All 12 Build an S3-style distributed object store scenes