Skip to content

Latest commit

 

History

History
401 lines (260 loc) · 12.7 KB

File metadata and controls

401 lines (260 loc) · 12.7 KB

Configuring Vole

Vole can be configured with CLI flags, a config file, or a mix of both. CLI flags always take priority over the config file, so you can set your baseline in the file and override individual settings on the fly.

A handful of settings can also be changed at runtime with CONFIG SET without restarting.

Config file

Copy the example and edit it:

cp vole.conf.example /etc/vole/vole.conf

Then start Vole with:

vole --config /etc/vole/vole.conf

The format is one setting per line: key value. Lines starting with # are comments. See vole.conf.example in the repo for a fully commented template.

You can still pass CLI flags alongside --config. If a flag shows up in both places, the CLI wins.

Flag reference

This page walks through each setting, explains what it does, and tells you when you'd actually want to change it.

Network

--addr

Default: 127.0.0.1:7379

The address Vole listens on for RESP connections. This is the main protocol -- it's what vole-cli and every compatible client library connects to.

If you only need local access, the default is fine. To accept connections from other machines:

vole --addr 0.0.0.0:7379

To run on a non-standard port:

vole --addr 0.0.0.0:6400

--http-addr

Default: disabled

Turns on the HTTP/JSON API. Omit this flag when you want to run only the RESP server.

vole --http-addr :8080

This gives you REST endpoints for all operations, a Prometheus metrics endpoint at /metrics, a health check at /health, and Server-Sent Events for real-time key change notifications at /api/v1/events. The metrics endpoint includes command counters, per-command latency totals, memory and GC stats, eviction count, lazy-free queue depth, and store lock wait time.

You can run this on the same machine as the RESP port without issues -- they're independent listeners.

Persistence

Vole stores everything in memory, but it can write data to disk so it comes back after a restart. You've got two options, and they work well together.

--appendonly

Default: true

When this is on, every write command gets appended to a log file before the client gets a response. On restart, the log is replayed to rebuild the dataset.

When Vole rewrites the AOF to compact it, the rewritten file carries the current dataset for core Redis types and Vole's extended types: streams and consumer groups, JSON documents, time-series data, reliable queues, tags, delayed-key metadata, HyperLogLog state, and multi-master conflict metadata.

If you're using Vole as a pure cache and don't care about surviving restarts, turn it off:

vole --appendonly=false

--appendfilename

Default: vole.aof

Where the append-only log goes. Can be a relative or absolute path.

vole --appendfilename /var/lib/vole/data.aof

--appendfsync

Default: everysec

How often the AOF is flushed to disk. This is the classic durability-vs-speed tradeoff.

Value What it means When to use it
always Flush after every write Choose this when every acknowledged command must survive a crash. This is the slowest option.
everysec Flush once a second Good balance for most workloads. You might lose up to one second of writes in a hard crash.
no Let the OS decide Fastest. The OS will flush eventually, but you could lose more data in a crash. Fine for caches.
vole --appendfsync always

--snapshot

Default: vole.rdb.json

Path for point-in-time snapshots. A snapshot is a full dump of everything in memory, written as JSON.

Snapshots are useful because replaying a long AOF can be slow on restart. With both enabled, Vole loads the snapshot first (fast) and then replays only the AOF entries that came after it.

--snapshot-interval

Default: 0 (disabled)

How often to take automatic snapshots. Set this to something like 5m or 1h. When a snapshot completes, the AOF is truncated since everything in it is now captured in the snapshot.

vole --snapshot /var/lib/vole/vole.snap --snapshot-interval 5m

You can also trigger snapshots manually with the SAVE (blocking) or BGSAVE (background) commands.

A note on how the two work together

On startup, Vole does this:

  1. If a snapshot file exists, load it.
  2. If an AOF file exists, replay it on top of the snapshot.

On each automatic snapshot:

  1. Write the snapshot to a temporary file, then rename it into place (atomic on most filesystems).
  2. Truncate the AOF.

So even if Vole crashes mid-snapshot, the old snapshot and AOF are still intact. You'll never end up with a half-written snapshot and a truncated AOF.

Memory management

--maxmemory

Default: 0 (unlimited)

A soft memory limit in bytes. When Vole estimates it's using more than this, it starts evicting keys according to the policy.

vole --maxmemory 536870912  # 512 MB

The estimate is still approximate because Go does not expose exact retained bytes for every object, but Vole now keeps the estimate per key and updates it when data changes. That keeps eviction decisions current without periodically walking the full keyspace.

You can change this at runtime:

CONFIG SET maxmemory 1073741824

--maxmemory-policy

Default: noeviction

What happens when the memory limit is hit.

Policy What it does
noeviction Reject writes with an OOM error. Reads still work.
allkeys-random Pick a random key and delete it. Any key is fair game.
volatile-random Same, but only picks from keys that have a TTL set. If no keys have a TTL, writes fail.
allkeys-lru Delete the key that was accessed least recently. Vole samples 5 random keys and evicts the oldest one, so it's an approximation.
vole --maxmemory 536870912 --maxmemory-policy allkeys-lru

Also changeable at runtime:

CONFIG SET maxmemory-policy allkeys-lru

Security

--requirepass

Default: none

Sets a password that clients must provide before they can run commands.

vole --requirepass s3cret

On the client side:

vole-cli
127.0.0.1:7379> GET foo
(error) NOAUTH Authentication required.
127.0.0.1:7379> AUTH s3cret
OK
127.0.0.1:7379> GET foo
"bar"

PING works without authenticating, so health checks still function. Everything else is blocked.

