SableDB
is a key-value NoSQL database that utilizes RocksDB
as its storage engine and is compatible with the Valkey protocol.
It aims to reduce memory costs and increase capacity compared to Valkey. SableDB
features include Valkey-compatible access via
any Valkey client, up to 64K databases support, asynchronous replication using transaction log tailing and TLS connectivity support.
SableDB
is supported on all major OS: Linux
, macOS
and Windows
git clone https://github.com/sabledb-io/sabledb.git
cd sabledb
git submodule update --init
cargo build --release
cargo test --release
On Windows, we require MSYS2
terminal for building SableDB
.
First, ensure that you have the required toolchain (beside Rust):
pacman -Sy git \
mingw-w64-clang-x86_64-toolchain \
mingw-w64-clang-x86_64-python3 \
mingw-w64-clang-x86_64-cmake \
mingw-w64-clang-x86_64-libffi \
unzip \
mingw-w64-clang-x86_64-gcc-compat
git clone https://github.com/sabledb-io/sabledb.git
cd sabledb
git submodule update --init
CFLAGS="-D_ISOC11_SOURCE" cargo build --release
cargo test --release
./target/release/sabledb
Usage:
$target/release/sabledb [sabledb.ini]
docker build -t sabledb:latest .
docker run -p 6379:6379 sabledb:latest
If you prefer to use docker-compose
, you can use the following command:
docker compose up --build
To tail the logs, use the below command:
docker exec -it sabledb-sabledb-1 /bin/bash -c "tail -f /var/lib/sabledb/log/sabledb.log.*"
Note: the container name (in the above example: sabledb-sabledb-1
) can be found using the command docker ps
- Persistent data using RocksDB - use
SableDB
as a persistent storage usingValkey
's API - TLS connections
- Replication using tailing of the transaction log
- Highly configurable, but comes with sensible default values
- Use the
sabledb-benchmark
command line utility (target/release/sabledb-benchmark
) for performance testing - Transactions (
MULTI
/EXEC
) - Auto-failover & recovery
SableDB
uses its own benchmarking tool named sabledb-benchmark
. sabledb-benchmark
supports the following commands:
set
get
lpush
lpop
rpush
rpop
incr
ping
hset
setget
Run sabledb-benchmark --help
to get the full help message.
Below is a simple ( ping
) test conducted locally using WSL2 on Windows 10 (same machine is running both SableDB
and sabledb-benchmark
...):
set
test, on the same set-up (local machine, WSL2 on Windows 10):
IMPORTANT
SableDB
is under constant development, if you are missing a command, feel free to open an issue
and visit this page again in couple of days
Command | Supported | Fully supported? | Comment |
---|---|---|---|
append | ✓ | ✓ | |
decr | ✓ | ✓ | |
decrby | ✓ | ✓ | |
get | ✓ | ✓ | |
getdel | ✓ | ✓ | |
getex | ✓ | ✓ | |
getrange | ✓ | ✓ | |
getset | ✓ | ✓ | |
incr | ✓ | ✓ | |
incrby | ✓ | ✓ | |
incrbyfloat | ✓ | ✓ | |
lcs | ✓ | x | Does not support: IDX , MINMATCHLEN and WITHMATCHLEN |
mget | ✓ | ✓ | |
mset | ✓ | ✓ | |
msetnx | ✓ | ✓ | |
psetex | ✓ | ✓ | |
set | ✓ | ✓ | |
setex | ✓ | ✓ | |
setnx | ✓ | ✓ | |
setrange | ✓ | ✓ | |
strlen | ✓ | ✓ | |
substr | ✓ | ✓ |
Command | Supported | Fully supported? | Comment |
---|---|---|---|
blmove | ✓ | ✓ | |
blmpop | ✓ | ✓ | |
blpop | ✓ | ✓ | |
brpop | ✓ | ✓ | |
brpoplpush | ✓ | ✓ | |
lindex | ✓ | ✓ | |
linsert | ✓ | ✓ | |
llen | ✓ | ✓ | |
lmove | ✓ | ✓ | |
lmpop | ✓ | ✓ | |
lpop | ✓ | ✓ | |
lpos | ✓ | ✓ | |
lpush | ✓ | ✓ | |
lpushx | ✓ | ✓ | |
lrange | ✓ | ✓ | |
lrem | ✓ | ✓ | |
lset | ✓ | ✓ | |
ltrim | ✓ | ✓ | |
rpop | ✓ | ✓ | |
rpoplpush | ✓ | ✓ | |
rpush | ✓ | ✓ | |
rpushx | ✓ | ✓ |
Command | Supported | Fully supported? | Comment |
---|---|---|---|
hset | ✓ | ✓ | |
hget | ✓ | ✓ | |
hmget | ✓ | ✓ | |
hmset | ✓ | ✓ | |
hgetall | ✓ | ✓ | |
hdel | ✓ | ✓ | |
hlen | ✓ | ✓ | |
hexists | ✓ | ✓ | |
hincrby | ✓ | ✓ | |
hincrbyfloat | ✓ | ✓ | |
hkeys | ✓ | ✓ | |
hvals | ✓ | ✓ | |
hrandfield | ✓ | ✓ | |
hscan | ✓ | ✓ | |
hsetnx | ✓ | ✓ | |
hstrlen | ✓ | ✓ |
Command | Supported | Fully supported? | Comment |
---|---|---|---|
bzmpop | ✓ | ✓ | |
bzpopmax | ✓ | ✓ | |
bzpopmin | ✓ | ✓ | |
zadd | ✓ | ✓ | |
zcard | ✓ | ✓ | |
zincrby | ✓ | ✓ | |
zcount | ✓ | ✓ | |
zdiff | ✓ | ✓ | |
zdiffstore | ✓ | ✓ | |
zinter | ✓ | ✓ | |
zintercard | ✓ | ✓ | |
zinterstore | ✓ | ✓ | |
zlexcount | ✓ | ✓ | |
zmpop | ✓ | ✓ | |
zmscore | ✓ | ✓ | |
zpopmax | ✓ | ✓ | |
zpopmin | ✓ | ✓ | |
zrandmember | ✓ | ✓ | |
zrangebyscore | ✓ | ✓ | |
zrevrangebyscore | ✓ | ✓ | |
zrangebylex | ✓ | ✓ | |
zrevrangebylex | ✓ | ✓ | |
zrange | ✓ | ✓ | |
zrangestore | ✓ | ✓ | |
zrank | ✓ | ✓ | |
zrem | ✓ | ✓ | |
zremrangebylex | ✓ | ✓ | |
zremrangebyrank | ✓ | ✓ | |
zremrangebyscore | ✓ | ✓ | |
zrevrange | ✓ | ✓ | |
zrevrank | ✓ | ✓ | |
zunion | ✓ | ✓ | |
zunionstore | ✓ | ✓ | |
zscore | ✓ | ✓ | |
zscan | ✓ | ✓ |
Command | Supported | Fully supported? | Comment |
---|---|---|---|
sadd | ✓ | ✓ | |
scard | ✓ | ✓ | |
sdiff | ✓ | ✓ | |
sdiffstore | ✓ | ✓ | |
sinter | ✓ | ✓ | |
sintercard | ✓ | ✓ | |
sinterstore | ✓ | ✓ | |
sismember | ✓ | ✓ | |
smismember | ✓ | ✓ | |
smembers | ✓ | ✓ | |
smove | ✓ | ✓ | |
spop | ✓ | ✓ | |
srandmember | ✓ | ✓ | |
srem | ✓ | ✓ | |
sscan | ✓ | ✓ | |
sunion | ✓ | ✓ | |
sunionstore | ✓ | ✓ |
Command | Supported | Fully supported? | Comment |
---|---|---|---|
del | ✓ | ✓ | |
ttl | ✓ | ✓ | |
exists | ✓ | ✓ | |
expire | ✓ | ✓ | |
keys | ✓ | x | Pattern uses wildcard match ( ? and * ) |
scan | ✓ | x | Pattern uses wildcard match ( ? and * ) |
Command | Supported | Fully supported? | Comment |
---|---|---|---|
info | ✓ | ✓ | SableDB has its own INFO output format |
ping | ✓ | ✓ | |
replicaof | ✓ | ✓ | |
slaveof | ✓ | ✓ | |
command | ✓ | ✓ | |
command docs | ✓ | x | |
flushall | ✓ | ✓ | |
flushdb | ✓ | ✓ | |
dbsize | ✓ | ✓ | Data is accurate for the last scan performed on the storage |
Command | Supported | Fully supported? | Comment |
---|---|---|---|
multi | ✓ | ✓ | |
exec | ✓ | ✓ | |
discard | ✓ | ✓ | |
watch | ✓ | ✓ | |
unwatch | ✓ | ✓ |
Command | Supported | Fully supported? | Comment |
---|---|---|---|
client id | ✓ | ✓ | |
client kill | ✓ | x | supports: client kill ID <client-id> |
select | ✓ | ✓ | |
ping | ✓ | ✓ |
Payload size (bytes) | rps | p50 (ms) | p90 (ms) | p99 (ms) |
---|---|---|---|---|
64 | 448K | 1.127 | 1.279 | 1.423 |
128 | 420K | 1.199 | 1.375 | 1.551 |
256 | 363K | 1.375 | 1.567 | 1.799 |
Payload size (bytes) | rps | p50 (ms) | p90 (ms) | p99 (ms) |
---|---|---|---|---|
64 | 950K | 0.495 | 0.671 | 1.087 |
128 | 907K | 0.511 | 0.695 | 1.111 |
256 | 905K | 0.519 | 0.711 | 1.119 |
Note: Each mset
command is equivalent of 10
set
commands
Payload size (bytes) | rps | p50 (ms) | p90 (ms) | p99 (ms) |
---|---|---|---|---|
64 | 116K | 3.8 | 4.6 | 6.3 |
128 | 72K | 6.375 | 7.039 | 54.111 |
256 | 41.5K | 0.432 | 7.279 | 226.943 |
The increment command is unique because it uses a "read-modify-update" in order to ensure the atomicity of the action which in a multi-threaded environment causes a challenge
Payload size (bytes) | rps | p50 (ms) | p90 (ms) | p99 (ms) |
---|---|---|---|---|
N/A | 443K | 1.127 | 1.295 | 1.383 |
Command | rps | pipeline | p50 (ms) | p90 (ms) | p99 (ms) |
---|---|---|---|---|---|
ping_inline | 1.05M | 1 | 0.407 | 0.775 | 1.143 |
ping_inline | 6.65M | 20 | 0.855 | 1.551 | 1.815 |
ping_mbulk | 1.05M | 1 | 0.399 | 0.727 | 1.127 |
ping_mbulk | 7.96M | 20 | 0.807 | 1.471 | 1.711 |
Command executions can be seen here