System designDeep dive10 min
Distributed file systems & erasure coding
When files are measured in gigabytes and the data in petabytes, no single machine can hold or read them fast enough. A distributed file system cuts files into large blocks, spreads them over hundreds of machines and keeps them safe while disks fail every day. Erasure coding then survives more failures on half the disk, at a cost you pay during repairs.
1 · The idea
A distributed file system turns many machines' disks into one namespace
A genome sequencing lab produces about 4 TB of read files a day, each file around 30 GB. Fifty analysis machines align those reads and call variants, and every job reads whole files from start to end. One server can't store a year of this, and it couldn't feed fifty machines at once even if it could.
A distributed file system such as HDFS spreads the files across the disks of many ordinary machines and shows them as one tree of directories. Its design starts from three assumptions: hardware failure is the norm, files are large, and they are written once and read many times. The trade-offs it makes follow from those:
Built for | Not built for |
|---|---|
Files of gigabytes to terabytes | Millions of tiny files |
Reading whole files at high throughput | Low-latency random reads, as a user would click |
Write once, then append | Editing bytes in the middle of a file |
Running the computation where the data is | Serving files to browsers over HTTP (Object & blob storage) |
That last row is HDFS's motto: moving computation is cheaper than moving data. A batch job is scheduled on the machines that already hold its blocks, so 4 TB a day is read from local disks instead of crossing the network (Batch processing).
2 · Architecture
One metadata server knows where every block is, and the bytes never pass through it
HDFS splits every file into blocks, 128 MB by default, so one 30 GB read file becomes 240 blocks spread over different machines. Two kinds of server share the work:
- The NameNode holds the namespace: directories, file names, permissions, and which blocks make up each file and where they live. It keeps all of it in memory.
- DataNodes, one per machine, store blocks as ordinary files on local disks and serve reads and writes.
The NameNode answers small questions about where blocks are; the data flows straight between the job and the DataNodes. That's what lets one metadata server coordinate hundreds of machines.
The NameNode is critical, so its state is made durable like a database's: every change goes to a transaction log (the EditLog), which is periodically folded into a full snapshot of the namespace (the FsImage). For availability, HDFS runs several NameNodes that share the log through a group of journal servers, with one active at a time (Consensus & leader election).
3 · Replication
Three copies on two racks survive a disk, a machine or a whole rack
By default each block is stored three times. Where the copies go matters as much as how many there are. Machines sit in racks that share a switch and power, so a rack can fail as a unit (Redundancy & failure domains). HDFS puts the first copy on the writer's machine, and the second and third on two different machines in another rack:
A write pipeline: each DataNode stores a portion and forwards it to the next while still receiving. Only one copy crosses between racks, and losing either rack still leaves a copy.
Failures are found by silence. Every DataNode sends the NameNode a heartbeat, plus a periodic report of the blocks it holds. A DataNode that stays quiet for over 10 minutes by default is declared dead. The wait is deliberately long, so that a node flapping on and off doesn't set off a storm of copying (Failure detection & split brain).
Once a node is declared dead, every block that had a copy on it is under-replicated, and the NameNode orders new copies from the survivors. Corruption is caught separately: the client checksums each block when writing it, verifies the checksum on every read, and reads another replica when one doesn't match.
4 · Erasure coding
Erasure coding survives more failures on half the disk
Three copies cost 200% extra: a year of the lab's data, 1.46 PB, takes 4.38 PB of disk. Erasure coding stores computed redundancy instead of copies. The data is cut into k data cells, and m parity cells are computed from them with a Reed-Solomon code. Any k of the k + m cells are enough to rebuild the rest, so any m can be lost.
HDFS's default policy is RS(6,3): six data cells and three parity cells, on nine different DataNodes. Six blocks of data take 9 blocks of disk instead of 18, and any three of the nine can fail. The extra space is m / k:
Scheme | Survives losing | Extra space | Used by |
|---|---|---|---|
3 copies | Any 2 | 200% | HDFS and Ceph by default |
RS(6,3) | Any 3 of 9 | 50% | HDFS's default erasure coding policy |
RS(10,4) | Any 4 of 14 | 40% | An HDFS built-in policy |
17 + 3 | Any 3 of 20 | 18% | Backblaze, one shard per storage server in a group of 20 |
Disk for one year of the lab's reads, 4 TB × 365 days. RS(6,3) survives more failures than three copies while using half the disk.
In Ceph, a 4+2 or 6+3 profile gives about double the usable space of three copies. Past four or so data chunks the savings flatten while the performance cost keeps growing.
5 · The price
Erasure coding pays for its savings in repairs and reads
With copies, rebuilding a lost block means reading one surviving copy. With RS(6,3) it means reading six blocks from six machines, decoding them, and writing the result. A disk holding millions of blocks multiplies that into a lot of network traffic and CPU. Erasure coding is not a free lunch, especially during recovery.
Data read to rebuild one lost 128 MB block: one copy, or k other blocks. Azure's local reconstruction codes add a parity per group of six, so a single loss reads six blocks instead of twelve at 1.33× storage.
Reads change too. A missing or slow cell is rebuilt on the fly from other cells, so a read waits on the slowest of several machines. Azure Storage even starts a reconstruction in parallel when a fragment's machine looks slow, and returns whichever answer comes first. HDFS lists further costs:
- Encoding and decoding take CPU on clients and DataNodes.
- Cells are spread across racks, so most reads and writes cross racks.
- RS(6,3) needs at least 9 DataNodes, and at least 3 racks, ideally 9, for rack failures.
- Erasure-coded files don't support append, truncate or flushing a partly written file.
6 · Hot and cold
Copy what's being written, erasure-code what has cooled
The two schemes suit different stages of a file's life. Replication is cheap to write and repair, and erasure coding is cheap to keep. Azure Storage combines them: data is appended to extents kept as three full copies, and once an extent reaches about 1 GB it is sealed, erasure-coded in the background, and the copies are deleted:
Writes and appends stay simple on copies; long-term storage gets erasure coding's savings. Azure reports this cut its storage cost by over half compared with three copies.
In HDFS the policy is set per directory and applies to new files; changing a file's policy means copying it, not renaming it. The lab keeps /runs/current, where sequencers are still writing, on three copies, and moves finished runs into /archive, which uses RS(6,3) and is read mostly by occasional reanalysis. Google's Colossus does a similar thing with hardware: new data is spread across all drives, then moved to larger drives as it cools (Data lifecycle: tiering, TTL & compression).
7 · Limits
The metadata server is the ceiling, so keep files few and large
Because the NameNode keeps every file and block in memory, the number of files, not the bytes, is what fills it. HDFS aims at tens of millions of files per instance. Each sequencing run also produces thousands of tiny quality-control files, a few kilobytes each. Each one takes a file entry and a block entry in the NameNode's memory, just as a full 128 MB block does, while holding almost nothing. The lab packs them into one archive per run.
Beyond one NameNode there are two routes. HDFS federation runs several independent NameNodes, each owning part of the namespace, over the same DataNodes. Google's Colossus, the successor to GFS, stores file metadata in Bigtable instead of one server's memory, which lets it scale over 100 times past the largest GFS clusters.
- Check the access pattern
Large files read in full by batch jobs fit; small files served to users belong in object storage.
- Place copies by failure domain
Rack awareness, so one switch or power failure can't take every copy.
- Erasure-code cold data
RS(6,3) for finished, rarely read data; copies for data still being written.
- Budget for repairs
Enough racks, nodes and cross-rack bandwidth to rebuild a dead disk quickly.
- Watch the file count
Pack small files and size the metadata tier for files, not bytes.
Check yourself
4 questions
Takeaways
Remember this
- A distributed file system splits large files into big blocks spread over many machines, for batch jobs that read whole files.
- One metadata server tracks where blocks live, but data flows directly between clients and the storage servers.
- Three copies placed across racks survive disk, machine and rack failures, and dead nodes trigger automatic re-replication.
- Erasure coding stores k data and m parity cells: RS(6,3) survives three losses with 50% extra space instead of 200%.
- Its price is repair traffic, slower degraded reads and CPU, so keep hot data as copies and erasure-code cold data.