Fast, durable key-value store for control plane state.
Orbita is a strongly consistent store for locks, leases, catalogs, epochs, and control-plane state. It aims to be the durable shared memory a platform coordinates on: Redis-like latency on the fast path, datasets that can outgrow memory, and operational simplicity that doesn't require a team to maintain it.
The amount of coordination data is usually small. Its consequences are not. Orbita is built for the state that tells a larger system who owns what, what is current, and what may happen next.
Website · Quickstart · Requirements · Roadmap
I have typically leaned on Redis as the source of truth for control planes. It acts as shared memory, and its collection of data structures makes it easy to model rate limits, quotas, epochs, mutexes, leader election, and more. I used this strategy at Tower, and it worked, but a few problems kept coming back:
- Durability was always a question. You can put Redis into a durable mode, but crash recovery is expensive, and coordination state is exactly the data you cannot afford to lose.
- Memory residency. You cannot outgrow memory. When the dataset grows, the only answer is more memory.
- Tooling. We had to build all of our own tooling for exploring the state of our control plane data, which became expensive to maintain.
- Hosting. ElastiCache is a decent hosted option, but I wanted something more full service, with cloud-native authentication and real multitenancy.
The alternatives each came with their own tax. At Snowflake we used FoundationDB and got amazing results from it, but we had a large team maintaining it and contributing to it. Tower's control plane store originally ran on etcd, and operating that was likewise complicated. ZooKeeper, which I ran at Cloudability, was amazingly fragile. DynamoDB fit the shape of the problem, but its serverless pricing got expensive for this workload.
What I always wanted was a cloud-native service for control-plane state that is not shockingly expensive to run as a service, has Redis-like performance, can handle datasets larger than memory, is operationally simple, and comes with good tooling over standard interfaces. That is why I built Orbita. It will be the store behind a service I eventually host.
Orbita is under active development and is not production-ready. The wire protocol, storage format, and operating model may still change before the first release.
Single-node and multi-node clusters work end to end today. The current system has a Raft-backed control plane, replicated writes, lease-based replica reads, owner failover, object-backed storage and hydration, keyspace credentials and quotas, rolling-upgrade gates, and an Admin service on every node.
The notable holes are just as important:
- Partition split and merge return
Unimplemented. Every keyspace currently remains one range partition, so horizontal partition growth is architecture, not demonstrated behavior yet. - Native TLS, peer mTLS, prefix authorization, and audit logging are planned for v0.4. Do not expose the peer port to an untrusted network.
- Watch streams, multi-key transactions, backup and restore, and the offline format reader are not implemented.
- The project has not published production-scale latency, throughput, or correctness results. The simulator is the development method today; broader evidence is the next phase of the roadmap.
The quickstart keeps the detailed list of what works and what does not.
From a checkout:
cargo install --path crates/orbita-cli
orbita devThat starts a complete development cluster on 127.0.0.1:7100: one process
running a one-voter control plane and a worker, with a default keyspace and
state under .orbita/dev. It deliberately has no object store or replication,
so it is for learning and local development rather than durable deployment.
Use one-shot commands from another terminal:
orbita set default greeting hello
orbita get default greeting
orbita list default
orbita cluster describeOr keep one connection open in the interactive shell:
$ orbita repl
orbita interactive session against http://127.0.0.1:7100. Type :help for session commands, :quit to leave.
orbita> :use default
keyspace set to default
orbita:default> set greeting "hello world"
ok, version 1
orbita:default> get greeting
hello world
version 1
orbita:default> list
greeting
orbita:default> :quitThe prompt shows the current keyspace. Use :use <keyspace> to select one,
:format json to change output, :help for session commands, and :quit or
Ctrl-D to leave. Ctrl-C cancels the current input line.
The REPL uses the same parser and renderer as one-shot commands. get default greeting at the prompt and orbita get default greeting in a shell do the
same thing. It provides line editing and history for the current session;
persistent history and command completion are not implemented yet.
For scripts, keep using one-shot commands and --output json. get prints the
value first so it pipes, exits 2 when a key is absent, and exits 3 when a
conditional write does not apply.
Orbita stays small on purpose:
GET,SET,DELETE, and ordered prefixLIST, with bounded pages and opaque cursors.- Compare-and-swap by version and
IF NOT PRESENT, which are the primitives behind locks, leader election, fencing, and atomic catalog pointers. - Absolute TTL deadlines. Expired keys disappear from reads at the deadline, independent of replication delay or failover.
- Keyspaces as tenant boundaries, with scoped credentials, read and write permissions, storage quotas, rate limits, default TTLs, and value limits.
- Linearizable reads from replicas while their owner-issued lease and per-key invalidation state remain valid. A replica forwards when it cannot prove a local answer is current.
The current hard value limit is 256 KiB. A LIST page is individually
consistent, but a scan across pages is not a point-in-time snapshot.
Orbita separates the fast coordination path from bulk durability:
- The partition owner serializes a write and replicates its WAL entry. A fully placed partition acknowledges after the owner and one of two replicas have made the entry durable.
- Workers flush immutable partition segments and atomically publish manifests to S3-compatible object storage outside the normal acknowledgement path.
- A new or replaced worker hydrates its index from the bucket, then catches up from the WAL instead of copying the full dataset from a busy peer.
- Range partitions are designed to distribute indexes and hot data across workers while the small Raft voter group carries metadata rather than every read and write.
The WAL keeps writes fast. Object storage makes workers replaceable. Range partitions are the path to horizontal capacity. The first two are implemented; automatic split execution is the remaining step that makes the third true in a running cluster.
The storage engine uses Orbita's documented
partition-v1 format over a pluggable object
store. S3-compatible storage covers AWS S3, MinIO, and R2. A filesystem backend
keeps local development self-contained.
Orbita is built so a failure can become evidence instead of a story about what probably happened. Network, disk, clock, and object-store access sit behind deterministic runtime seams. A failing simulation emits its seed, and that seed replays the same schedule.
moon run orbita-sim:sim
ORBITA_SIM_SEED=<seed> moon run orbita-sim:simThe simulator injects dropped, duplicated, delayed, and reordered messages;
torn writes and lying fsync; crashes and restarts; and object-store failures.
It checks linearizability and convergence across failover, leases, WAL
replication, flush, hydration, and retention scenarios.
The reasoning is public too:
- Requirements fix the scope and guarantees.
- Architecture decisions record the tradeoffs and are immutable once accepted.
- Work briefs divide ownership across the workspace.
partition-v1specifies the bytes at rest.
This is a method and a commitment, not a completed proof. Continuous simulation results, real-cluster measurements, and a public correctness report are v0.2 work.
The Compose stack runs three Raft voters, three workers, and MinIO:
docker compose up --build -d
docker compose --profile smoke run --rm smokeThe Helm chart runs the same shape on Kubernetes:
helm install orbita deploy/helm/orbita --namespace orbita --create-namespace
kubectl --namespace orbita port-forward svc/orbita 7100:7100
orbita cluster readyEvery node uses two listeners. Port 7100 serves the public client and Admin gRPC APIs. Port 7101 carries unauthenticated private peer framing for Raft, WAL replication, and forwarding. Keep 7101 on a private network.
Set ORBITA_REQUIRE_AUTH=true and ORBITA_ROOT_CREDENTIAL to enforce
credentials at the client boundary. Authentication is off by default, and the
current listeners are plaintext h2c.
The quickstart covers laptop, Compose, and Kubernetes paths. Testing on EKS adds a disposable real-AWS path with S3 and IRSA.
One orbita executable runs every node role and every client command.
orbita cluster describeshows node health, ownership, replica progress, storage, index memory, and quota configuration. Add--output jsonfor a stable scripting interface.orbita cluster readychecks registration, recovery, partition catch-up, Raft progress, version compatibility, and auth-policy agreement.orbita cluster finalize-upgradecloses the rollback window after every live node can speak the next cluster version.ORBITA_OTLP_ENDPOINTenables OTLP/gRPC export for traces and metrics. Structured logs remain on stderr.
Upgrades documents the n-1 compatibility window, readiness, draining, finalization, and rollback boundary.
| Document | What it covers |
|---|---|
| Quickstart | Three ways to run Orbita, current gaps, configuration, and incident commands |
| Requirements | Product scope, guarantees, scale envelope, and acceptance criteria |
| Roadmap | What ships in each pre-1.0 release |
| Architecture decisions | Decisions, corrections, and rejected alternatives |
| Storage format | The open partition format and its invariants |
| Build | Toolchain, Moon tasks, tests, and simulation |
| Upgrades | Rolling upgrades and the cluster-version contract |
| Releasing | Versioning, artifacts, and the tag-driven release pipeline |
Start with CONTRIBUTING.md. The full local gate mirrors CI:
moon run :fmt :lint :test --query "language=rust"Behavior changes that touch replication, ownership, failover, splits, or reads should include a simulation seed or scenario that fails without the change. Participation is governed by the Code of Conduct.
Report security issues through SECURITY.md, not a public issue.
Orbita is licensed under the Apache License 2.0.