SD System Design In Depth
0%
lesson system-designobject-storage

Append-only stream layer

Module 2.3: Storage Engine Internals & Blob Systems Updated Sep 17, 2026
📄 Cheat Sheet
11 Windows Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency
sosp2011 11 Windows Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency Watch on YouTube ↗

The SOSP 2011 Windows Azure Storage talk introduces the stream layer, extents, sealing and the partition layer on top, which is the original source of this unit's design.

0:00 / --:--

Under the Hood: The Low-Level Storage Stream Engine

Modern cloud object storage engines (such as Azure Storage and Apache BookKeeper / Pulsar) do not write directly to arbitrary filesystem files. Instead, they operate on top of an internal Append-Only Stream Layer. A stream is an unbounded, durable sequence of immutable bytes composed of ordered extents (Azure's term; this unit also calls them chunks).

The Chunk Append Pipeline

flowchart LR Writer["Primary Storage Worker"] -->|"Append(data)"| ChunkServer1["Storage Node 1 (Primary)"] ChunkServer1 -->|"Replicate Append"| ChunkServer2["Storage Node 2 (Replica)"] ChunkServer1 -->|"Replicate Append"| ChunkServer3["Storage Node 3 (Replica)"] ChunkServer2 & ChunkServer3 -->|"Ack"| ChunkServer1 ChunkServer1 -->|"Committed Offset"| Writer

Handling Network Partitions: Lease Fencing & Sealed Chunks

The hardest challenge in distributed append-only storage is network split-brain: what happens if a primary storage node experiences a network blip and another node is promoted to take its place?

  • Sealing Chunks: To prevent two writers from appending conflicting data to the same chunk, chunks are strictly sealed. When a master promotes a new stream writer, it contacts the storage node quorum and updates the chunk status to SEALED at the last universally agreed byte offset.
  • Fencing (BookKeeper style): In Apache BookKeeper, ledger recovery fences the ledger on the storage nodes (bookies), so appends from the old, zombie writer are rejected; Kafka achieves the same with leader epochs. Azure's stream layer instead relies on the stream manager sealing the extent and allocating a new one for the new writer.

Worked example: sealing after a failure

An extent is replicated on three extent nodes, and the primary acknowledges an append only after all three replicas have written it.

  1. Appends up to byte 800 have been acknowledged to clients.
  2. The primary sends the next append (bytes 800-1000) to the replicas and crashes. Replicas A and B have written it; replica C has not.
  3. The stream manager seals the extent. It asks reachable replicas for their lengths: A = 1000, B = 1000, C = 800. It seals at the smallest length among the replicas it can reach, 800.
  4. Is anything lost? No: bytes 800-1000 were never acknowledged, so the client will retry. A and B trim to 800 when the seal is applied.
  5. The stream manager creates a new extent on a fresh set of nodes and the writer continues there.

If replica C were unreachable at seal time, the manager would seal at 1000; when C returns, it syncs to the sealed length. Either way all replicas of a sealed extent become byte-identical.

Comparing append-only log layers

SystemUnitReplication and acknowledgementSplit-brain protection
Azure Storage stream layerExtent, sealed around 1 GBChain to 3 replicas; ack after allStream manager (Paxos) seals and reassigns
Apache BookKeeperLedger, split into entriesEnsemble with write quorum and ack quorumRecovery sets a fence on bookies so the old writer's adds are rejected
KafkaPartition log split into segmentsLeader plus in-sync replicas; acks=allLeader epochs; controller fences stale leaders
HDFSBlock in a filePipeline to 3 datanodesNameNode lease recovery and generation stamps

Why build object storage on streams

  • Sequential appends are the cheapest disk pattern and make replication simple to reason about.
  • Sealed extents are immutable, so they can be erasure coded, scrubbed and moved without coordination with writers.
  • The partition layer above (Azure's tables, blobs and queues) keeps its own logs and checkpoints in streams, so every higher layer inherits the same durability model.
Check yourself Question 1 of 3
Purpose of fencing recall
From: Handling Network Partitions: Lease Fencing & Sealed Chunks

In Apache BookKeeper, what does ledger recovery's fencing step accomplish?

Key Takeaways

Stream layers provide append-only chunk sequences that serve as the durable foundation for object storage.
To prevent split-brain write corruption, chunks are sealed at fixed byte offsets before promoting new writers.
Storage nodes enforce fencing tokens to immediately reject zombie writer nodes.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue