Taj
← all projects

Redis-Rust

An in-memory Redis-style store in Rust: strings with TTL, lists, sets and sorted sets, served over a Redis-style TCP protocol and a JSON HTTP API.

rust · tokio · axum · serde · ordered-float

Source ↗

Redis-Rust is an in-memory data store inspired by Redis, written in Rust to learn how a database server works from the socket up. It keeps all data in memory and serves it over two interfaces at once: a Redis-style TCP protocol and a JSON HTTP API.

What it supports

Data type Commands
Strings SET, GET, DEL, and SET key value EX seconds for expiry
Lists LPUSH, RPUSH, LPOP, RPOP, LRANGE (with negative indices)
Sets SADD, SREM, SISMEMBER, SMEMBERS
Sorted sets ZADD, ZREM, ZRANGE, ZSCORE
Utility PING

How it's built

  • TCP server on port 6379. A Tokio TcpListener accepts connections and spawns one task per client. Each command is read as a line, matched with Rust slice patterns (["SET", key, value, "EX", ttl]), and answered in RESP, the Redis wire format.
  • HTTP API on port 3000. An axum router exposes the same operations as JSON endpoints, for example POST /keys/:key, GET /lists/:key/range/:start/:end and POST /zsets/:key/add. Both servers share one Arc<Database>, so a key written over TCP can be read over HTTP.
  • One lock per data type. Strings, expiry times, lists, sets and sorted sets each live in their own HashMap behind an RwLock, so reads run in parallel and list traffic never blocks string reads.
  • Lazy expiry. SET ... EX records a deadline, and GET deletes the key if the deadline has passed.
  • Sorted sets on two structures. A HashMap gives ZSCORE its member lookup, and a BTreeSet ordered by (score, member) keeps ZRANGE in order. ordered-float makes f64 scores sortable.

Try it

bash
cargo run

Talk to the TCP server with netcat:

bash
echo "SET greeting hello" | nc localhost 6379
echo "ZADD scores 100 alice" | nc localhost 6379

Or use the HTTP API:

bash
curl -X POST localhost:3000/keys/greeting \
  -H "Content-Type: application/json" \
  -d '{"value": "hello", "ttl": 60}'
curl localhost:3000/keys/greeting

Limitations

  • Commands are read as plain lines, not RESP arrays, so nc works but redis-cli doesn't yet. Values can't contain spaces.
  • Data types don't conflict: one key can hold a string and a list at the same time, where Redis would return WRONGTYPE.
  • Expired keys are only removed when they're read. There's no background cleanup.
  • Nothing is persisted. Restarting the server clears all data.

I wrote about how it works in more detail in Building a Redis clone in Rust.