This is a single shared password, not per-user accounts. It's meant to keep casual access out, not to implement fine-grained permissions.

--tls-cert and --tls-key

Default: none

Encrypt all traffic (RESP and HTTP) with TLS.

vole --tls-cert /etc/vole/cert.pem --tls-key /etc/vole/key.pem

Use both flags together. The minimum TLS version is 1.2.

If you need a quick self-signed cert for testing:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \
  -subj '/CN=localhost'

In production, use certs from your CA or Let's Encrypt. After rotating certs, restart the server so new connections use the updated files.

Replication

--replicaof

Default: none

Starts this instance as a follower of another Vole server. On startup, it connects to the leader, downloads a full snapshot, and then streams every subsequent write in real time.

# The leader
vole --addr :7379

# A follower
vole --addr :7380 --replicaof localhost:7379

The follower is read-only. Writes get rejected with READONLY. You can manage replication from the CLI:

# Start following
vole-cli REPLICAOF localhost 7379

# Check status
vole-cli INFO

# Promote to standalone
vole-cli REPLICAOF NO ONE

# Or enable multi-master so both nodes accept writes
vole-cli MULTIMASTER ENABLE
vole-cli MULTIMASTER STATUS

Or start following from the CLI:

REPLICAOF localhost 7379

A few things to be aware of:

  • Replication is asynchronous. A write that succeeds on the leader might not have reached the follower yet.
  • If the follower disconnects and reconnects, it resumes from the leader's replication backlog when the missing offset range is still available. If not, it falls back to a fresh snapshot.
  • Failover can be coordinated through the cluster failover commands. During failover, epoch fencing prevents stale leaders from continuing to accept writes.

Cluster

--node-id

Default: auto-generated from a random value

A stable identifier for this node in a cluster. Set this explicitly for cluster deployments so the same node keeps the same identity across restarts.

For any cluster setup, set this explicitly:

vole --node-id node1 --addr :7379

--peers

Default: none

A comma-separated list of other nodes in the cluster, in the format nodeID@host:port.

vole --node-id node1 --addr :7379 --peers "node2@host2:7380,node3@host3:7381"

On startup, Vole divides 16,384 hash slots evenly across all known nodes (including itself). When a command targets a key that belongs to a different node, the client gets a MOVED redirect telling it where to go.

You can also add and remove nodes at runtime:

CLUSTER MEET host2:7380
CLUSTER FORGET <node-id>

--multimaster

Default: false

Turns on multi-master replication. Every node in the cluster accepts writes, and changes propagate to all peers automatically.

vole --addr :7379 --node-id node1 --peers "node2@localhost:7380" --multimaster

When enabled, Vole connects to every known peer and sets up bidirectional write streaming. If a new node is added via CLUSTER MEET, it's automatically connected.

You can also toggle it at runtime:

MULTIMASTER ENABLE
MULTIMASTER DISABLE

Multi-master accepts writes on every peer and propagates them across the cluster. For workloads where multiple nodes can update the same key, design key ownership or application-level write rules so concurrent updates resolve predictably.

You can run multi-master alongside --peers. Choose either follower mode with --replicaof or multi-master mode for a given node.

How clustering works in practice

Each key maps to one of 16,384 slots via CRC32 hashing. Each node owns a contiguous range of slots. When you send a command for a key that lives on a different node, you get back:

MOVED 12182 host2:7380

Your client library follows this redirect to the owner node; most Redis-compatible clients already handle this flow.

A background heartbeat pings every peer every 5 seconds. If a node stops responding, it gets marked as failing and eventually offline. When nodes are added or removed, the slot ranges are recalculated automatically.

For cluster topology changes:

  • Pair slot ownership updates with replication, multi-master, or an application-level migration plan so data remains available while ownership changes.
  • Use --replicaof for follower replication or --multimaster for peer-to-peer replication, depending on the topology you want.
  • Use the coordinated/manual failover commands with epoch fencing when promoting a new leader, and validate the topology after promotion.

This keeps routing explicit while giving operators control over replication, promotion, and topology changes.

Putting it all together

Here's what a production-ish setup might look like:

vole \
  --addr 0.0.0.0:7379 \
  --http-addr 0.0.0.0:8080 \
  --appendonly \
  --appendfilename /var/lib/vole/vole.aof \
  --appendfsync everysec \
  --snapshot /var/lib/vole/vole.snap \
  --snapshot-interval 5m \
  --maxmemory 1073741824 \
  --maxmemory-policy allkeys-lru \
  --requirepass changeme \
  --tls-cert /etc/vole/cert.pem \
  --tls-key /etc/vole/key.pem

That gives you:

  • RESP on port 7379, HTTP on 8080, both encrypted with TLS
  • Password required
  • AOF persistence with 1-second fsync, plus snapshots every 5 minutes
  • 1 GB memory cap with LRU eviction
  • Prometheus metrics at https://host:8080/metrics

Quick reference

Flag Default Description
--addr 127.0.0.1:7379 RESP listen address
--http-addr (off) HTTP/JSON API listen address
--appendonly true Enable append-only file
--appendfilename vole.aof AOF path
--appendfsync everysec always, everysec, or no
--snapshot vole.rdb.json Snapshot path
--snapshot-interval 0 Auto-snapshot interval (e.g., 5m)
--maxmemory 0 Memory limit in bytes (0 = unlimited)
--maxmemory-policy noeviction Eviction policy
--requirepass (none) Client password
--tls-cert (none) TLS certificate path
--tls-key (none) TLS private key path
--replicaof (none) Leader address (host:port)
--multimaster false Enable multi-master replication
--node-id (auto) Cluster node ID
--peers (none) Cluster peer list