默认监听 6380 而非 6379,客户端需改端口或传 --port 6379;默认开启 protected mode,远程连接需设密码或 --bind;Lua 脚本和 TLS 需用 --features lua/tls 编译,默认构建不支持;启动重建索引期间多数命令返回 LOADING。
kividb
kividbioAGPL-3.0活跃维护用 Rust 写的高性能多线程 Redis/Valkey 替代品,可直接替换现有部署,并内置全文检索和向量搜索,适合做缓存和 RAG 检索后端。
A fast, multi-threaded Redis® and Valkey alternative written in Rust: drop-in compatible, with full-text and vector search built in
docker run -d -p 6380:6380 kividb/kividb
redis-cli -p 6380 PINGREADME 未说明显存或 GPU 要求;为纯内存数据库,需按数据量预留内存。Linux 上内核允许时使用 io_uring,否则回退 Tokio。
用 Rust 写的多线程 Redis/Valkey 替代品,兼容 RESP 协议并内置全文与向量检索
用 Rust 写的高性能多线程 Redis/Valkey 替代品,可直接替换现有部署,并内置全文检索和向量搜索,适合做缓存和 RAG 检索后端。
核心能力
- 兼容 RESP2/RESP3,现有 Redis 客户端和 redis-cli 可直接连接
- 分片内存 KV 设计,命令在所有核心上并行执行
- 内置 FT.* 命令,支持全文、标签、数值及 FLAT/HNSW 向量检索
- 支持快照与可选 AOF 持久化,快照可保存 HNSW 图
- Lua 脚本与 TLS 作为可选 Cargo feature 按需编译
容易踩的坑
- v1.2.0最新正式版2026-11-03 · 2026-11-03 18:35 UTC
KiviDB v1.2.0
What's in 1.2.0
1.2.0 is mostly about not losing writes, and being a better Redis:
- Durability.
- With the append-only file on, a write is now acknowledged only once its record is in the file, as in Redis, so a killed process keeps every write it acknowledged, as long as the disk keeps up: a reply waits at most 5 s for its record, and one sent without it is counted in
INFO persistenceasaof_acks_before_write. - A checkpoint no longer stalls writes for seconds on a slow disk.
- A graceful shutdown (
SHUTDOWN, SIGTERM) keeps every write it acknowledged: no command runs from the start of the final snapshot to the exit. - A transaction, or a script that writes more than once, reaches replicas and the AOF as one step, so a replica never shows it half done.
- A manual failover whose election is slow no longer loses writes.
- Automatic failover elects the replica with the most data, and a replica stands only once it holds its master's data: never in the middle of a full sync, and its data's age counts from when it was last in step.
- A clean shutdown waits up to
shutdown-timeout(10 s) for its replicas to have every write, so after a restart they carry on instead of being sent the whole dataset. A manual failover does the same for the master it replaces. - A full sync under heavy writes finishes: while the replica loads the dataset, the writes kept for it may grow to
repl-replica-sync-max-backlog-bytes(1 GiB) instead of the normal limit, and both limits can be changed withCONFIG SET. - A replica stopped in the middle of a full sync keeps its last good
dump.kdbinstead of saving the partial dataset over it. - A server started in a data directory another one is still using, as a replacement pod can be after a forced delete, waits for it to exit instead of loading what it was about to replace.
- With the append-only file on, a write is now acknowledged only once its record is in the file, as in Redis, so a killed process keeps every write it acknowledged, as long as the disk keeps up: a reply waits at most 5 s for its record, and one sent without it is counted in
- Clusters.
- The bus keeps one connection per peer.
- Nodes can announce a separate client port (
cluster-announce-client-port), for NodePorts and load balancers. - After a failover, the shard's other replicas carry on instead of resyncing in full.
- An import cut short by a restart cleans up after itself.
redis-cli --cluster reshardruns to the end under writes and loses none of them: writes to the keys aMIGRATEis moving wait for it, as in Redis.redis-cli --cluster fixcloses a reshard that stopped halfway, and no key is left on the wrong node:CLUSTER DELSLOTSworks as in Redis, andDEBUG DIGEST-VALUEreturns each value's digest.
- TLS without restarts.
- Certificates, CAs and
tls-portchange withCONFIG SET. - A server can turn TLS on while it runs.
port 0runs a server on TLS only.tls-auth-clients-allowed-namesaccepts only client certificates whose names match.
- Certificates, CAs and
- Memory.
- Active defrag gives memory freed by deletes back to the system, and is on by default.
- String values take less memory.
- Multi-key writes.
MSETandMSETNXof keys in many shards no longer queue behind each other: more than three times as many a second as 1.1.3 with 1,200 clients, and a lower tail. - Search. TEXT fields are stemmed, as in Redis:
preferencesfindsprefer. Scores come out as Redis's, andSCORERis honoured.FT.SEARCHandFT.AGGREGATEtake aTIMEOUT, and the timeout is safe across a rolling upgrade. Synonyms work. Scores stay right after updates and deletes. - Compatibility. Dozens of fixes bring KiviDB's replies, errors,
INFOandCLIENT LISTfields, keyspace events, Lua scripting and vector-set scores closer to Redis 8.10. - Signed releases. Every file and image carries a signed build attestation. Check one with
gh attestation verify <file> --repo kividbio/kividb.
CHANGELOG.md has the full list.
Security
1.2.0 fixes issues that let a user restricted by ACL read or overwrite keys outside their permissions, or read credentials
- Durability.
- v1.1.32026-10-31 · 2026-10-31 22:17 UTC
查看更新说明
KiviDB v1.1.3
This is a security release. Everyone on 1.1.x, and on the 1.2.0 release candidates, should upgrade. It fixes three vulnerabilities, all reported by @Parikalp-Bhardwaj:
- GHSA-58x5-jq4h-h6rr: a TLS client that never finishes its handshake could hold up new connections (denial of service).
maxclientsis now enforced, and counts TLS clients from the start of their handshake. - GHSA-rhrj-pgm8-2686: a write to a key whose time to live had passed, but which active expiry had not yet removed, could be acknowledged and then lost.
- GHSA-pjrr-m43f-m5g3: overlapping AOF checkpoints, or a crash at the wrong moment of one, could lose acknowledged writes or bring back deleted keys.
What's in 1.1.3
1.1.3 is a patch release of 1.1.0, made from 1.1.2. Besides the three fixes above:
- A cluster master back without its data no longer wipes its replicas. A master that restarts empty (no persistence, or its files lost) tells its replicas not to copy its empty dataset.
- Keys expire on replicas and in the AOF as they do on the master: the master now sends a
DELfor every key it expires. - A master drops a replica that has gone silent, after
repl-timeout. - Search: HNSW graphs are whole again after an AOF replay; a write in one database no longer touches another's indexes; expired keys,
RENAMEandRENAMENXkeep the indexes up to date;FT.DROPINDEX index DDreaches replicas and the AOF as the documents it deleted; a missing index is reported in Redis 8's words.
CHANGELOG.md has the full list.
Before you upgrade
- Replicas and clusters: upgrade the replicas first, then their master. A 1.1.2 replica does not understand a 1.1.3 master's "don't copy my empty dataset": once the master stops waiting, after 30 seconds, the replica syncs and drops its data, as 1.1.2 did. With the replicas on 1.1.3 first, nothing is lost.
maxclientsis now enforced, and a config file may set it. Check it is high enough for your connection count (default 10000).- Data files from 1.1.0 to 1.1.2 load unchanged.
Binary variants
Each OS/architecture ships four binaries — pick the one that matches your needs:
Tarball suffix Features included When to use (none) — Minimal / constrained environments -luaLua scripting EVAL/EVALSHA-tlsTLS termination Encrypted client connections -fullLua + TLS Recommended general-purpose build Full changelog: CHANGELOG.md
License: GNU Affero General Public License v3 (AGPL-3.0-only)
Code of conduct: CODE_OF_CONDUCT.md
Changes since v1.1.2:
What's Changed
- Version 1.1.3 by @murtazayusuf in https://github.com/kividbio/kividb/pull/220
- 1.1.3: the Docker image without OpenSSL (backport of #164) by @murtazayusuf in https://github.com/kividbio/kividb/pull/222
Full Changelog: https://github.com/kividbio/kividb/compare/v1.1.2...v1.1.3
- GHSA-58x5-jq4h-h6rr: a TLS client that never finishes its handshake could hold up new connections (denial of service).
- v1.1.22026-10-23 · 2026-10-23 20:09 UTC
查看更新说明
Affected by GHSA-58x5-jq4h-h6rr, GHSA-rhrj-pgm8-2686 and GHSA-pjrr-m43f-m5g3. Upgrade to v1.1.3.
KiviDB v1.1.2
What's in 1.1.2
1.1.2 is a patch release of 1.1.0. It replaces 1.1.1, which has been withdrawn for the expiry bug fixed here: if you run 1.1.1, upgrade. It brings KiviDB in line with Redis 8.10, the release it reports itself as. CI now runs Redis 8.10.2's own test suite against every change: it went from 2079 tests passed, 76 failed and 7 units that hung or stopped early, to 2697 passed and 6 failed, each of the 6 a documented difference (see docs/REDIS_TEST_SUITE.md). It also fixes a crash a crafted
RESTOREpayload could cause, keeps function libraries across restarts and replication, loads far more of what Redis writes, and makes the Linux packages run KiviDB as a service.CHANGELOG.md has the full list.
Before you upgrade
- The Docker image has no shell and no
redis-cli. It is now built ongcr.io/distroless/cc-debian12, which removes every critical CVE scanners reported on the 1.1.0 image.docker exec <name> redis-cliandkubectl exec … -- redis-clino longer work; connect from another container instead (docker run --rm -it --network container:<name> redis redis-cli -p 6380), or withkubectl debugor a port-forward. The server still runs as UID and GID 1000 in/home/kividb, so existing volumes keep working. - The
.deband.rpmnow install and start a systemd service. 1.1.0's packages installed only the binary. Upgrading from them, or installing fresh, enables and startskividb.service, which runs as thekividbuser with its data in/var/lib/kividband its config in/etc/kividb/kividb.conf, listening on127.0.0.1:6380. If you already run KiviDB from the packaged binary some other way on port 6380, stop that first or change the port in the config. A unit you have disabled stays disabled on later upgrades. - Function libraries are now kept in
dump.kdb. Before,SAVEand a restart, a clean stop with the AOF on,BGREWRITEAOFand a replica's full sync all dropped every library loaded withFUNCTION LOAD. In a rolling upgrade, a 1.1.2 replica that syncs from a 1.1.0 master gets no libraries, because the master's snapshot has none: upgrade the master (or fail over to an upgraded replica), then runFUNCTION LOADonce more, orFUNCTION RESTOREaFUNCTION DUMP. Going back to 1.1.0, its reader stops before the new section and starts without the libraries. - Replies and events that now follow Redis 8.10, which a client written
against 1.1.0 may notice:
MSETEXreplies1, or0whenNX/XXstops it (it repliedOKor nil).ARSCANandARGREP … WITHVALUESreply with[index, value]pairs.XINFO STREAM FULLcalls pending entriespending(waspel).HEXPIRE,HPEXPIREand theEX/PXofHGETEX/HSETEXtake 0 as now and remove the fields; only a negative time is an error.SETEXandPSETEXannouncesetthenexpire(they announcedsetex/psetex), and replacing a value announces the newo(overwritten) andc(type changed) events when those classes are on.- A script's error ends with the script and the place,
… script: <sha1>, on @user_script:1.;redis.error_reply('X')is-ERR X. XADD … IDMPAUTOhashes fields as Redis does, so an idempotent ID recorded by 1.1.0 does not match the same entry added again under 1.1.2 until it leaves its r
- The Docker image has no shell and no
- v1.1.1v1.1.1 (withdrawn)2026-10-23 · 2026-10-23 03:08 UTC
查看更新说明
Withdrawn. Under a high rate of writes with a TTL, background expiry falls behind and memory grows without bound (#87). Use 1.1.2, a patch release of 1.1.0 that includes everything in 1.1.1 and the fix. The 1.1.1 images and packages stay available so that nothing pinned to them breaks.
KiviDB v1.1.1
What's in 1.1.1
1.1.1 brings KiviDB in line with Redis 8.10, the release it reports itself as. CI now runs Redis 8.10.2's own test suite against every change: it went from 2079 tests passed, 76 failed and 7 units that hung or stopped early, to 2697 passed and 6 failed, each of the 6 a documented difference (see docs/REDIS_TEST_SUITE.md). It also fixes a crash a crafted
RESTOREpayload could cause, keeps function libraries across restarts and replication, loads far more of what Redis writes, and makes the Linux packages run KiviDB as a service.CHANGELOG.md has the full list.
Before you upgrade
- The Docker image has no shell and no
redis-cli. It is now built ongcr.io/distroless/cc-debian12, which removes every critical CVE scanners reported on the 1.1.0 image.docker exec <name> redis-cliandkubectl exec … -- redis-clino longer work; connect from another container instead (docker run --rm -it --network container:<name> redis redis-cli -p 6380), or withkubectl debugor a port-forward. The server still runs as UID and GID 1000 in/home/kividb, so existing volumes keep working. - The
.deband.rpmnow install and start a systemd service. 1.1.0's packages installed only the binary. Upgrading from them, or installing fresh, enables and startskividb.service, which runs as thekividbuser with its data in/var/lib/kividband its config in/etc/kividb/kividb.conf, listening on127.0.0.1:6380. If you already run KiviDB from the packaged binary some other way on port 6380, stop that first or change the port in the config. A unit you have disabled stays disabled on later upgrades. - Function libraries are now kept in
dump.kdb. Before,SAVEand a restart, a clean stop with the AOF on,BGREWRITEAOFand a replica's full sync all dropped every library loaded withFUNCTION LOAD. In a rolling upgrade, a 1.1.1 replica that syncs from a 1.1.0 master gets no libraries, because the master's snapshot has none: upgrade the master (or fail over to an upgraded replica), then runFUNCTION LOADonce more, orFUNCTION RESTOREaFUNCTION DUMP. Going back to 1.1.0, its reader stops before the new section and starts without the libraries. - Replies and events that now follow Redis 8.10, which a client written
against 1.1.0 may notice:
MSETEXreplies1, or0whenNX/XXstops it (it repliedOKor nil).ARSCANandARGREP … WITHVALUESreply with[index, value]pairs.XINFO STREAM FULLcalls pending entriespending(waspel).HEXPIRE,HPEXPIREand theEX/PXofHGETEX/HSETEXtake 0 as now and remove the fields; only a negative time is an error.SETEXandPSETEXannouncesetthenexpire(they announcedsetex/psetex), and replacing a value announces the newo(overwritten) andc(type changed) events when those classes are on.- A script's error ends with the script and the place,
… script: <sha1>, on @user_script:1.;redis.error_reply('X')is-ERR X. XADD … IDMPAUTOhashes fields as Redis does, so an idempotent ID recorded by 1.1.0 does not match the same entry added again under 1.1.1 until it leaves its retention window.- Arguments that were ignored or read loosely are refused with Redis's errors, and many error messages now use Redis 8.10's wording.
EVALscripts and functions each have their own Lua VM, as in Redis.
- The Docker image has no shell and no
- v1.1.02026-10-16 · 2026-10-16 18:34 UTC
查看更新说明
KiviDB v1.1.0
What's in 1.1.0
KiviDB is now open source, under the GNU Affero General Public License, version 3 (AGPL-3.0-only). The KiviDB End User License Agreement no longer applies to this or later releases. Using KiviDB as the database of your application does not put your application under the AGPL; only a modified KiviDB offered to others over a network must have its source offered too. A commercial license is also available. The entitlement check that builds for cloud marketplaces made at startup is removed, with the marketplace machine images.
1.1.0 supersedes 1.0.6, which was published only as release candidates (1.0.6-rc1 to 1.0.6-rc4) and never as a final release. Everything in those candidates is in 1.1.0. Coming from 1.0.5, it brings:
- security fixes: Lua scripts are kept in their sandbox, a command a script calls is checked against the user's ACL, protected mode is enforced, and malformed input from a client can no longer crash or stall the server;
- a server log you can act on, and a page explaining every warning and error;
- a startup update check;
- cluster work:
min-replicas-to-write, hostnames, a bus secret, TLS between nodes, and search indexes and queries across every master; - lower memory per key, scripts that run several times faster, and vector ingest about six times faster;
- images on Docker Hub as well as GHCR.
CHANGELOG.md has the full list.
Before you upgrade
- Protected mode is now enforced (
protected-mode yes, the default, as in Redis). With nobindaddress given and no password on thedefaultuser, only clients on the same machine may connect; others are told-DENIEDand disconnected. It used to be ignored. A server reached over the network with a passwordlessdefaultuser needs a password, abindaddress, orprotected-mode no. Replicas and cluster nodes connect as clients too. The Docker image turns protected mode off unless you pass arguments of your own. - Scripts are checked against the caller's ACL. A command a script runs
through
redis.callis now held to the same ACL rules as one the user sends directly. A user allowedEVALcould previously run any command on any key from a script. - Scripts lose
package,require,loadfile,dofile,debugandstring.dump, andloadtakes source text only, not bytecode. A script that used any of these fails. - Scripts on one hash tag may not touch keys outside it. A script whose
KEYSall carry one hash tag ({orders}:waiting) now runs beside scripts on other tags, and aredis.callon a key outside its tag fails.lua-parallel-scripts norestores the old behaviour. See docs/SCRIPTS.md. tls-ca-cert-filenow verifies client certificates. It was read and then ignored, so any client that trusted the server could connect. With a CA file set, a client must now present a certificate that CA signed, as on Redis. If you settls-ca-cert-fileand your clients send no certificate, they will be refused after upgrading: give them certificates, or set the newtls-auth-clientstono(not asked) oroptional(checked only when presented). Without a CA file nothing changes.- The server now makes one outbound HTTPS request at startup to
https://github.com/kividbio/kividb/releases/latest, unless you turn it off. If your hosts may not reach the internet, or you do not want the request made, addupdate-check noto the config file (or pass--update-check no, or setKIVIDB_NO_UPDATE_CHECK=1). A host without internet access still starts; it waits at most 1.5 seconds for the reply, and the failure is logged at debug level only. loglevelnow works. It was accepted and ignored: every message was printed, whatever it was set to. If you start KiviDB with--loglevel warningor `e
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
KiviDB is a fast, multi-threaded alternative to Redis® and Valkey, written in Rust. It
speaks the Redis protocol (RESP2 and RESP3), so existing Redis clients, redis-cli and
libraries work unchanged, and it has full-text and vector search built in. It runs every
core on a sharded in-memory key-value design, and persists to snapshots and an optional
append-only file.
On the same 32 cores, KiviDB serves 21 million pipelined GETs per second: about 9× Redis 8 and 2.3× Dragonfly, with under half Dragonfly's p99 latency (benchmarks).
docker run -d -p 6380:6380 kividb/kividb
redis-cli -p 6380 PING # PONG
KiviDB listens on 6380, not Redis's 6379, so the two can run side by side; point your
client at that port, or pass --port 6379.
- Protocol: Redis-compatible command surface (see COMMANDS.md for the supported commands)
- Search and vectors: Redis Stack–style
FT.*commands for full-text, tag, numeric and vector (FLAT / HNSW) search - Lua scripting: optional Cargo feature.
EVAL,SCRIPT,FUNCTION,FCALLand related commands are available in builds with--features lua(see Scripting commands (Lua)) - TLS: optional Cargo feature (
--features tls) - Default listen address:
0.0.0.0:6380, with protected mode on - License: GNU Affero General Public License v3 (AGPL-3.0-only), open source; using KiviDB does not put your application under the AGPL; see License
Repository: github.com/kividbio/kividb · Website: kividb.io
Moving from Redis? Migration guide · Compatibility and differences · Client examples · Benchmarks · Releases · Kubernetes operator
How it compares
| KiviDB | Redis 8 | Valkey 8 | Dragonfly | KeyDB | |
|---|---|---|---|---|---|
| License | AGPL-3.0 | RSALv2, SSPLv1 or AGPL-3.0 | BSD-3-Clause | BSL 1.1 | BSD-3-Clause |
| Language | Rust | C | C | C++ | C++ |
| Commands run on | every core (sharded) | one thread (I/O threads) | one thread (I/O threads) | every core (shared-nothing) | several threads |
Full-text and vector search (FT.*) | built in | built in (Query Engine) | separate module | built in | no |
| Lua scripting | lua build | yes | yes | yes | yes |
As of October 2026. Something out of date or wrong? Please open an issue.
Performance
KiviDB 1.2.0 against Garnet, Dragonfly, Redis, Redis Cluster and Valkey. Click for the full-resolution video.
KiviDB 1.2.0 was measured in November 2026 on Azure VMs against Redis 8.10, Redis Cluster, Valkey 9.1, Dragonfly 2.0, Garnet 2.2 and kvrocks 2.17, each on the same machines in the same hour, with p50/p99/p99.9 latency from two load generators. benchmarks/1.2.0/REPORT.md has every number and comparison; benchmarks/1.2.0 has the harnesses, raw results and charts.
| KiviDB 1.2.0 | Best other | Redis 8.10 | |
|---|---|---|---|
GET 100 B, pipeline 16 | 10.45M ops/s | Garnet 10.69M | 1.41M |
SET 100 B, pipeline 16 | 7.94M ops/s | Garnet 9.83M | 1.25M |
MSET of 10 keys | 569K commands/s | Garnet 800K | 144K |
| Lists, hashes, sets, sorted sets, counters, pipeline 16 | 4.2-6.6M ops/s | Redis Cluster (16 shards): level, ahead on HSET and INCR | 3.7-6.0x less |
| Bytes per key, 100 B values, 50M keys | 140.7 | Dragonfly 141.5 | 174.4 |
Memory added by BGSAVE, 30M keys of 1 KB under writes | +10% | Dragonfly +0.4% | +89% |
| Filtered vector search, 100 clients | 4,478 q/s | Dragonfly 811 | 1,802 |
| Cache hit rate (#202) | 60.96% | 60.78% |
Where KiviDB loses: Garnet is faster on SET at pipeline 16 and on MSET; Redis Cluster on
HSET and INCR; Dragonfly uses less memory per vector, during a snapshot, and for ASCII
values; Redis ingests vectors faster and serves 3-9% more cache reads a second. These are
cloud VMs, so absolute numbers are lower than on the bare-metal machines below.
Earlier runs: KiviDB 1.1 on bare metal
The figures in this section are from one session in October 2026 on AWS Graviton3 bare metal: the
server on a c7gn.metal (64 vCPU), confined to 32 cores, and the load generator on a
second c7gn.metal in the same placement group. Each engine ran alone on the server,
one after another.
Key-value
memtier_benchmark through kivi-benchmark's run-matrix.sh: 10 million keys, 100-byte
values, 30 s a scenario, mean of two rounds; 300 connections pipelined, 1,200 without
pipelining.
| ops/s | KiviDB 1.1.0 | Dragonfly 2.0.2 | Redis 8.10 | Redis Cluster (32 shards) |
|---|---|---|---|---|
| GET, pipeline 16 | 21.2M | 9.1M | 2.4M | 4.7M |
| SET, pipeline 16 | 19.2M | 8.5M | 2.0M | 4.7M |
| GET, no pipelining | 3.07M | 3.35M | 1.32M | 1.46M |
| SET, no pipelining | 3.12M | 3.38M | 1.54M | 1.46M |
| p99 latency, GET / SET, pipeline 16 | 0.36 / 0.42 ms | 0.88 / 1.07 ms | 2.2 / 2.7 ms | |
| Memory per key | 177 B | 134 B | 178 B | 183 B |
Vector search
redis/vector-db-benchmark on glove-25-angular (1.18M vectors, 25 dimensions): HNSW with M=16 and EF_CONSTRUCTION=256, 100 clients uploading in batches of 64, then queries at ef 64, 128, 256 and 512.
| KiviDB 1.1.0 | Dragonfly 2.0.2 | Redis 8.10 (query engine) | |
|---|---|---|---|
| Queries/s at ef 64 (recall@10) | 59.3k (0.943) | 41.3k (0.912) | 31.8k (0.912) |
| Queries/s at ef 128 | 50.7k (0.961) | 40.3k (0.937) | 28.9k (0.937) |
| Queries/s at ef 256 | 31.5k (0.989) | 36.2k (0.979) | 21.1k (0.979) |
| Queries/s at ef 512 | 18.7k (0.998) | 29.8k (0.995) | 13.7k (0.995) |
| Ingest and index build | 31 s | 13 s | 38 s |
| Memory after ingest | 1.66 GB | 1.13 GB | 1.07 GB |
Load rising to saturation
A second setup, on Azure, in the manner of a latency/throughput/saturation test: rather
than one fixed load, clients are added every 30 seconds, 40 to 1,600 per database, until
each server can take no more. Each client sends 10 pipelined SET+GET pairs over 10
million keys, then sleeps 10 ms. Every single server ran on its own 8 vCPU arm64 VM
(D8ps_v5); the Redis Cluster had four 2 vCPU VMs, 8 vCPUs in all. KiviDB 1.1.2, October
2026.
The whole run, 20 minutes at 60× speed. Click for the full-resolution video.
| Peak throughput | p50 / p99 at 1,600 clients | Errors | |
|---|---|---|---|
| KiviDB 1.1.2 | 2.08M req/s | 4.3 / 13.9 ms | 0 |
| Dragonfly 2.0.2 | 1.56M req/s | 10.1 / 33.9 ms | 0 |
| Redis 8.10.2 Cluster (4 × 2 vCPU) | 0.97M req/s | 26.8 / 44.9 ms | 0 |
| Redis 8.10.2 | 0.49M req/s | 55.2 / 72.1 ms | 0 |
Latency is per pipelined batch. Without pipelining, KiviDB measured about 20% below Dragonfly on these machines (about 8% below on the bare-metal run above). The harness, the run's raw data and its video are in kivi-benchmark/ramp-saturation; the run's dashboard is a Grafana snapshot.
- Methodology and scripts: kivi-benchmark
- The most recent automated run: benchmarks/LATEST.md
Results depend on the environment. Treat published figures as one controlled capture, not a guarantee, and measure on your own hardware and workload.
Vector search (Redis Stack–style FT.*)
KiviDB implements Redis Stack–compatible search and vector commands, so existing clients and tutorials largely work unchanged. Use them for full-text (BM25), tags / numerics, and vector ANN (FLAT or HNSW) on hash fields.
Quick start
- Create an index on keys with a prefix, declaring at least one
VECTORfield (HNSW or FLAT) and optionalTEXT/TAG/NUMERICfields:
redis-cli -p 6380 FT.CREATE idx ON HASH PREFIX 1 doc: SCHEMA \
vec VECTOR HNSW 10 TYPE FLOAT32 DIM 128 DISTANCE_METRIC COSINE M 16 EF_CONSTRUCTION 128
-
Store vectors as raw FLOAT32 little-endian bytes in a hash field (
DIM × 4bytes), the same convention as Redis Stack andredis-py/numpyblobs. Use your client's binary-safeHSET(the integration tests undertests/e2e/have examples). -
Query with KNN (Dialect 2), passing the query vector as a named binary parameter:
redis-cli -p 6380 FT.SEARCH idx '*=>[KNN 10 @vec $q]' PARAMS 2 q <blob> DIALECT 2
The full command surface, filters, hybrid search and edge cases are in COMMANDS.md (search for FT.CREATE, FT.SEARCH, FT.HYBRID, and so on).
Persistence and restarts
- Native snapshots (
dump.kdb) store the keys, the index schemas, and, when youSAVE/BGSAVEwith indexes populated, the HNSW graph of each vector field, so search quality after a restart matches the graph you had before shutdown. - While search indexes are being rebuilt at startup, most commands return
LOADINGuntil the rebuild finishes;PING,INFOand a few other commands still work. - After a large ingest, run
SAVE(or scheduleBGSAVE) so the next start reloads the graph from disk instead of rebuilding it from the hashes.
Builds
KiviDB comes in four variants, chosen by Cargo features at build time:
| Variant | Cargo features | Adds |
|---|---|---|
default | none | the core server, without Lua or TLS |
lua | lua | Lua scripting (EVAL, EVALSHA, SCRIPT, FUNCTION, FCALL, …) |
tls | tls | TLS listener, and TLS between cluster nodes and replicas |
full | lua,tls | both |
In a build without Lua, the scripting commands return an error. A build without TLS refuses
to start if --tls-port is given, rather than serving plaintext.
Building from source
Requires a stable Rust toolchain (rust-toolchain.toml selects
stable with rustfmt and clippy). The crate uses the 2024 edition; the oldest
toolchain it is checked against is Rust 1.89, the version the Dockerfile
builds with.
git clone https://github.com/kividbio/kividb.git
cd kividb
cargo build --release # default variant
cargo build --release --features lua # with Lua scripting
cargo build --release --features tls # with TLS
cargo build --release --features lua,tls # full
./target/release/kividb
On Linux the server uses io_uring when the kernel allows it and falls back to Tokio
otherwise (--io-model auto, the default).
To build the Docker image yourself, docker build -t kividb . builds the default variant;
docker build --build-arg KIVIDB_FEATURES=lua,tls -t kividb:full . builds another one.
Running KiviDB
./target/release/kividb # listens on 0.0.0.0:6380
redis-cli -p 6380 PING
Any Redis client works; point it at port 6380.
Protected mode
Protected mode is on by default, as in Redis. While it is on, no bind address has been
set (--bind or bind in the config file) and the default user has no password, only
clients on the same machine (loopback) may connect. Any other client
receives a -DENIED error that explains the options, and is disconnected.
To accept clients from other machines, do one of these:
- set a password:
--requirepass <password>, orACL SETUSER default ><password>; - set a bind address:
--bind <address>; - turn protected mode off:
--protected-mode no,protected-mode noin the config file, orCONFIG SET protected-mode nofrom a local client.
If you turn it off or bind to a public address, make sure the server cannot be reached from the internet without a password.
Linux packages
The release page has .deb and .rpm packages for amd64 and arm64. They
install the binary, a systemd unit, a kividb system user, and a default
/etc/kividb/kividb.conf that listens on loopback only. Installing enables and
starts the unit, and an upgrade restarts it:
sudo apt install ./kividb_amd64.deb # or: sudo rpm -i kividb.x86_64.rpm
redis-cli -p 6380 PING
Data (the snapshot, the AOF, nodes.conf) lives in /var/lib/kividb, and logs
go to the journal: journalctl -u kividb. To accept clients from other
machines, set a password and change bind in /etc/kividb/kividb.conf.
Docker
Images are published to Docker Hub and the GitHub Container Registry, with the same tags in both:
docker pull kividb/kividb:latest
# or
docker pull ghcr.io/kividbio/kividb:latest
latest, 1.2 and version tags such as v1.2.0 are the default variant; v1.2.0-lua,
v1.2.0-tls and v1.2.0-full are the others. Images are built for amd64 and arm64.
docker run -p 6380:6380 kividb/kividb
A container is reached through its network, never from loopback, so the image's default
command is --protected-mode no. Arguments you pass replace that default, which turns
protected mode back on. When you pass your own flags, set a password (recommended) or add
--protected-mode no yourself:
docker run -p 6380:6380 ghcr.io/kividbio/kividb \
--requirepass "change-me" \
--databases 8 \
--loglevel debug
With AOF persistence (mount a volume so data survives restarts; the server runs as UID
1000 in /home/kividb):
docker run -p 6380:6380 \
-v $(pwd)/data:/home/kividb \
ghcr.io/kividbio/kividb --aof --requirepass "change-me"
With --aof, every write is appended to appendonly.aof and the file is replayed on
startup, so a crash loses at most about the last second of writes (the fsync interval)
rather than everything since the last snapshot. When an AOF is present it is the source of
truth and the snapshot is not loaded; see docs/PERSISTENCE.md for why.
The image is distroless: it has no shell and no redis-cli. Connect from another container
instead, for example docker run --rm -it --network container:<name> redis redis-cli -p 6380.
io_uring in containers: Docker's default seccomp profile blocks io_uring on recent
versions, and KiviDB then falls back to Tokio. To allow it on a Linux host, run with
--security-opt seccomp=unconfined (understand what that permits before using it in
production).
Release binaries
Release binaries for Linux (x86_64, aarch64) and macOS (Apple silicon, Intel) are published
on GitHub Releases. The latest/download
links below always resolve to the newest release; replace latest/download with
download/v1.2.0 to pin a version. On macOS, Homebrew installs the default variant:
brew install kividbio/tap/kividb.
# Linux x86_64
curl -LO https://github.com/kividbio/kividb/releases/latest/download/kividb-linux-x86_64.tar.gz
tar xzf kividb-linux-x86_64.tar.gz
./kividb
# Linux aarch64 (an ARMv8.1 CPU or newer: Graviton2 and later, Ampere; not a Raspberry Pi 4)
curl -LO https://github.com/kividbio/kividb/releases/latest/download/kividb-linux-aarch64.tar.gz
# macOS, Apple silicon / Intel
curl -LO https://github.com/kividbio/kividb/releases/latest/download/kividb-darwin-aarch64.tar.gz
curl -LO https://github.com/kividbio/kividb/releases/latest/download/kividb-darwin-x86_64.tar.gz
Each variant other than the default has its name in the file: kividb-lua-linux-x86_64.tar.gz,
kividb-tls-…, kividb-full-…. The default variant is also packaged for Linux as
kividb_amd64.deb / kividb_arm64.deb and kividb.x86_64.rpm / kividb.aarch64.rpm,
built with nfpm from
packaging/nfpm.yaml. A SHA256SUMS.txt file lists the checksum
of every file in a release.
curl -LO https://github.com/kividbio/kividb/releases/latest/download/kividb_amd64.deb && sudo dpkg -i kividb_amd64.deb
curl -LO https://github.com/kividbio/kividb/releases/latest/download/kividb.x86_64.rpm && sudo rpm -i kividb.x86_64.rpm
From 1.2.0 on, every file in a release and every image carries signed build provenance: a GitHub artifact attestation that says it was built by this repository's release workflow, from the tagged commit. A checksum proves a download arrived whole; the attestation proves who built it. With the GitHub CLI:
gh attestation verify kividb-linux-x86_64.tar.gz --repo kividbio/kividb
gh attestation verify oci://ghcr.io/kividbio/kividb:v1.2.0 --repo kividbio/kividb
Configuration
KiviDB is configured with command-line flags, or with a Redis-style configuration file
(one directive per line, such as port 6380 or appendonly yes). The file is read from
/etc/kividb/kividb.conf if it exists; --configfile <path> names another one. A flag given
on the command line wins over the same setting in the file. Run kividb --help for the full
list.
| Flag | Default | Description |
|---|---|---|
--port | 6380 | Port to listen on; 0 for none (TLS only, with --tls-port) |
--bind | 0.0.0.0 | Address to listen on. Setting it explicitly turns off protected mode |
--protected-mode <yes|no> | yes | See Protected mode |
--threads | 0 (auto) | Worker threads; auto is the number of cores minus 2 (all cores below 4) |
--databases | 16 | Number of databases |
--dir <path> | start directory | Where dump.kdb, appendonly.aof and nodes.conf live |
--aof | off | Append-only file persistence |
--maxmemory <bytes> | 0 (unlimited) | Memory limit |
--maxmemory-policy | noeviction | What happens at the limit: noeviction, or the allkeys-* / volatile-* eviction policies (kividb --help lists them) |
--loglevel | info | debug, verbose, notice (or info), warning, nothing |
--logfile <path> | standard error | Write the log to a file |
--log-format <text|json> | text | Log line format |
--io-model | auto | auto, uring or tokio (io_uring is Linux only) |
--requirepass <password> | none | Password for the default user |
--aclfile <path> | none | ACL file to load users from |
--replicaof <HOST> <PORT> | none | Replicate from a primary |
--replica-announced-port <port> | server port (the TLS port with --tls-replication yes or --port 0) | Port announced to the primary via REPLCONF listening-port |
--replica-priority <n> | 100 | Sentinel promotes the replica of lowest priority first, and never one of 0 |
--replica-announced <yes|no> | yes | Whether Sentinel lists this replica |
--slowlog-log-slower-than <us> | off | Slowlog threshold in microseconds (0 logs every command) |
--slowlog-max-len <n> | 128 | Slowlog entries kept |
--cluster-enabled <yes|no> | no | Cluster mode: a cluster bus on <port> + 10000, topology in nodes.conf, gossip, failure detection and failover |
--cluster-node-timeout <ms> | 15000 | Time without a reply before a peer is suspected to have failed |
--tls-port <port> | 0 (off) | TLS listener (TLS builds only); with --port 0, the only one |
--tls-cert-file, --tls-key-file | none | Server certificate and key (PEM) |
--tls-ca-cert-file | none | CA that client certificates are checked against |
--tls-auth-clients <yes|optional|no> | yes | Whether clients must present a certificate (only with --tls-ca-cert-file) |
--tls-auth-clients-allowed-names <names> | none | Names a client certificate's CN or DNS name must match; *. is one label |
--update-check <yes|no> | yes | The startup update check |
maxclients (default 10000, in the file or with CONFIG SET) counts plaintext and TLS
clients, TLS ones from the start of their handshake. At startup KiviDB raises the soft
open-file limit to maxclients plus what it keeps for itself (32 files, or on io_uring 40 and
8 a worker thread) if the hard limit allows; if not, it lowers maxclients to fit and logs a
warning. Cluster bus links, a replica's link to its master and files written while saving
are not counted in that; leave room for them in a large cluster.
TLS
TLS clients connect on a separate port, --tls-port; plain traffic stays on --port. With
--port 0 there is no plaintext port, and the server is reached over TLS only (it needs a
--tls-port; a cluster node needs --tls-cluster yes as well, and its bus is then
<tls-port> + 10000). A replica of such a master connects with --tls-replication yes.
cargo build --release --features tls
./target/release/kividb --port 6380 --tls-port 6381 --tls-cert-file cert.pem --tls-key-file key.pem
redis-cli --tls -p 6381 --cacert ca.pem # ca.pem: the CA that signed cert.pem
Client certificates (mutual TLS). With --tls-ca-cert-file ca.pem, clients must present a
certificate signed by that CA; others are refused during the handshake.
--tls-auth-clients optional accepts clients without a certificate but still refuses an
invalid one, and --tls-auth-clients no does not ask for one. With redis-cli:
redis-cli --tls -p 6381 --cacert ca.pem --cert client.pem --key client.key.
Pinning client certificates by name. --tls-auth-clients-allowed-names "*.db1.example admin.example" (spaces or commas between names) accepts a client certificate only if its subject
CN or one of its DNS names matches one of the names; others signed by the same CA fail the
handshake, and the server logs the names they carried. * stands for exactly one label:
*.db1.example takes node-0.db1.example, not a.b.db1.example or db1.example. Case does
not matter. It applies to clients, replicas and, with tls-cluster, nodes on the cluster bus;
empty (the default) is off. KiviDB's own setting: Redis has none.
Changed without a restart. CONFIG SET of tls-cert-file, tls-key-file,
tls-ca-cert-file, tls-auth-clients, tls-client-cert-file and tls-client-key-file loads the
files again for every handshake from then on. CONFIG SET tls-port <port> opens the TLS port
(also on a server that started without TLS: CONFIG SET tls-cert-file cert.pem tls-key-file key.pem tls-port 6381), moves it, or closes it with 0; connections already open stay open.
CONFIG SET tls-replication yes makes a replica's next connection to its master TLS. What cannot
be loaded or listened on is refused, and nothing changes. tls-cluster needs a restart, and so
does tls-port on a node with tls-cluster yes.
Clients must use TLS on the TLS port. A plain connection to it (for example redis-cli -p 6381
without --tls) fails the handshake, and the server logs [TLS] handshake failed. For
memtier_benchmark, add --tls (and --tls-skip-verify for a self-signed certificate).
Logs and errors
The log goes to standard error, or to --logfile. docs/LOGGING.md
describes the log; docs/ERRORS.md explains the warnings, errors and error
replies, and what to do about each.
Startup update check
When it starts, a release build of KiviDB makes one HTTPS request to
https://github.com/kividbio/kividb/releases/latest, the same page you would open to find
the newest release. GitHub answers with a redirect to that release's tag; if it is newer
than the running build, KiviDB prints a short notice with the link before the startup
banner. Nothing is sent but the request itself, with a User-Agent of kividb/<version>:
no host name, configuration, keys, data or identifier. GitHub sees the request's source IP
address, as any web server would.
Startup waits at most 1.5 seconds for the reply; a failure is logged at debug level only and never affects clients. Only a version-shaped tag is accepted from the reply, and nothing else from it is printed.
Any one of these turns it off:
--update-check noon the command line;update-check noin the configuration file;KIVIDB_NO_UPDATE_CHECK=1in the environment.
It is also never made by a debug build or when the CI environment variable is set.
--update-check-url points it at another https:// address, such as a mirror inside a
closed network. docs/UPDATE_CHECK.md has the details.
Contributing
Contributions are welcome. See CONTRIBUTING.md for how to build, test and submit changes. Contributions are accepted under the Contributor License Agreement, which you sign on your first pull request.
Questions, ideas, or want to talk to the maintainers? Join us on Discord, or open a discussion.
Please follow the Code of Conduct. The Changelog lists what changed in each release.
Security
Please do not report security vulnerabilities in public issues. See SECURITY.md for how to report one privately.
License
Copyright (c) 2026 KIVIDB PRIVATE LIMITED.
KiviDB is open source software, licensed under the GNU Affero General Public License, version 3 (AGPL-3.0-only), an OSI-approved license. You may use, modify and redistribute it under its terms. See NOTICE.
Using KiviDB does not put your application under the AGPL. An application that talks to KiviDB over the network, through any Redis client, is a separate program: you can run an unmodified KiviDB as your database, in any product, open or closed, commercial or not, with no obligation on your application's code. The AGPL asks for one thing beyond the GPL: if you modify KiviDB itself and let others use your modified version over a network (for example, as a hosted service), you must offer them the source code of your modified KiviDB.
Commercial license. KIVIDB PRIVATE LIMITED owns the copyright in KiviDB and also offers it under a commercial license, for organizations that cannot use AGPL software or that want to modify or embed KiviDB without publishing their changes. Write to [email protected].
Our commitment. Every version of KiviDB we release under the AGPLv3 stays available under the AGPLv3. The Contributor License Agreement lets us offer the commercial license alongside it; it is not a way to take the open source version away.
FAQ
- Can I use KiviDB as the database of my closed-source or commercial application? Yes. Your application connects to KiviDB over the network; it is not a derivative of KiviDB, and the AGPL places no obligation on it.
- Can I run KiviDB as a service for my own users or customers? Yes. If you run it unmodified, you have nothing to publish. If you modify KiviDB and offer that modified version over a network, you must offer its source to the users of that service.
- Do client libraries or my configuration count as modifications? No. Redis clients, configuration files, and scripts and functions you send to KiviDB are not part of KiviDB.
- My organization does not allow AGPL software. The commercial license is for that case: [email protected].
Trademarks
Redis® is a registered trademark of Redis Ltd. Any rights therein are reserved to Redis Ltd. Any use by KiviDB is for referential purposes only and does not indicate any sponsorship, endorsement or affiliation between Redis and KiviDB. KiviDB is not affiliated with Redis Ltd. Other names mentioned are trademarks of their respective owners.