A Redis-protocol-compatible in-memory server written in Go. It speaks both
RESP2 and RESP3 and works with standard Redis client libraries
(verified against redis-py 8.0.1 and node-redis 6.0.1).
go build -o zenith .
./zenith --addr :6379Then point any Redis client at it:
redis-cli -p 6379
# or
python3 -c "import redis; r=redis.Redis(port=6379); print(r.ping())"main.go entrypoint / flag parsing
resp/ RESP2 + RESP3 wire protocol
resp.go reader: parses *N $L bulk arrays + inline commands
writer.go writer: encodes replies, downgrades RESP3 -> RESP2
store/ in-memory keyspace (per-DB, mutex-guarded)
db.go keyspace, expiry, generic key ops
string.go string type + counters
list.go list type
set_hash.go set + hash types
zset.go sorted set (score-ordered)
server/ networking + command dispatch
server.go TCP listener
engine.go 16 logical DBs + pub/sub registry
conn.go per-connection state, read loop, subscriber impl
pubsub.go channel + pattern subscriptions
dispatch.go command table, arity checks, MULTI/EXEC/WATCH
cmd_conn.go PING ECHO SELECT HELLO CLIENT CONFIG INFO ...
cmd_key.go DEL EXISTS TYPE KEYS EXPIRE TTL SCAN RENAME ...
cmd_string.go SET GET INCR APPEND GETRANGE SETRANGE MSET ...
cmd_list.go LPUSH RPUSH LPOP LRANGE LREM LTRIM ...
cmd_sethash.go SADD SMEMBERS SUNION / HSET HGETALL HDEL ...
cmd_zset.go ZADD ZRANGE ZRANGEBYSCORE ZRANK ZINCRBY ...
cmd_pubsub.go SUBSCRIBE PSUBSCRIBE PUBLISH ...
- Protocol: RESP2 and RESP3, including the
HELLOhandshake with version negotiation,AUTH/SETNAMEoptions, and RESP3-native maps, sets, doubles, booleans, nulls, and push frames. - Keys: DEL, UNLINK, EXISTS, TYPE, KEYS, SCAN, RENAME, RENAMENX, RANDOMKEY, EXPIRE, PEXPIRE, EXPIREAT, PEXPIREAT, TTL, PTTL, PERSIST. Lazy expiry on access.
- Strings: SET (NX/XX/GET/EX/PX/EXAT/PXAT/KEEPTTL), GET, GETSET, GETDEL, SETNX, SETEX, PSETEX, MSET, MGET, MSETNX, APPEND, STRLEN, INCR/DECR/INCRBY/ DECRBY/INCRBYFLOAT, GETRANGE, SETRANGE.
- Lists: LPUSH/RPUSH(+X), LPOP/RPOP (with count), LLEN, LINDEX, LSET, LRANGE, LTRIM, LREM.
- Sets: SADD, SREM, SISMEMBER, SCARD, SMEMBERS, SUNION, SINTER, SDIFF.
- Hashes: HSET, HMSET, HSETNX, HGET, HMGET, HDEL, HLEN, HEXISTS, HGETALL, HKEYS, HVALS.
- Sorted sets: ZADD (NX/XX/GT/LT/CH/INCR), ZSCORE, ZINCRBY, ZCARD, ZREM, ZRANGE, ZREVRANGE, ZRANGEBYSCORE, ZRANK, ZREVRANK, ZCOUNT, WITHSCORES.
- Pub/Sub: SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH with glob pattern matching.
- Transactions: MULTI, EXEC, DISCARD, WATCH, UNWATCH (queueing + EXECABORT).
- Server/conn: SELECT (16 DBs), DBSIZE, FLUSHDB, FLUSHALL, INFO, CONFIG GET/SET, TIME, CLIENT, COMMAND, RESET, QUIT.
This is the core of Redis, not all of it. Missing:
- Persistence: no RDB snapshots, no AOF. Data is in-memory only.
- Replication & cluster: no replicas, no cluster mode / hash slots.
- Scripting: no EVAL / Lua / FUNCTION.
- Other types/features: no streams, HyperLogLog, geo, bitfields, bitmap ops, blocking ops (BLPOP/BRPOP), keyspace notifications, or ACLs.
- SCAN is non-incremental: it returns all matching keys in one pass with cursor 0. Correct for clients that loop until cursor 0, but not a true incremental cursor.
test_resp2.py and test_advanced.py exercise the server with redis-py
(RESP2 + RESP3). nodeclient/test.js cross-verifies with node-redis.
Combined: 70 redis-py checks + 17 node-redis checks, all passing.