{"id":25424387,"url":"https://github.com/dynamic-calm/mokv","last_synced_at":"2026-05-01T06:31:38.846Z","repository":{"id":277818631,"uuid":"922171385","full_name":"dynamic-calm/mokv","owner":"dynamic-calm","description":"A distributed key-value store written in Go","archived":false,"fork":false,"pushed_at":"2026-01-11T14:30:59.000Z","size":20923,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-11T17:59:51.998Z","etag":null,"topics":["distributed-systems","go","golang","grpc","kv","raft","serf"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dynamic-calm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-25T14:08:52.000Z","updated_at":"2026-01-11T14:31:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"835dc68c-a6c6-4dec-bc56-387c38d2ec86","html_url":"https://github.com/dynamic-calm/mokv","commit_stats":null,"previous_names":["dynamic-calm/mokv"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dynamic-calm/mokv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynamic-calm%2Fmokv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynamic-calm%2Fmokv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynamic-calm%2Fmokv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynamic-calm%2Fmokv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dynamic-calm","download_url":"https://codeload.github.com/dynamic-calm/mokv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dynamic-calm%2Fmokv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32487300,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["distributed-systems","go","golang","grpc","kv","raft","serf"],"created_at":"2025-02-16T23:15:59.214Z","updated_at":"2026-05-01T06:31:38.840Z","avatar_url":"https://github.com/dynamic-calm.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- markdownlint-disable MD033 MD041 --\u003e\n\u003cdiv align='center'\u003e\n\u003cimg src=\"mokv.png\" alt=\"mokv logo\"/\u003e\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Go Report Card](https://goreportcard.com/badge/github.com/dynamic-calm/mokv)](https://goreportcard.com/report/github.com/dynamic-calm/mokv)\n[![Build](https://github.com/dynamic-calm/mokv/actions/workflows/build.yml/badge.svg)](https://github.com/dynamic-calm/mokv/actions/workflows/build.yml)\n\n\u003c/div\u003e\n\n\u003c!-- markdownlint-enable MD033 MD041 --\u003e\n\n## Client example\n\n\u003c!-- markdownlint-disable MD010 --\u003e\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\n\t\"github.com/dynamic-calm/mokv/mokv\"\n)\n\nfunc main() {\n\tclient, _ := mokv.NewClient(\"addr\")\n\tdefer client.Close()\n\n\tctx := context.Background()\n\n\tkey := `59°19'14.7\"N`\n\tval := []byte(`18°03'39.0\"E`)\n\n\tclient.Set(ctx, key, val)\n\tclient.Get(ctx, key)\n\tclient.Delete(ctx, key)\n\tclient.GetServers(ctx)\n}\n```\n\n\u003c!-- markdownlint-enable MD010 --\u003e\n\n## Overview\n\nmökv is a distributed key-value store built with [Raft](https://github.com/hashicorp/raft) for consensus, [Serf](https://github.com/hashicorp/serf) for discovery, and [gRPC](https://github.com/grpc/grpc-go) for communication.\n\nBuilt following the book [Distributed Services with Go](https://pragprog.com/titles/tjgo/distributed-services-with-go/) by Travis Jeffery.\n\n## Features\n\n- **Distributed \u0026 Fault-Tolerant**: Data replicated across multiple nodes using Raft consensus\n- **In-Memory Storage**: Fast read/write operations with persistent snapshots\n- **Service Discovery**: Automatic node discovery and membership via Serf\n- **Smart Load Balancing**: Client-side routing directs writes to leader, reads to followers\n\n## Quick Start\n\n### Prerequisites\n\n- [`Docker`](https://www.docker.com/)\n- [`kind`](https://kind.sigs.k8s.io/) (for local Kubernetes)\n- [`kubectl`](https://kubernetes.io/docs/tasks/tools/)\n- [`Helm`](https://helm.sh/)\n\n### Run it locally\n\n```bash\nmake\n```\n\nThis will:\n\n1. Create a kind cluster\n2. Build the Docker image\n3. Load it into kind\n4. Deploy with Helm\n5. Wait for all pods to be ready\n\nThen test it:\n\n```bash\n➜ kubectl port-forward pod/mokv-0 9800:8400\n# In another terminal:\n➜ go run cmd/test_kv.go -addr localhost:8400\nGetting servers:\n        - mokv-0.mokv.default.svc.cluster.local:8400 -\u003e is leader: true\n        - mokv-1.mokv.default.svc.cluster.local:8400 -\u003e is leader: false\n        - mokv-2.mokv.default.svc.cluster.local:8400 -\u003e is leader: false\n\nSetting key 'hello' = 'world'\nSet OK: true\n\nGetting key 'hello'\nGot: hello = world\n```\n\n```bash\nkubectl scale statefulset mokv --replicas=5\n```\n\n### Configuration\n\nCustomize via `deploy/mokv/values.yaml` or override during installation:\n\n```bash\nhelm install mokv deploy/mokv --set replicas=5 --set storage=2Gi\n```\n\nDefault values:\n\n```yaml\nreplicas: 3 # Number of nodes\nstorage: 1Gi # Persistent volume size per node\nrpcPort: 8400 # gRPC port\nserfPort: 8401 # Serf discovery port\n```\n\n## API\n\n`mökv` exposes a gRPC API defined in `api/kv.proto`:\n\n```proto\nservice KV {\n    rpc Get(GetRequest) returns (GetResponse);\n    rpc Set(SetRequest) returns (SetResponse);\n    rpc Delete(DeleteRequest) returns (DeleteResponse);\n    rpc List(google.protobuf.Empty) returns (stream GetResponse);\n    rpc GetServers(google.protobuf.Empty) returns (GetServersResponse);\n}\n```\n\n## Architecture\n\n**Raft Consensus**: Ensures strong consistency with leader-based replication. Writes go through the leader and are replicated to followers.\n\n**Serf Discovery**: Nodes automatically discover each other via gossip protocol. When a node joins via Serf, it's added as a Raft voter.\n\n**Client-Side Load Balancing**: Custom gRPC resolver and picker route:\n\n- **Writes** (`Set`, `Delete`) → Leader\n- **Reads** (`Get`, `List`) → Followers (load balanced)\n\n**Kubernetes Components**:\n\n- **StatefulSet**: Stable network identities (mokv-0, mokv-1, mokv-2)\n- **Headless Service**: Direct pod-to-pod communication via FQDNs\n- **PersistentVolumeClaims**: Durable storage for Raft logs and snapshots\n- **Init Container**: Auto-configures each pod (bootstrap vs join)\n\n## Management\n\n**Update deployment**:\n\n```bash\nmake docker-build\nmake kind-load\nkubectl rollout restart statefulset mokv\n```\n\n**Scale the cluster**:\n\n```bash\nhelm upgrade mokv deploy/mokv --set replicas=5\n```\n\n**Uninstall**:\n\n```bash\nmake clean\n```\n\n## Local Development\n\nFor local testing without Kubernetes, see [`example/start_nodes.sh`](example/start_nodes.sh).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdynamic-calm%2Fmokv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdynamic-calm%2Fmokv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdynamic-calm%2Fmokv/lists"}