The question this answers
How do you store a file that is larger than any one machine, on machines that keep dying?
Each chunk survives the loss of up to (replication factor − 1) machines, *provided the placement policy put those copies in genuinely independent failure domains*. The namespace is exactly as available as the metadata service. Appends are atomic per chunk; arbitrary concurrent writes to the same offset are not defined.
Everything below is bought to hold this sentence. "Strongly consistent" with no scope attached is a slogan, not a guarantee — read what it actually covers, and what it explicitly does not.
A chunk server knows which chunk replicas are on its own disks and which of those it has recently verified with a checksum. It does not know the replication factor, the placement policy, or whether the other copies still exist — the metadata service knows that. Symmetrically, the metadata service knows what it has been *told*: its chunk map is a cache of chunk-server reports, and after a restart it is empty until the chunk servers report in again.
A node knows its own state and the messages that arrived. Everything else is inference from evidence that was already stale. "B has not replied in five seconds" is knowledge; "B is down" is a decision — and usually the bug.
The decomposition: data plane and metadata plane
The founding move is to split the file system in two. A metadata service holds the namespace — directories, file names, permissions, and for each file, the ordered list of chunks it is made of. Chunk servers hold the bytes and nothing else: a chunk is just a large opaque blob with an id, typically 64 MB or 128 MB, stored as an ordinary file on an ordinary local file system.
The chunk size is the design decision everything else follows from. Make chunks small and the metadata service must track billions of them; its map stops fitting in memory and every operation gets slower. Make them large and the map stays tiny — a petabyte at 128 MB per chunk is about eight million entries, which fits comfortably in RAM — but a small file wastes a whole chunk entry and a hot chunk cannot be spread across more machines. Large chunks also mean the metadata service is off the data path entirely: a client asks *once* where the chunk is and then talks to chunk servers directly for a hundred megabytes of reads.
That last property is the whole performance story. The metadata service handles a few thousand lookups a second; the chunk servers collectively handle tens of gigabytes a second, because there are a thousand of them and each read goes straight to a disk. Bandwidth scales with the number of machines because the coordinator is not in the way.
Replication factor and placement are two different knobs
The replication factor says *how many* copies. The placement policy says *where*, and it is the one that decides whether the copies are worth anything. Three copies on three machines in the same rack survive three independent disk failures and do not survive the rack switch dying. The classic policy — one replica local to the writer, one on a different rack, one more on that second rack — is a deliberate compromise: it buys rack-failure survival while keeping two of the three writes off the expensive cross-rack link.
This is Correlated Failure: The Independence Assumption Is Usually False applied to bytes. A replication factor of three is a statement about *independent* failures; the moment the failures are correlated, three copies behave like one. Cloud deployments repeat the exercise one level up — the failure domain becomes the availability zone, and the policy has to spread across zones or the replication factor is decorative.
The second thing placement decides is re-replication cost. When a machine is lost, every chunk it held is now under-replicated, and the cluster must copy those chunks from their surviving replicas. If the surviving replicas are concentrated on a few machines, re-replication saturates those machines’ network links and the recovery itself becomes an incident. Spreading each machine’s chunks across *many* peers means the repair of one machine is a small amount of work for hundreds of machines rather than a large amount of work for three.
- Metadata service — holds the chunk map; detects the missing heartbeat
- Rack 1 / server A — held replicas of chunks 42, 43, 77
- Rack 1 / server B — has chunk 42
- Rack 2 / server C — has chunks 42, 43
- Rack 2 / server D — has chunk 77; re-replication target
- mdbelieves “server A is gone; chunks 42, 43, 77 are at replication factor 2”✓ and it is true
- mdbelieves “copying 43 from server C restores its factor”✓ and it is true
- r1abelieves “it is healthy and still serving — it has merely been partitioned from the metadata service”✕ and it is false
Every node above is acting on what it believes. Nothing in the cluster tells the mistaken one that it is mistaken.
The single metadata master, honestly
GFS ran one master. HDFS ran one NameNode for most of its life. This was not an oversight and it was not a mistake — it was a trade the designers made on purpose and documented clearly. A single master means the namespace has a single authority, so there is no distributed agreement in the metadata path at all: file creation, renaming and chunk allocation are ordinary operations on one machine’s in-memory data structures, with an operation log on local disk. That is dramatically simpler than the alternative and, for the workload these systems targeted — a few thousand large files, written once and read many times — it was fast enough.
What it costs is honest and severe. The master is a single point of failure for the namespace, and the recovery time is not instant: a restarting master has an operation log to replay and must wait for chunk servers to report which chunks they hold before it can safely allocate or re-replicate anything. On a large cluster that was historically tens of minutes. During that window the data is entirely intact and entirely unreachable, because nobody knows where any chunk is.
It also caps the file count. The whole namespace lives in the master’s memory, so the number of files is bounded by one machine’s RAM — which is why these systems are miserable for millions of small files, and why "small files problem" is a phrase every HDFS operator knows. Later designs answered this in two ways: standby masters with a shared or quorum-replicated edit log, which cuts failover from minutes to seconds without removing the single-active-authority model; and federated or sharded namespaces, which split the namespace across several masters and thereby give up a single global view.
The lesson generalises past file systems. A single-authority metadata service is a legitimate design when the metadata operation rate is small relative to the data operation rate. The question to ask is never "is a single master bad?" but "what is my recovery time when it is gone, and can the data plane keep serving reads while it is?"
- A single master removes distributed agreement from the metadata path — that is its real benefit, not simplicity of code.
- Its cost is namespace unavailability during failover, with the data plane fully intact but unaddressable.
- Namespace size is bounded by one machine’s memory, which is what makes many small files pathological.
- Standby masters cut failover time; federation removes the memory bound at the price of a global view.
- A chunk server that cannot reach the master is not down — it is a Crashed or Just Slow: The Distinction You Cannot Make problem, and treating it as dead triggers unnecessary re-replication.
What "write" means here, and why append is special
These systems do not offer general random writes with useful semantics. A concurrent write to the same offset from two clients has no defined outcome, and the designers said so. What they *do* offer is atomic record append: many writers can append to the same file concurrently, each record lands at least once, and each record is contiguous. The offset is chosen by the system, not the client.
This is a beautiful example of matching the guarantee to the workload. The target workload was log ingestion and batch output — many producers appending records, one batch job later reading everything. "At least once, contiguous, at an offset we choose" is exactly enough for that and vastly cheaper than making arbitrary concurrent writes linearizable. The cost is that duplicates are possible and the reader must tolerate them, which drops you straight into Deduplication: Bounded Memory Against an Unbounded Stream and Where You Put the Acknowledgement Decides Everything.
Notice also what this makes the file: an The Log Is Not a Queue structure at the file-system layer. The same shape reappears at every level of this domain — the log is the primitive that makes both recovery and replication tractable, which is the subject of Recovered State Is a Checkpoint Plus the Log After It.
Key points
- Split the system into a metadata plane (namespace, chunk map) and a data plane (bytes), and keep the metadata service off the read path.
- Large chunks keep the metadata map small enough to hold in one machine’s memory — that is what makes the single-master design viable.
- Replication factor says how many copies; placement policy decides whether those copies fail independently. Only the second one buys durability.
- Losing a machine triggers re-replication, and re-replication is real cluster load that can itself cause an incident.
- The single metadata master is a documented trade: no agreement in the metadata path, at the cost of namespace downtime during failover and a file count bounded by RAM.
- Atomic record append, not general random write, is the guarantee that matched the workload.
The chain, answered
Every field here is required, which is why no lesson in this domain can recommend a design without naming what an operator sees when it fails, what survives the partition, what repairs it afterwards, and the simpler thing to consider first.
- • A file is split into fixed-size chunks, each with a globally unique id, stored as a plain file on a chunk server’s local file system.
- • The metadata service holds the namespace and the file-to-chunk list durably, and the chunk-to-server map as soft state rebuilt from chunk-server reports.
- • A client resolves a file offset to a chunk id and a replica list in one metadata call, then reads or writes bytes directly against a chunk server.
- • Writes are pushed to all replicas; a designated primary replica serialises the order of concurrent mutations to that chunk.
- • Chunk servers heartbeat to the metadata service with the list of chunks they hold and their checksum status.
- • When a heartbeat stops or a checksum fails, the metadata service marks the affected chunks under-replicated and schedules copies from surviving replicas, rate-limited to protect the network.
- • A disk returns bytes that are silently corrupt — which is why every chunk is checksummed in blocks rather than trusted.
- • A chunk server is partitioned from the metadata service but still reachable by clients, so it serves reads while being counted as dead.
- • The metadata service restarts and does not yet know where any chunk is.
- • A rack switch fails and takes every replica of some chunks with it, because placement did not actually separate them.
- • Re-replication traffic after a machine loss saturates the network that the serving traffic also needs.
- • Namespace outage with healthy data: every client gets errors resolving paths, disk utilisation across the cluster is normal, and no bytes were lost — the metadata service is down or still replaying its log.
- • Silent corruption caught late: a read fails a checksum, and the operator discovers the other two replicas have been unreadable for weeks because nothing scanned them. Effective replication factor was one.
- • Re-replication storm: one machine is decommissioned, cluster network utilisation goes to 100%, and unrelated jobs’ read latency triples. The repair is the outage.
- • Correlated placement loss: a single rack or zone fails and a specific set of files becomes unreadable, while overall cluster capacity looks fine — all three replicas of those chunks were in one failure domain.
- • Small-file exhaustion: the metadata service’s memory grows until it is close to the limit and file creation slows or fails, while the cluster has petabytes of free disk.
- • The namespace is a single-authority structure: no consensus needed, but no availability past that one authority either. Standby masters move this to a quorum-replicated edit log and pay one round trip per metadata mutation.
- • Per-chunk mutation order is delegated to a primary replica holding a lease from the metadata service — a Leases: Authority With an Expiry Date pattern, so a stale primary expires rather than needing to be told.
- • Chunk placement and re-replication decisions are made centrally, which is what keeps them globally sensible; a decentralised placement policy would need agreement to avoid two servers both deciding to copy the same chunk.
- • Bytes already written to a chunk survive the loss of any (replication factor − 1) independent failure domains.
- • With the metadata service down, existing data is intact but the namespace is unusable — durability is preserved, availability is not.
- • Under-replicated chunks are still readable; they have simply lost their margin, and the risk is cumulative until repair completes.
- • A lease held by a primary replica expires on its own, so a partitioned primary stops being able to serialise writes without anyone having to reach it.
- • Detect: missing heartbeats mark a server suspect; background checksum scrubbing finds corruption that reads have not touched.
- • Contain: rate-limit re-replication so repair never competes with serving traffic for the same links.
- • Recover: copy under-replicated chunks from surviving replicas, oldest and most-under-replicated first.
- • Reconcile: on metadata-service restart, replay the operation log, then wait for chunk reports before allowing allocation or deletion — acting on an incomplete map deletes data.
- • Verify: report the distribution of actual replica counts, not just the configured factor. The configured factor is an intention; the distribution is the fact.
- • Count of under-replicated chunks *and the age of the oldest one* — a chunk that has been under-replicated for a day is a different problem from one that has been for a minute.
- • Replica distribution across failure domains for a sample of files, which is the only way to catch a placement policy that is not doing what it claims.
- • Checksum failure rate from background scrubbing, separate from read-path failures.
- • Metadata service heap usage and file count, trended — this is a slow-moving limit that arrives suddenly.
- • Metadata operation latency separated from data-path latency; they fail for entirely different reasons.
- • Very large files, written once or appended to, read repeatedly by batch jobs — the workload the design was built for and still the one it fits.
- • Environments where you want aggregate read bandwidth to scale with machine count, because the coordinator is off the data path.
- • On-premises clusters where you own the disks and the network and want the storage co-located with the compute that reads it.
- • Millions of small files: the metadata service is the bottleneck and no amount of disk helps.
- • Random-write or update-in-place workloads: the guarantees on offer do not cover them, and layering a database on top is usually the wrong shape.
- • Cloud deployments where compute and storage are already separated by the network — the locality benefit that justified the design is gone, and managed object storage is cheaper and more durable.
- • Low-latency serving: the design optimises throughput on large sequential reads, not the p99 of a small random one.
- • Object storage — a flat namespace with no directory tree to keep in one machine’s memory, and durability managed by someone else. For most new systems this is the right default; see Object Storage: A Flat Namespace With a Hash Behind It.
- • A network file system with a single server and a real backup regime, if the data fits on one machine. Vastly simpler and probably sufficient.
- • A distributed database, when what you actually want is indexed access to records rather than sequential access to bytes.
- • A local disk plus a nightly copy, when the data set is small and the recovery objective is measured in hours.
Three copies in one rack is one copy with extra steps
What people believe, and what is true
Replication factor three means the data is safe.
It means it survives three independent failures. Placement decides whether the failures are independent; three copies in one rack is one copy with extra steps.
The metadata master being down means data loss.
The bytes are untouched. What is lost is the map, and therefore the ability to address them. Durability and availability fail separately here.
Bigger chunks are just a performance tuning knob.
Chunk size determines the size of the metadata map, and the metadata map fitting in one machine’s memory is what makes the whole architecture possible.
Re-replication is free background work.
It is a bulk copy across the same network your queries use. Unthrottled, it is one of the most reliable ways to turn a single machine loss into a cluster-wide incident.
Go deeper
Only the levels this lesson can honestly fill — a missing level is a claim nobody had.
Overview
Split a big file into large chunks, put several copies of each chunk on different machines, and keep the file-to-chunk map in a small metadata service. Clients ask the map once, then read bytes directly.
Practical
The knobs that matter are chunk size (which sets metadata size), replication factor (which sets your failure margin), placement policy (which decides whether that margin is real), and re-replication rate limits (which decide whether repair causes an outage). Watch under-replication age, not just count.
Advanced
The design is an argument about where to put the coordination. All agreement is concentrated in one metadata service so the data plane needs none, and the data plane is where all the bytes and all the machines are. Read the single-master decision this way and it stops looking naive: it is coordination placed where the operation rate is lowest, which is the same instinct behind per-partition consensus in A Distributed Database Is a Stack, Not a Box and behind the coordinator in Who Runs What, and What Happens When a Worker Goes Quiet.
Apply it
- 💬 Why are chunks 64 MB and not 64 KB?
- 💬 A cluster has replication factor three and lost a rack. Some files are unreadable. What went wrong?
- 💬 The metadata master restarts. Why can it not immediately start re-replicating under-replicated chunks?
- 💬 Your cluster has free disk everywhere and file creation is failing. Where do you look?