Appearance
Architecture
This page tells how kinedb works today, and where it is going. It is written for the people and the agents who use kinedb, not for the people who change it.
text
application ── SQL ──► kinedb ◄── SQL ── application
(Rust library, one engine (HTTP /sql, WebSocket /ws,
in-process) JS and Python clients)
│
┌──────────────────┼───────────────────┐
embedded one server a cluster
Db::open(path) kinedb --port kinedb --calvin --join ...
shards ─ Raft ─ replicasToday
Storage: a tree of content-addressed blocks
kinedb keeps every table and collection in a prolly tree. A prolly tree is a search tree whose node boundaries come from the content, so two trees with the same data have the same shape and the same root hash. Each block is stored under the hash of its bytes, so two equal blocks are stored once.
A commit writes new blocks and a new root. The old roots stay readable. This is why a branch is cheap: CREATE BRANCH records one more root, and USE BRANCH moves the session to it. Old versions stay on disk until garbage collection removes them. Garbage collection is off by default; --gc-retention turns it on and sets how much history to keep.
The blocks live in memory, on local disk, or in an S3 bucket (--s3).
Durability in a cluster
A write is durable when the cluster acknowledges it. The leader of a shard writes the entry to disk before the entry counts toward the quorum, and every follower does the same before it answers. A node that restarts applies its committed entries again, so an acknowledged write survives a crash.
Transactions and the order of writes
BEGIN, COMMIT and ROLLBACK group statements. A COMMIT can carry an idempotency token, and GET TRANSACTION STATUS tells a client that lost its connection whether the commit happened. See the SQL reference.
In a cluster (--calvin), a sequencer collects the writes into small batches. Raft gives the batches one order, and every replica applies the same batches in the same order. So the replicas of a shard reach the same state, and they need no locks to agree. This design comes from the Calvin paper on deterministic databases.
The cluster
- Membership. The nodes find each other with SWIM, a gossip protocol that also detects a node that stops answering.
- Shards. The cluster splits each table into shards by key range. It splits a shard again when the shard grows past a size threshold.
- Replicas. Each shard has a Raft group of replicas on different nodes. The replication factor is 3 by default.
- Peer security. Nodes must prove to each other that they know the cluster secret (
KINEDB_CLUSTER_SECRET). This check is on by default. See Run kinedb.
The data model
- Tables have typed columns and a primary key.
- Document collections hold JSON documents. Each document has an
_id. - Key-value collections hold one value per key.
- Files go into a table with
INSERT ... FILEand come out withSELECT FILE. - Indexes speed up a
WHERE.DESCRIBE SELECT ...shows which plan a query uses.
Queries and live queries
kinedb speaks its own SQL dialect: tables and documents in one language, with WHERE, ORDER BY, LIMIT, aggregates, GROUP BY and joins.
WATCH <table> streams the changes of a table to a client over the WebSocket, until UNWATCH.
Logic in the server
CREATE FUNCTION ... LANGUAGE kd stores a function in kd, the scripting language of kinedb, and CALL runs it. CREATE TICKER ... EVERY <interval> CALL <function> runs a function on a schedule.
Access control
A client logs in with a user name and a password and gets a token. The SQL has users, roles, GRANT and REVOKE, and a grant can carry a row filter (WHERE). The SQL reference tells which of these statements run today.
The protocol and the clients
One port (4820 by default) carries everything:
POST /sqltakes SQL and answers JSON./wsis a WebSocket with a binary protocol. A result tells the column types once, not once per cell. Live queries use this path.POST /logingives a token.GET /healthanswers without a login./ui/is the web console, and/ui/docs/is this documentation.
Put a TLS proxy in front of kinedb when the traffic crosses a network that you do not trust.
The JavaScript client and the Python client speak this protocol.
Where it is going
- Sync between an embedded copy and a cluster. The design: each client gets a change feed with a cursor, catches up after it was offline, and receives only the rows it may read. Conflicts fall back to last-writer-wins or a merge function. Live subscriptions and partial fetch are part of it.
- The browser. The engine compiles to WebAssembly with in-memory storage today. Next: storage in IndexedDB, and an npm package with the engine inside (
@kinedb/embedded; the name is reserved). - Joins and transactions across shards for every query plan and every statement shape.
- Branch merge. Merge one branch into another.
- Placement. Place replicas by data center and rack, and keep hot and cold data on different machines.
- More SQL. Computed columns, CHECK constraints, a vector index, columnar storage for analytics, and the Postgres and MySQL wire protocols.
- More clients. An embedded and a direct client in each language.