# QuorumKV

QuorumKV is a distributed key-value store designed for low-latency reads, durable writes, and straightforward horizontal scaling. Data is partitioned across the cluster using consistent hashing and replicated to multiple nodes for fault tolerance.

QuorumKV is suitable for service metadata, session state, feature flags, caches that require persistence, and other workloads built around simple key-based access.

## Features

- Consistent hashing with automatic data partitioning
- Configurable replication factor
- Quorum-based reads and writes
- Automatic leader election and failure recovery
- Persistent write-ahead log and snapshotting
- Time-to-live (TTL) support
- Compare-and-set operations
- HTTP and gRPC APIs
- Prometheus-compatible metrics
- Rolling node additions and removals
- Optional TLS and token authentication

## Installation

### Prebuilt binaries

Download the latest archive for your platform, extract it, and place the binary on your `PATH`:

```sh
tar -xzf quorumkv-linux-amd64.tar.gz
sudo install quorumkv /usr/local/bin/quorumkv
```

Verify the installation:

```sh
quorumkv version
```

### Build from source

Building requires Go 1.23 or newer:

```sh
git clone https://github.com/example/quorumkv.git
cd quorumkv
go build -o bin/quorumkv ./cmd/quorumkv
```

## Usage

### Start a single-node cluster

Create a local data directory and start the server:

```sh
quorumkv server \
  --node-id node-1 \
  --data-dir ./data/node-1 \
  --http-address 127.0.0.1:8080 \
  --raft-address 127.0.0.1:7000 \
  --bootstrap
```

The HTTP API is available at `http://127.0.0.1:8080`.

### Store a value

```sh
curl -X PUT http://127.0.0.1:8080/v1/kv/users/alice \
  -H 'Content-Type: application/octet-stream' \
  --data-binary 'active'
```

Add a TTL using the `ttl` query parameter:

```sh
curl -X PUT 'http://127.0.0.1:8080/v1/kv/sessions/abc123?ttl=30m' \
  --data-binary 'alice'
```

### Read a value

```sh
curl http://127.0.0.1:8080/v1/kv/users/alice
```

A successful response includes metadata headers:

```text
HTTP/1.1 200 OK
Content-Type: application/octet-stream
ETag: "7"
X-QuorumKV-Version: 7

active
```

Use the `consistency` parameter to select the read guarantee:

```sh
curl 'http://127.0.0.1:8080/v1/kv/users/alice?consistency=quorum'
```

Supported values are `local`, `quorum`, and `linearizable`.

### Delete a value

```sh
curl -X DELETE http://127.0.0.1:8080/v1/kv/users/alice
```

### Compare and set

Use the value version from the `ETag` response header:

```sh
curl -X PUT http://127.0.0.1:8080/v1/kv/users/alice \
  -H 'If-Match: "7"' \
  --data-binary 'disabled'
```

The server returns `412 Precondition Failed` if the version has changed.

### Create a multi-node cluster

Start the first node with `--bootstrap`, then join additional nodes through an existing member:

```sh
quorumkv server \
  --node-id node-2 \
  --data-dir ./data/node-2 \
  --http-address 127.0.0.1:8081 \
  --raft-address 127.0.0.1:7001 \
  --join 127.0.0.1:7000
```

Each node must use a unique node ID and advertise addresses reachable by the other cluster members.

Check cluster membership:

```sh
curl http://127.0.0.1:8080/v1/cluster/members
```

## Configuration

QuorumKV accepts command-line flags, environment variables, or a YAML configuration file. Command-line flags take precedence over environment variables, which take precedence over file settings.

Start the server with a configuration file:

```sh
quorumkv server --config /etc/quorumkv/config.yaml
```

Example configuration:

```yaml
node:
  id: node-1
  data_dir: /var/lib/quorumkv
  advertise_http_address: kv-1.internal:8080
  advertise_raft_address: kv-1.internal:7000

server:
  http_address: 0.0.0.0:8080
  grpc_address: 0.0.0.0:9090
  raft_address: 0.0.0.0:7000
  shutdown_timeout: 30s

cluster:
  bootstrap: false
  join:
    - kv-2.internal:7000
    - kv-3.internal:7000
  replication_factor: 3
  read_quorum: 2
  write_quorum: 2

storage:
  sync_writes: true
  snapshot_interval: 10m
  snapshot_threshold: 10000
  max_value_size: 4MiB

security:
  auth_token_file: /etc/quorumkv/token
  tls:
    enabled: true
    certificate: /etc/quorumkv/tls/server.crt
    private_key: /etc/quorumkv/tls/server.key
    client_ca: /etc/quorumkv/tls/ca.crt

observability:
  log_level: info
  log_format: json
  metrics_address: 0.0.0.0:9100
```

Common environment variables include:

| Variable | Description | Default |
| --- | --- | --- |
| `QUORUMKV_NODE_ID` | Unique node identifier | Hostname |
| `QUORUMKV_DATA_DIR` | Directory for logs and snapshots | `./data` |
| `QUORUMKV_HTTP_ADDRESS` | HTTP API listen address | `127.0.0.1:8080` |
| `QUORUMKV_GRPC_ADDRESS` | gRPC API listen address | `127.0.0.1:9090` |
| `QUORUMKV_RAFT_ADDRESS` | Cluster transport listen address | `127.0.0.1:7000` |
| `QUORUMKV_JOIN` | Comma-separated addresses of existing members | Empty |
| `QUORUMKV_REPLICATION_FACTOR` | Number of replicas per key | `3` |
| `QUORUMKV_LOG_LEVEL` | `debug`, `info`, `warn`, or `error` | `info` |

For production deployments, use an odd number of nodes, keep the write quorum greater than half the replication factor, place replicas in separate failure domains, and store the data directory on persistent storage.