A distributed key-value store implemented in Node.js using a Raft-inspired consensus algorithm.
This project was built from scratch to explore the internals of distributed systems, including leader election, log replication, majority consensus, node recovery, and persistence.
- Leader election
- Heartbeats
- Term-based voting
- Majority quorum consensus
- Automatic leader failover
- Leader-based writes
- Log replication to followers
- Commit after majority acknowledgment
- Consistent state across nodes
- Node restart recovery
- Log synchronization from leader
- Divergence detection
- Log repair and catch-up
- Automatic cache reconstruction from logs
- Persistent log storage
- Persistent term and vote information
- Recovery after process restart
- Set key-value pairs
- Delete keys
- Retrieve data from replicated state
The cluster consists of multiple servers.
Client
|
v
Follower ----> Leader
|
v
Replicated Log
|
-----------------
| |
v v
Follower Follower
Only the leader accepts writes.
If a follower receives a write request, it forwards the request to the current leader.
The leader:
- Appends the operation to its log.
- Replicates the log entry to followers.
- Waits for a majority of acknowledgments.
- Commits the entry.
- Applies the operation to its cache.
- Notifies followers of the commit.
POST /setBody:
{
"key":"goal",
"value":"peace"
}DELETE /delete/:keyUsed when followers forward client requests to the leader.
POST /writeUsed for log replication.
POST /changeUsed to commit replicated entries.
POST /commitUsed by the leader to maintain authority.
POST /heartbeatUsed during elections.
POST /requestVoteUsed by recovering nodes to request missing log entries.
GET /sync/:lastIndexGET /logGET /cacheEach operation is recorded as a log entry:
{
"term":10,
"operation":"set",
"key":"goal",
"value":"peace"
}Followers verify:
- Previous log index
- Previous log term
- Current term
before accepting entries.
If divergence is detected, the leader rewinds and repairs the follower's log before continuing replication.
When a node rejoins the cluster:
- It discovers the current leader through heartbeats.
- It requests missing entries using
/sync. - It appends the missing log entries.
- It replays unapplied operations.
- Its cache becomes consistent with the cluster.
Example:
node server1.js
node server2.js
node server3.jsEach server should have:
- Unique ID
- Unique port
- Appropriate peer list
Example:
const myId = "server1";
const myAddress = "http://localhost:3001";
const servers = [
"http://localhost:3002",
"http://localhost:3003"
];This project was built to understand:
- Distributed systems
- Consensus algorithms
- Replication
- Leader election
- Failure recovery
- Eventual consistency
- State machine replication
Rather than relying on an existing implementation, the goal was to build the mechanisms manually and understand how they interact under failure and recovery scenarios.
- Snapshotting and log compaction
- Dynamic cluster membership
- Read consistency guarantees
- Authentication and authorization
- Better persistence layer
- Network partition testing
- Automated integration tests
This is an educational implementation inspired by Raft and distributed database design principles. It is intended for learning and experimentation rather than production use.