Skip to content

v0.2.0

Choose a tag to compare

@barddoo barddoo released this 22 Oct 23:25
· 16 commits to main since this release
Immutable release. Only release title and notes can be modified.

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

  • TTL returned the absolute expiry timestamp instead of seconds remaining
  • RENAME to an existing key hit unreachable
  • INCR/DECR/INCRBY/DECRBY replied 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
  • CONFIG command was not registered
  • Clock initialisation crash on Linux (undefined timestamp before the update coroutine ran)

Migrating from 0.1.x

  • aof_write_buffer_size config key is removed — delete it from your config file if present
  • Default executor count is now 1; set executors auto to restore the previous behaviour
  • Build optimisation is now ReleaseFast by default

Full Changelog: 0.1.3...v0.2.0