kevy 2.1.0

kevy — a pure-Rust, zero-dependency, Redis-compatible KV server.
Documentation

kevy

A Redis-wire-compatible single-DC key–value server in pure Rust. Zero crates.io dependencies. Speaks RESP2, so redis-cli, valkey-cli, and every Redis client library work unchanged.

cargo install kevy
kevy --port 6379 &
redis-cli -p 6379 SET hello world
redis-cli -p 6379 GET hello

What this gives you

  • All five Redis data types (String, Hash, List, Set, Sorted Set) plus Streams, Pub/Sub, Transactions (MULTI / EXEC / WATCH / UNWATCH), Blocking pops, and the standard persistence verbs.
  • A thread-per-core, shared-nothing engine. On Linux the reactor prefers io_uring (kernel ≥ 5.19) and falls back to epoll. On macOS/BSD the reactor uses kqueue.
  • AOF + RDB snapshot persistence. Eight Redis eviction policies.
  • 98 commands reply-checked byte-for-byte against valkey 9.1.
  • A 768 KB stripped binary that boots into under 5 MB of RSS.

Install

crates.io

cargo install kevy
kevy --port 6379

Pre-built binaries

Attached to every GitHub Release for Linux x86_64, Linux aarch64, and macOS Apple Silicon. Each archive ships the kevy binary, an annotated kevy.toml.example, the README, and both license files; a matching .sha256 is published alongside.

TAG=v2.0.20
TARGET=x86_64-unknown-linux-gnu   # or aarch64-unknown-linux-gnu, aarch64-apple-darwin
curl -L "https://github.com/goliajp/kevy/releases/download/$TAG/kevy-$TAG-$TARGET.tar.gz" | tar -xz
sudo install "kevy-$TAG-$TARGET/kevy" /usr/local/bin/kevy
kevy --port 6379

Docker

Multi-arch (linux/amd64, linux/arm64), published to both registries:

docker run --rm -p 6379:6379 goliakk/kevy:latest        # Docker Hub
docker run --rm -p 6379:6379 ghcr.io/goliajp/kevy:latest # GHCR

Image defaults: KEVY_BIND=0.0.0.0, KEVY_PORT=6379, KEVY_DIR=/data, KEVY_AOF=1. Override with -e or by appending flags:

docker run -d --name kevy -p 6379:6379 -v kevy-data:/data \
  goliakk/kevy:latest --threads 4 --port 7000

Docker's default seccomp blocks io_uring_setup, so the container runs on epoll. To enable io_uring for benchmarks:

docker run --rm -p 6379:6379 --security-opt seccomp=unconfined \
  goliakk/kevy:latest

Quick start

First connection

kevy --port 6379 &
redis-cli -p 6379 PING                  # → PONG
redis-cli -p 6379 SET foo bar           # → OK
redis-cli -p 6379 GET foo               # → "bar"
redis-cli -p 6379 INFO server | head    # → version, uptime, threads, ...

Configuration precedence

CLI flags → environment variables → TOML file → built-in defaults.

kevy --bind 0.0.0.0 --port 7000 --threads 4 --dir /var/lib/kevy
# env-var equivalents: KEVY_BIND  KEVY_PORT  KEVY_THREADS  KEVY_DIR  KEVY_AOF

kevy --config /etc/kevy/kevy.toml

TOML config example

[server]
bind     = "127.0.0.1"
port     = 6379
threads  = 0            # 0 = auto-detect CPU count
data_dir = "/var/lib/kevy"

[persistence]
aof          = true
appendfsync  = "everysec"    # "always" | "everysec" | "no"
auto_aof_rewrite_percentage  = 100
auto_aof_rewrite_min_size    = "64mb"

[memory]
maxmemory          = "1gb"
maxmemory_policy   = "allkeys-lru"
maxmemory_samples  = 5

[metrics]
enabled            = true
bind               = "127.0.0.1"
port               = 9100         # Prometheus scrape: http://host:9100/metrics

The full annotated schema is in kevy.toml.example.

Unix-domain socket

For same-host clients on Linux, point KEVY_UNIX_SOCKET at a filesystem path. The server dual-binds TCP and UDS with identical RESP semantics; UDS is materially faster than TCP loopback at every workload measured. See docs/uds.md.

KEVY_UNIX_SOCKET=/tmp/kevy.sock kevy --port 6379
redis-cli -s /tmp/kevy.sock SET foo bar

