Repository navigation
v0.2.0
Zedis v0.2.0
This release is the most important yet. IO is now sorted out, the previous TCP server implementation was full of memory copy, buffers being released everywhere. It now uses a single-threaded async IO; Linux and MacOS implementations are performing extremely well. Zedis now outperforms Redis 8.8.1 by 40–51% on Linux and 3× on macOS on a single executor thread, with dramatically better tail latency.
Performance highlights
| Redis 8.8.1 | Zedis 0.2.0 | |
|---|---|---|
| SET (100c -P32) | 990k rps | 1,389k rps |
| GET (100c -P32) | 1,064k rps | 1,613k rps |
| SET p50 | 2.9ms | 2.2ms |
| GET p50 | 2.3ms | 2.0ms |
| GET max latency | 6.3ms | 2.9ms |
AOF appendfsync always |
~200k rps | ~190k rps |
Benchmarks run on the same Linux machine, single-threaded, no persistence, redis-benchmark -n 100000 -c 100 -P 32.
Machine: Ubuntu 26.04.1 LTS, Linux 7.0.0-34-generic, i7-11800H, 32GB RAM.
What changed
Zero-copy command parsing: Commands that arrive buffered are now parsed in a single pass without allocating. Arg slices point directly into the socket read buffer. Bulk strings up to 512 MB are accepted.
Single executor by default: Zedis now runs on one OS thread by default. SET/GET throughput increased 1.7× and CPU use dropped from ~450% to ~75%. Multithreaded might be eventually be dropped.
AOF writer thread with group commit: File I/O is offloaded to a dedicated OS thread. Under appendfsync always, concurrent writes are batched into a single fsync. Throughput under always went from ~450 rps to ~190k rps (420×).
Rolled our own custom hash map: We previously used std hash map, which was good, but this approach made more sense for this project. The entry array now doubles in size with each resize. Insert throughput past 1M keys increased from 6.6k rps to 173k rps (26×). It is much harder to maintain it, but the results are worth it.
Bug fixes
TTLreturned the absolute expiry timestamp instead of seconds remainingRENAMEto an existing key hitunreachableINCR/DECR/INCRBY/DECRBYreplied with bulk strings instead of RESP integers- Error replies had the code doubled (
-ERR ERR …) - List commands (
LPUSH,RPUSH,LPOP,RPOP,LSET) were not logged to the AOF CONFIGcommand was not registered- Clock initialisation crash on Linux (undefined timestamp before the update coroutine ran)
Migrating from 0.1.x
aof_write_buffer_sizeconfig key is removed — delete it from your config file if present- Default executor count is now
1; setexecutors autoto restore the previous behaviour - Build optimisation is now
ReleaseFastby default
Full Changelog: 0.1.3...v0.2.0