I wanted to actually understand how the 2003 Google File System paper worked, so I built a minimal, functioning version of it from scratch in Go.
It splits files into 64 MB chunks and spreads them across a cluster. It features a single Master for metadata, multiple Chunkservers for the actual disk I/O, and a Client library that handles the routing.
The Master doesn't store any actual file data—it just tells clients where to look. Chunkservers store the physical files and ping the Master every 3 seconds to prove they are alive and report what chunks they have.
┌────────────┐ ┌─────────────────────────────────────┐
│ Client │ ◄──────► │ Master Server │
└────────────┘ metadata│ namespace + chunk metadata + leases│
│ └─────────────────────────────────────┘
│ ▲ ▲ ▲
│ heartbeat heartbeat heartbeat
│ │ │ │
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│Chunkserver│ ◄──────►│Chunkserver│ │Chunkserver│ │Chunkserver│
│ (data) │ clone │ (data) │ │ (data) │ │ (data) │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
You just need Go 1.22+.
1. Build the binaries
go build ./cmd/master
go build ./cmd/chunkserver
2. Boot the Master
./master --port 8080
3. Spin up some Chunkservers (Run these in separate terminal windows)
./chunkserver --address :8081 --data /tmp/cs1 --master localhost:8080
./chunkserver --address :8082 --data /tmp/cs2 --master localhost:8080
./chunkserver --address :8083 --data /tmp/cs3 --master localhost:8080
Once three are up, the Master will automatically start replicating new chunks across all of them.
I wrote a simple Go client library to handle the heavy lifting (talking to the Master, caching locations, and hitting the Chunkservers).
import "github.com/hsce/tinygfs/client"
c := client.NewClient("localhost:8080")
// Create a file
err := c.Create("/logs/app.log")
// Append some data (writes go to the primary, which syncs to replicas)
offset, err := c.Append("/logs/app.log", []byte("hello world\n"))
// Read it back (reads can hit any replica)
data, err := c.Read("/logs/app.log", offset, 12)
fmt.Println(string(data)) // "hello world\n"To keep this project digestible, I took a few shortcuts compared to the real GFS:
- In-Memory Master: If you restart the Master process, the namespace and metadata are gone. A real system would checkpoint this to disk.
- Appends Only: You can't overwrite random parts of a file. I stuck to this because the original paper noted that Google's workloads were overwhelmingly sequential appends anyway.
- Hardcoded Replication: The Replication Factor is locked at 3.
- Zero Security: All gRPC connections are insecure. It's meant for a local learning cluster, not production.
- Single-Chunk Reads: The client
Readmethod won't automatically cross a 64MB chunk boundary. If your read straddles two chunks, you have to make two calls.