Skip to content

Joyzyy/redis-clone

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Redis Clone (Go)

This is a compact Redis-like server written in Go. I built it as a learning project to understand the pieces that make Redis feel fast and simple: the protocol, the data model, and how replication and persistence are hooked together.


Why I made this

Redis is deceptively simple at the surface. Under the hood there's a tidy set of primitives that work together to provide low-latency operations and reliable replication. I wanted a codebase that shows those primitives in plain Go: no frameworks, just sockets, goroutines, and clear data structures.

This project helped me learn: TCP/RESP parsing, in-memory data structures, expirations, replication handshakes, and the RDB snapshot format.


How it works (high level)

Global context

  • global.MainContext (app/global/context.go) — Every client connection gets a MainContext. It bundles the active connection, the in-memory store, parsed command arguments, transaction state, and client-specific flags. That makes handlers small and focused.
  • global.Memory (app/global/memory.go) — A threadsafe in-memory key/value store. It stores typed values (strings, lists, streams, zsets, ...), supports expiration, and acts as the single source of truth for the server process.

Client handling

  • connection.HandleClient (app/connection/connection.go) accepts TCP connections and runs a small loop to parse RESP frames, update the MainContext, and dispatch commands to handlers in app/commands/.
  • Handlers read ctx.Args, operate on ctx.Memory, and write RESP replies back to ctx.Conn. Transactional state (MULTI/EXEC) and blocking commands are handled per-context so clients remain isolated.

Commands and dispatch

Commands are implemented in app/commands/ and registered in the dispatcher. Each handler validates arguments, manipulates global.Memory, and composes RESP responses using helpers in app/utils/.


RDB parser, partial sync, and persistence (focus)

Persistence and replication are intentionally simple but practical:

  • On startup the server can load an RDB file using rdb.ReadFrom (app/rdb/rdb.go). That code parses the Redis RDB binary layout and rebuilds the in-memory structures (strings, lists, streams, zsets, expirations). The implementation is compact and written to be easy to follow rather than fully optimized.
  • For replication we implement a PSYNC-style handshake. When a replica connects, the master may stream an RDB snapshot followed by incremental commands. The RDB parser is used during that initial sync to populate the replica's global.Memory.
  • Expirations read from the RDB are scheduled after loading so TTL behavior matches the persisted snapshot.

Why this matters: implementing a real RDB parser forces the code to face binary formats, type markers, and corner cases like compressed payloads and special encodings. It also gives a clean way to bootstrap replicas without implementing an append-only log.

Note: this project focuses on RDB snapshots for durability and replication. There is no full AOF implementation here — that would be a valuable extension.


Supported data types & commands

Below is a concise list of what this server supports. It aims to mirror Redis commands where useful but keeps behavior intentionally simple.

Basic

  • PING — check server is alive
  • ECHO — echo a message
  • SET — set a string value (supports PX for millisecond TTL)
  • GET — get a string value
  • TYPE — return the type of the value stored at a key
  • INCR — increment an integer string atomically

Lists

  • RPUSH / LPUSH — push elements to the tail/head
  • LRANGE — return a sub-range of a list
  • LLEN — list length
  • LPOP — pop one or more elements from head
  • BLPOP — blocking pop with timeout

Streams

  • XADD — append an entry to a stream
  • XRANGE — query entries by ID range
  • XREAD — read entries (blocking/non-blocking)

Sorted Sets (zsets)

  • ZADD — add a member with a score (app/commands/zset.go)
  • ZRANK — rank of a member
  • ZRANGE — range by rank
  • ZCARD — cardinality
  • ZSCORE — score of a member
  • ZREM — remove a member

Transactions

  • MULTI — begin transaction
  • EXEC — execute queued commands
  • DISCARD — cancel a transaction

Pub/Sub

  • SUBSCRIBE / UNSUBSCRIBE — subscribe or unsubscribe from channels
  • PUBLISH — publish a message to subscribers

Replication & server tools

  • INFO — server info (role, replication state)
  • REPLCONF — replication handshake options
  • PSYNC — partial synchronization (initial RDB snapshot + offset)
  • WAIT — wait for write propagation to replicas
  • CONFIG — query configuration
  • KEYS — list keys from the loaded RDB snapshot

Implementation highlights

  • Networking: plain net package with a tight RESP parser.
  • Concurrency: goroutines for connection handling, expiration timers, and replication streams.
  • Data structures: typed values for strings, lists, streams and zsets; handlers are intentionally small and readable.
  • Replication: PSYNC-style sync using RDB snapshots to bootstrap replicas, then command propagation.
  • Tests: small unit and integration tests (where present) focus on correctness over performance.

Try it locally

Run the server and connect with any Redis client that speaks RESP:

go run app/main.go

# then, from another terminal, you can use redis-cli or telnet:
redis-cli -p 6379 PING

If your environment uses a different port, check app/server_config.go.


Next steps and ideas

  • Add an AOF writer for command-based persistence.
  • Implement more zset and stream commands for parity with Redis.
  • Implement more data structures (geospatial, hash tables, etc.)
  • Add benchmark and profiling harnesses to explore performance bottlenecks.

About

A lightweight Redis clone written in Go (using only the std lib) - supports: lists, streams, zsets, transactions, pub/sub, replication (PSYNC - initial rdb snapshot + offset) & .rdb parser

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages