smikic.com
evergreentended May 24, 2025

Building a Distributed Key-Value Store in C++ (Part 1)

Key takeaways
  • A key-value store is a glorified dictionary — start with the simplest possible in-memory implementation before adding any distribution concerns.
  • Defining only three operations (put, get, del) up front keeps the first phase small enough to ship and test.
  • Shipping phase by phase forces you to confront distributed problems one at a time instead of all at once.

Why build a distributed KV store?

There are few better ways to get hands-on with distributed systems and C++ than building a distributed key-value store from scratch. This journey is both a learning experience and an exploration of ideas that power modern systems like Redis, etcd, and Consul.

In this series I'll attempt to walk through each step of designing and implementing a distributed KV store, from single-node basics to a replicated, fault-tolerant system.

The big idea

A key-value store is a simple database that stores data as a collection of key-value pairs — think of it as a glorified dictionary, but with persistence, concurrency control, replication, and more.

Eventually the store should support:

  • Multi-node communication
  • Replication and eventual consistency
  • Leader election
  • Crash recovery
  • Client-server networking

But we get there step by step.

Architecture overview

KV store architecture diagram — client, KVStore, and append-only log
Phase 1: a single-node KVStore backed by an append-only log. The log is replayed on startup for crash recovery.

Step 1: start simple

The journey begins with a very basic Hello World in-memory KV store.

File structure

distribkvstore/
├── CMakeLists.txt
├── src/
│   ├── kvstore.cpp
│   ├── kvstore.hpp
│   └── main.cpp
└── tests/
    └── test_kvstore.cpp  (planned)

Basic operations

Three operations for now:

  • put(key, value) — Insert or update a value
  • get(key) — Retrieve a value
  • del(key) — Delete a key

Example usage (main.cpp)

cpp
int main() {
  KVStore store;
  store.put("hello", "world");
 
  if (auto val = store.get("hello")) {
    std::cout << "GET hello: " << *val << "\n";
  }
 
  if (store.del("hello")) {
    std::cout << "deleted hello\n";
  }
 
  if (!store.get("hello")) {
    std::cout << "hello not found after deletion\n";
  }
 
  return 0;
}

The code compiles cleanly with CMake and serves as the foundation for everything that follows.

Roadmap

  1. Phase 1 — Local store ✅ Done: KVStore class with put, get, del; command-line demo
  2. Phase 2 — Persistence (next): Store data on disk using an append-only log for crash recovery and future compaction
  3. Phase 3 — Networking (planned): Expose the store over TCP sockets with a lightweight protocol and a CLI client
  4. Phase 4 — Multi-node architecture (planned): Run multiple instances with replication and eventual (or synchronous) consistency
  5. Phase 5 — Consensus (planned): Implement Raft or Gossip for leader election, partition handling, and write safety
  6. Phase 6 — Testing & resilience (final): Fuzz and chaos testing, graceful failure handling, and performance tuning

Next steps

In Part 2 I add unit tests and integrate persistence via a simple append-only log. That paves the way toward recoverability — one of the central challenges in distributed design.

2 linked references
Building a Distributed Key-Value Store in C++ (Final)

…s is the final post in the series. If you are arriving here for the first time, [Part 1](/notes/building-distributed-kv-store-pt1) is the right starting point — it covers the in-memory store and the overall roa…

Building a Distributed Key-Value Store in C++ (Part 3)

…tests before introducing a test harness for socket I/O. </KeyTakeaways> Parts [1](/notes/building-distributed-kv-store-pt1) and [2](/notes/building-distributed-kv-store-pt2) gave us a persistent, tested…

Stefan Mikic
Stefan Mikicdata eng

Data is my veggies — healthy, versatile, and sometimes hard to digest, but in the end, it always brings value.