package main
import (
"context"
"github.com/dynamic-calm/mokv/mokv"
)
func main() {
client, _ := mokv.NewClient("addr")
defer client.Close()
ctx := context.Background()
key := `59°19'14.7"N`
val := []byte(`18°03'39.0"E`)
client.Set(ctx, key, val)
client.Get(ctx, key)
client.Delete(ctx, key)
client.GetServers(ctx)
}mökv is a distributed key-value store built with Raft for consensus, Serf for discovery, and gRPC for communication.
Built following the book Distributed Services with Go by Travis Jeffery.
- Distributed & Fault-Tolerant: Data replicated across multiple nodes using Raft consensus
- In-Memory Storage: Fast read/write operations with persistent snapshots
- Service Discovery: Automatic node discovery and membership via Serf
- Smart Load Balancing: Client-side routing directs writes to leader, reads to followers
makeThis will:
- Create a kind cluster
- Build the Docker image
- Load it into kind
- Deploy with Helm
- Wait for all pods to be ready
Then test it:
➜ kubectl port-forward pod/mokv-0 9800:8400
# In another terminal:
➜ go run cmd/test_kv.go -addr localhost:8400
Getting servers:
- mokv-0.mokv.default.svc.cluster.local:8400 -> is leader: true
- mokv-1.mokv.default.svc.cluster.local:8400 -> is leader: false
- mokv-2.mokv.default.svc.cluster.local:8400 -> is leader: false
Setting key 'hello' = 'world'
Set OK: true
Getting key 'hello'
Got: hello = worldkubectl scale statefulset mokv --replicas=5Customize via deploy/mokv/values.yaml or override during installation:
helm install mokv deploy/mokv --set replicas=5 --set storage=2GiDefault values:
replicas: 3 # Number of nodes
storage: 1Gi # Persistent volume size per node
rpcPort: 8400 # gRPC port
serfPort: 8401 # Serf discovery portmökv exposes a gRPC API defined in api/kv.proto:
service KV {
rpc Get(GetRequest) returns (GetResponse);
rpc Set(SetRequest) returns (SetResponse);
rpc Delete(DeleteRequest) returns (DeleteResponse);
rpc List(google.protobuf.Empty) returns (stream GetResponse);
rpc GetServers(google.protobuf.Empty) returns (GetServersResponse);
}Raft Consensus: Ensures strong consistency with leader-based replication. Writes go through the leader and are replicated to followers.
Serf Discovery: Nodes automatically discover each other via gossip protocol. When a node joins via Serf, it's added as a Raft voter.
Client-Side Load Balancing: Custom gRPC resolver and picker route:
- Writes (
Set,Delete) → Leader - Reads (
Get,List) → Followers (load balanced)
Kubernetes Components:
- StatefulSet: Stable network identities (mokv-0, mokv-1, mokv-2)
- Headless Service: Direct pod-to-pod communication via FQDNs
- PersistentVolumeClaims: Durable storage for Raft logs and snapshots
- Init Container: Auto-configures each pod (bootstrap vs join)
Update deployment:
make docker-build
make kind-load
kubectl rollout restart statefulset mokvScale the cluster:
helm upgrade mokv deploy/mokv --set replicas=5Uninstall:
make cleanFor local testing without Kubernetes, see example/start_nodes.sh.
