A fast, lightweight, RESP2/RESP3-compatible in-memory Redis server built entirely in Java from scratch — no external dependencies. Connect to it with redis-cli or any standard Redis client library.
Demo
demo.mp4
See docs/COMMANDS.md for the full list of supported commands (Strings, Lists, Hashes, Sets, Sorted Sets, Pub/Sub, Transactions, RESP3, Replication, RDB, etc.). See docs/design_decisions.md for deep-dive technical design rationale, JVM vs C Redis architecture trade-offs, and systems decisions.
- Java 17+ (or Docker)
rm -rf out && mkdir -p out
find src -name "*.java" | xargs javac -d out
# Start the server (using default radish.conf)
java -cp out com.radish.Main radish.conf
# In a new terminal, start the custom interactive CLI
java -cp out com.radish.Main cli# Multi-node Leader + Replica cluster
docker-compose up --buildRadish uses a non-blocking Java NIO architecture built on Selector, ServerSocketChannel, and ByteBuffer, following an event-driven design similar to Redis. This allows a single event loop to efficiently handle many concurrent client connections while minimizing thread context-switching overhead.
Benchmarks were executed locally using:
redis-benchmark -c 50 -n 100000 -q| Command | Throughput | Median Latency (p50) |
|---|---|---|
| PING | ~151,000 req/s | 0.151 ms |
| SET | ~144,000 req/s | 0.151 ms |
| GET | ~175,000 req/s | 0.151 ms |
| HSET | ~164,000 req/s | 0.151 ms |
| LPUSH | ~159,000 req/s | 0.151 ms |
Benchmark Configuration
- Localhost benchmark
- 50 concurrent clients
- 100,000 total requests
- Full Features Enabled:
everysecAOF Background Sync, RDB Snapshotting, Probabilistic Expiry, and Approximated LRU. - Java NIO event loop
| Metric | Value |
|---|---|
| Concurrent Clients | 50 |
| Requests | 100,000 |
| Peak Memory | ~24 MB |
| Average Latency | 0.17 ms |
| Median Latency | 0.15 ms |
| Aggregate Throughput | ~165,000 req/s |
The ~165K req/sec figure is the aggregate throughput across the full
redis-benchmark -c 50 -n 100000 -qrun (all command types combined); per-command breakdowns range from ~144K (SET) to ~175K (GET) req/sec, as shown above.
Benchmarks performed on the same machine to contrast Radish (Pure Java) against the industry-standard Redis (C).
| Metric | Radish (Java) | Redis (C) |
|---|---|---|
| PING | 151k req/s | 210k req/s |
| GET | 175k req/s | 220k req/s |
| SET | 144k req/s | 205k req/s |
While Redis remains faster due to its highly optimized C implementation, Radish demonstrates comparable architecture and achieves extremely high throughput using pure Java and Java NIO, even with full disk durability and memory eviction enabled.
Radish supports full Leader-Follower replication with multi-stage handshakes, binary RDB resync, and real-time command streaming:
# Connect to Follower server and replicate Leader on port 6389:
redis-cli -p 6390 REPLICAOF 127.0.0.1 6389
# Promote Follower to standalone primary:
redis-cli -p 6390 REPLICAOF NO ONE- Full Resync: Follower requests
PSYNC, Leader streams snapshot payload. - Live Stream: Mutating write commands (
SET,INCR,LPUSH,DEL) stream over non-blocking socket channels in real-time.
- RDB Binary Snapshotting (
SAVE/BGSAVE):- Compact binary snapshots (
dump.rdb) featuring type tags and 8-byte millisecond expiration tags. - Non-blocking
BGSAVEexecutes snapshotting asynchronously in a background thread.
- Compact binary snapshots (
- AOF Log Write-Through (
radish.aof):- Every mutating command is written to an AOF buffer and flushed every second (
everysec). BGREWRITEAOFcompacts command history into minimal dataset recovery commands.
- Every mutating command is written to an AOF buffer and flushed every second (
- Hybrid Startup Boot:
- Radish automatically loads
dump.rdbbaseline and replays remainingradish.aofdelta commands on startup.
- Radish automatically loads
Clients can negotiate protocol version 3 via HELLO 3:
- RESP3 Native Types: Map (
%), Set (~), Double (,), Boolean (#), Null (_), Push (>). - Dynamic Dual-Mode Encoding: Serves RESP3 native types when negotiated, or backward-compatible RESP2 array fallbacks.
Radish comes with a built-in interactive CLI client featuring:
- Colorized Formatting: Arrays, integers, strings, and errors are color-coded for readability.
- Session History: Type
historyto view past commands, and!Nto re-execute them. - Watch Mode:
watch 2 DBSIZEclears the screen and runs the command every 2 seconds.
Running on port 6380 while the server is active. Open http://localhost:6380 in your browser for a live web dashboard showing server statistics, memory usage, and keyspace contents.
src/main/java/com/radish/
├── Main.java # Server & CLI entry point
├── config/
│ ├── ServerConfig.java # Configuration properties
│ └── ConfigFileParser.java # redis.conf style parser
├── server/
│ ├── RadishServer.java # NIO Selector Event Loop
│ ├── NioSession.java # Non-blocking stateful connection buffers
│ ├── ConnectionManager.java # Active connections tracker
│ └── ActiveExpiryDaemon.java # Probabilistic background sweeper
├── replication/
│ └── ReplicationManager.java # Leader/Replica state, RDB stream & broadcast
├── protocol/
│ ├── RespParser.java # RESP2/RESP3 zero-copy parser with ProtocolException
│ ├── RespEncoder.java # Dual-mode RESP2/RESP3 wire encoder
│ ├── RespCommand.java # Parsed command DTO
│ ├── RespMap.java # RESP3 Map wrapper (%)
│ ├── RespSet.java # RESP3 Set wrapper (~)
│ └── RespPush.java # RESP3 Push wrapper (>)
├── command/ # Command Handlers
│ ├── CommandDispatcher.java # Routing, AOF write-through & replication streaming
│ ├── ReplicaOfCommand.java # REPLICAOF / SLAVEOF
│ ├── PsyncCommand.java # PSYNC / SYNC
│ ├── HelloCommand.java # HELLO (RESP3 negotiation)
│ ├── SaveCommand.java # SAVE
│ ├── BgsaveCommand.java # BGSAVE
│ └── ... # (35+ command handlers)
├── persistence/
│ ├── RdbWriter.java # Binary snapshot serializer
│ ├── RdbLoader.java # Binary snapshot deserializer
│ ├── AofWriter.java # Background AOF queue + fsync
│ └── AofLoader.java # MappedByteBuffer AOF replay
├── storage/
│ ├── InMemoryStorage.java # ConcurrentHashMap engine + SCAN + WATCH touch
│ └── ScanResult.java # SCAN cursor pagination DTO
├── transaction/
│ ├── TransactionState.java # MULTI/EXEC/WATCH transaction state
│ └── WatchManager.java # Optimistic key locking manager
├── test/ # Comprehensive Test Suites
│ ├── RespParserUnitTest.java # Parser unit tests
│ ├── CommandHandlerUnitTest.java# Isolated handler unit tests
│ ├── ConfigFileParserTest.java # Config file tests
│ ├── FuzzTest.java # 150,000+ fuzzing & bit-flip iterations
│ ├── Resp3Test.java # RESP3 protocol tests
│ ├── ReplicationTest.java # Leader-Follower integration tests
│ ├── RdbPersistenceTest.java # RDB persistence tests
│ ├── ConcurrencyTest.java # Multi-threaded safety tests
│ └── StressTest.java # High-throughput benchmark suite
└── http/
└── AdminHttpServer.java # Embedded JSON API & Web Dashboard on port 6380
