Building a Distributed Database with Go and Raft
Why Another Database?
The database landscape is crowded, but there's a gap for lightweight, embeddable distributed SQL databases. Most solutions are either:
- Heavyweight (CockroachDB, TiDB)
- Eventually consistent (Cassandra, DynamoDB)
- Not SQL (etcd, Consul)
rqlite fills this gap by combining SQLite's simplicity with Raft's strong consistency guarantees.
Architecture
At its core, rqlite has three layers:
- SQLite for storage and query execution
- Raft for cluster consensus and log replication
- HTTP API for client communication
The Raft layer ensures that all nodes in the cluster agree on the order of writes. Each write is recorded in the Raft log, committed, and then applied to SQLite.
type Cluster struct {
raft *raft.Raft
sqlite *sqlite.DB
http *http.Server
}Consensus in Practice
Raft works by electing a leader. All writes go through the leader, which replicates them to followers. Reads can be served by any node, but you can also request consistent reads from the leader.
Here's the write path:
- Client sends SQL to leader via HTTP POST
- Leader appends the SQL to its Raft log
- Log entry is replicated to a majority of followers
- Entry is committed
- SQL is applied to the local SQLite instance
- Response is sent to the client
Performance
For a three-node cluster on commodity hardware, rqlite achieves:
| Operation | Latency | Throughput |
|---|---|---|
| Write | ~5ms | ~200/s |
| Read | ~1ms | ~1000/s |
| Streaming | ~2ms | ~500/s |
These numbers make it suitable for applications that need reliability without the operational overhead of a full distributed database.
Lessons Learned
Building distributed systems is hard. A few lessons:
- Testing: Use Jepsen-style testing early. Network partitions reveal bugs you didn't know existed.
- Simplicity: Resist the urge to over-optimize. A simple design that works is better than a complex one that might.
- Observability: Instrument everything. You can't debug a distributed system without good metrics and tracing.
"A distributed system is one in which the failure of a computer you didn't even know existed can render your own computer unusable." — Leslie Lamport
Conclusion
rqlite shows that you don't need a massive codebase to build useful distributed systems. By composing well-understood components (SQLite
- Raft), you get a reliable, easy-to-operate database.