Operations

Graceful shutdown

SIGTERM triggers a drain: stop accepting new connections, flush the AOF, run a final snapshot when persistence is enabled, then exit. SIGKILL skips the drain; on next boot the AOF replay resumes from the last fsync.

Metrics

Set [metrics] enabled = true. The server exposes a Prometheus-format endpoint at http://<metrics-bind>:<metrics-port>/metrics. Key exported series:

Series Meaning
kevy_connections_active Current open client connections
kevy_commands_total{cmd=…} Per-command command count
kevy_cmd_latency_ns_bucket{cmd=…} Histogram of per-command latency
kevy_keys_total{shard=…} Key count per shard
kevy_aof_lag_ms AOF write-to-fsync lag
kevy_memory_rss_bytes Resident set size

Backup and restore

kevy-cli backup --to ./snapshot-2026-07-01.kbackup   # safe online
kevy-cli restore --from ./snapshot-2026-07-01.kbackup --to /var/lib/kevy

backup runs against a live server; restore writes into a fresh data directory and the server picks the contents up on the next boot.

Cluster routing (single node, key-aware)

--cluster exposes each shard as a virtual cluster node so stock cluster-aware clients route writes directly to the owning shard. Topology is reported via CLUSTER SLOTS / SHARDS / NODES; a wrong-shard key on a cluster port replies -MOVED.

kevy --threads 8 --cluster      # main port 6379, shard ports 6380..6387
redis-cli -c -p 6380 SET foo bar

Full guide: docs/cluster.md.

Replication and failover

A kevy server can run as a primary that streams every applied mutation to N replicas, as a replica that mirrors a primary, or with kevy-elect integration as a quorum-failover node.

[replication]
role         = "primary"
listen_port_base = 16004

# or
role         = "replica"
upstream     = "primary.example:16004"

REPLICAOF / REPLICAOF NO ONE / ROLE retarget and inspect roles at runtime. Full server + client recipes in docs/replication.md.

Lua scripting

EVAL, EVALSHA, and SCRIPT LOAD / EXISTS / FLUSH are backed by the in-house pure-Rust luna runtime. Default Lua 5.1 (Redis ecosystem compatibility); opt into 5.2 – 5.5 per script with a #!lua version=N shebang. Includes pure- Rust cmsgpack and cjson standard libraries.

redis-cli -p 6379 EVAL "return redis.call('INCR', KEYS[1])" 1 counter

Full reference: docs/lua.md.

Client compatibility

The following client libraries are verified end-to-end against a default kevy --port 6379 instance, including the script-heavy paths:

Language Library Version
Java Jedis 5.x
.NET StackExchange.Redis 2.x
Go go-redis v9
Python redis-py 5.x
Python Celery 5.6
Ruby Sidekiq 6.5
Node.js ioredis 5.7
Node.js BullMQ 5.79
Node.js Bee Queue 1.7
Node.js node-redlock 5

redis-cli and valkey-cli both work out of the box.

What's not supported

Feature Why kevy doesn't ship it Recommended alternative
AUTH kevy assumes a trusted network. Authentication proxy in front of kevy.
TLS Same as AUTH — out of charter. stunnel / envoy TLS termination.
Multi-database SELECT One keyspace per server. Run multiple kevy instances on different ports.
ACL Single trust domain. Authentication proxy.
Multi-DC active-active Single-DC charter. A KV with explicit multi-region support.
Gossip discovery Topology is declarative. Operator-managed config.
Online resharding Resharding is offline. Plan capacity at the cluster boundary.

The detailed charter rationale lives in MIGRATION-FROM-VALKEY.md.

Reproducing the benchmarks

bash bench/run.sh              # portability smoke (Docker, no pipeline)
bash bench/loopback_c50.sh     # headline TCP loopback vs valkey/redis

Full method and the workload-by-workload table are in bench/REPORT.md.

Library entry-point

kevy also exposes a Rust library so the server can be started in- process:

use kevy::{Config, serve};

fn main() -> std::io::Result<()> {
    let cfg = Config::default()
        .with_bind("127.0.0.1")
        .with_port(6379)
        .with_data_dir("/var/lib/kevy");
    serve(cfg)
}

For embedding the engine without the network reactor at all, use kevy-embedded instead.

License

Licensed under either of MIT or Apache-2.0, at your option.