Crestway AI · infrastructure that runs itself

The cache that never evicts. It runs on NVMe SSDs, not RAM.

No eviction under memory pressure, so no miss storms hammering your backend — Flint holds your whole working set rather than the part that happens to fit. No warm-up either: a restart comes back with its data, not with an empty cache and a cold-start stampede at your origin. It speaks the Redis protocol, scales behind one endpoint, and costs storage economics instead of memory economics. It is multi-threaded — commands run concurrently across every core, not queued behind one — and multi-tenant by construction, with each tenant in its own isolated keyspace behind its own token and quota.

Rather not fill in a form? info@crestwayai.com reaches the same inbox.

~1/10the per-GB price of ElastiCache Serverless
100 TB+per cluster by design — add pairs to grow
0.39 msread p50 beyond RAM, end to end
0.94 msread p99 beyond RAM, end to end
757 msmeasured failover, kill → writable (committed ≤ 10 s)

Built to be run by an agent

The service was built from day one to be operated by an AI agent, not a pager rotation — the operational knowledge is the product's second half.

Every drill, incident, and debugging session on this fleet is captured as structured operational knowledge the moment it happens — not as tribal memory, but as material an operations agent can act on. The agent that runs the managed fleet meters usage, heals failed replicas, rotates drained credentials, and plans capacity against that accumulated knowledge; every action it takes is allowlisted, journaled, and auditable, it fails closed, and it pages a human the moment it cannot verify its own fix. Most managed services put people behind the dashboard and call it automation. Flint was designed the other way around: the system explains itself in a form an agent can execute, which is also why the failure claims on this page all come with runnable drills — the agent and you are reading the same evidence.

Latency, measured end to end — proxy and storage engine included

Our claim isn't "faster than RAM." It's fewer misses beats faster hits.
1

What a miss actually costs

A RAM cache that cannot hold your working set does not cost you microseconds — it costs you the evictions. Every evicted key is a request that falls through to your origin, and on a hot key it is not one request but every concurrent one at once: the thundering herd that turns a cache miss into an incident. Flint holds the whole set, so those misses stop happening.

2

Why the latency objection doesn't survive the arithmetic

A cache call is not a memory access — it is a network call, and in practice two: client → proxy, then proxy → cache node. Each hop costs hundreds of microseconds (a cross-AZ round trip is ~500 µs–1 ms), and a RAM cache behind a proxy crosses exactly the same wires — both designs pay that part identically. The only difference is the last step inside the node, a RAM lookup versus an NVMe read. Measured serially against the current build, Flint's own path — slot routing, the tenant gate, the encrypted internal hop, the node and the storage engine together — costs 37 µs at p50, against a 95 µs network round trip on the same fleet. That is a marginal figure: it is what a GET costs beyond a PING on the same connection, so the one-time connection handshake and the proxy's own parsing sit outside it — as they do for any cache reached through a proxy. That is the whole of what Flint trades; everything else on the path is identical. It is also the one-at-a-time floor: the p50s in the table below are measured at 32 connections, where the server‑side share grows several times over and the network settles at roughly a third of each read. What share of your latency it represents depends on your topology, so use your own hop times: the more network sits between your client and your cache, the smaller the medium's share of what anyone measures. The other side of that ledger does not depend on topology at all — a miss costs a full round trip to your origin, and on a hot key, all of them at once.

Reproduce it yourself: the harness (industry-standard memtier_benchmark scenarios) ships in the open repo as tools/memtier_bench.sh.

August 17, 2026 — current build, measured off-box. Client on a separate machine from the server, so every number includes a real network hop: two i4i.2xlarge in one AZ, 20 M × 1 KB incompressible values (20 GB), memtier_benchmark at 32 connections, the full stack under test (proxy, storage engine, control plane) built from the committed source. The client→server wire was measured separately at 93 µs p50, so roughly a third of each read below is the network itself.

scenario — off-box, end to end, 20 GBthroughputp50p99p99.9
GETs, hot slice90,775/s0.34 ms0.63 ms0.95 ms
Mixed 1:10 write:read90,730/s0.34 ms0.62 ms0.91 ms
GETs, pipelined ×16 (512 in flight)280,411/s1.74 ms3.57 ms5.86 ms
SETs (persistent, WAL before ack)69,340/s0.41 ms3.47 ms6.62 ms
SETs, pipelined ×16 (512 in flight)151,056/s2.10 ms42.75 ms52.48 ms

Every row is the worse of two independent runs, not the better one and not an average. This dataset fits in the box's 61 GB of RAM, so it measures the request path with the medium mostly out of the way — the table below runs the same build against a dataset twice the size of memory, and the difference between them is the honest price of not holding your data in RAM. Pipelined throughput here is roughly 2.4× what the same scenario measured before the August proxy rewrite.

The pipelined row is measured differently from the rest. It runs 16 requests deep on each of the 32 connections — 512 requests in flight, not 32 — so its p50 is one request's wait in a queue sixteen deep, not a slower round trip. That row trades sixteen times the queue depth for the throughput jump beside it. Most clients do not pipeline by default — redis-benchmark and memtier_benchmark both ship with it off — so the hot-slice row is the one an ordinary application sees.

August 18, 2026 — the beyond-RAM case, same build, same fleet shape. The dataset that does not fit: 100 M × 1 KB incompressible keys, measuring 121 GB on NVMe against 61 GB of RAM — about twice what memory can hold, so a real share of every read has to reach the disk. Same client machine, same 32 connections, same 4 proxy workers, and differing from the table above in dataset size and almost nothing else. The RTT probe did not build on this fleet, so these rows carry no network/server split of their own.

scenario — off-box, end to end, 121 GB on 61 GB RAMthroughputp50p99p99.9
GETs, hot slice71,925/s0.40 ms0.98 ms1.82 ms
Mixed 1:10 write:read72,160/s0.42 ms0.90 ms1.72 ms
GETs, pipelined ×16 (512 in flight)188,752/s2.70 ms5.57 ms8.64 ms
SETs (persistent, WAL before ack)73,625/s0.42 ms0.78 ms1.20 ms
SETs, pipelined ×16 (512 in flight)227,734/s2.22 ms3.34 ms4.45 ms

What leaving RAM actually costs: about 56 µs at GET p50, and 16 µs at SET. Reads pay because past memory a share of them must reach NVMe. Writes barely notice — a write goes to the write-ahead log and the memtable and never reads the data set, so its size hardly reaches it. That asymmetry is the whole design in one row: the medium is only in the read path. A result that slowed writes and reads equally would have meant something else was wrong.

Worse of two runs, as above. Every write went through the full persistent path, WAL before the ack, fsync on the bounded cadence. Reads are hit-dominated — the corpus is loaded with full key coverage, so these are not flattered by cheap misses.

Bulk loading

Every row above is memtier_benchmark, which keeps a sliding window continuously full. A bulk loader does not: it writes a batch and then blocks for the replies before composing the next one. Measured with a batch-and-wait client through the same edge, 1 KB values:

bulk load — batch-and-wait client, not memtierconnectionsbatchwrites/s
through the proxy edge11648,490
through the proxy edge16470,759
through the proxy edge816117,584
through the proxy edge864156,524

A separate table on purpose: it is a different load generator, and two tools in one table with only one of them named is how a number gets quoted against a row it was never comparable to. The same measurement on the same path read 690 writes/s per connection before we fixed it — the node was not setting TCP_NODELAY on accepted sockets, so a reply written while the loader's own send was still in flight waited out the peer's delayed-ACK timer, about 50 ms per round trip. A client that never stops sending never creates that pause, which is why no row above ever showed it.

Scale is a property of the architecture

Capacity is disk × node pairs, not RAM per node — so growth is a purchase order, not a re-architecture.

Flint is slot-sharded behind a stateless proxy. Add a node pair and slots migrate to it live, under a copy-rate throttle, while the endpoint stays exactly where it was. Because the working set lives on NVMe rather than in memory, the capacity of one pair is the capacity of its disks:

node typeNVMe~usable per pairpairs for 100 TB
i4i.4xlarge3.75 TB~3 TB~34
i4i.16xlarge15 TB~11 TB~9
i4i.32xlarge30 TB~23 TB~5

That is arithmetic, not a benchmark: it is what the design permits, and it is stated that way deliberately. There is no configured size ceiling in the product to raise, and no client-side sharding to write — the endpoint is unchanged at every size, and federation adds clusters behind that same endpoint beyond one cluster's range. Our published multi-terabyte validation runs are staged independently of this claim; we will say what we have measured, and this table is what the architecture supports.

For contrast on the ceiling specifically: ElastiCache Serverless documents a maximum of 5,000 GiB per cache, and 32 GiB per hash slot — a single hot slot reaches eviction or out-of-memory errors well before the cache does. Past the cap, growth means sharding across caches in your own client code.

Hot keys are handled in the architecture

The hot-key incident is a design problem, not an on-call problem — so it is solved at the edge, before it reaches a shard.

Heat is measured, not guessed

The proxy keeps a sampled per-key heat sketch across every connection it serves, split by reads and writes. You can ask it what is hot right now, scoped to your own tenant, instead of reconstructing the incident from shard CPU graphs after the fact.

Hot reads absorbed at the edge

A bounded, short-TTL near-cache at the proxy answers hot reads without touching the shard that owns the key. The staleness window is a TTL you choose, and it is opt-in per tenant — so a single key going viral is absorbed by the edge rather than pinning one node's CPU.

Write bursts absorbed too

Write-heavy tenants can opt into an async write queue that takes bursts off the hot path. Every write still lands in the write-ahead log — the queue changes when you wait, not whether the write is durable.

No thundering herd to survive

The classic hot-key failure is an eviction under memory pressure followed by every concurrent request missing at once. Flint does not evict under memory pressure, so that trigger does not exist.

Multi-tenant by construction

Isolation, quotas and every core in the box — defaults, not things you assemble.
1

Commands run on every core

Flint serves each connection on its own thread against a shared store with no global lock, so concurrent commands genuinely run at the same time and a higher-core instance is faster rather than merely larger — no single command thread for an expensive call to stall every client behind it. Scaling up is a machine choice, not a resharding project. It is also why the excluded commands below are excluded: the blocking and whole-keyspace ones would put the bottleneck back.

2

Tenants are isolated by construction, not by convention

Each tenant gets its own isolated keyspace, invisible to every other tenant — and you never type it. Your token maps to your namespace at the proxy, so you write ordinary key names (user:42, session:abc) with nothing to prefix and no namespace argument. Isolation is enforced at the proxy from your token, so a bug in someone else’s prefix logic cannot reach your data. The isolation does not depend on every client getting it right.

3

A noisy neighbour is bounded, not apologised for

Each tenant carries a rate quota (ops/second) and a storage cap, both enforced at the proxy and both visible live. Crossing the storage cap flips writes to -QUOTA while reads keep serving and deletes always work — so the way out is never blocked by the limit itself — and dropping back under clears it automatically, with no human in either direction. Tokens are hashed at rest and rotate without downtime: old and new both authenticate until the old one is dropped.

Persistent by construction

Disk-first, RAM-fast

Every write lands in the on-NVMe write-ahead log before it is acknowledged, fsynced on a bounded half-second cadence — a restart never costs you the cache. Hot keys serve from the managed memory tier at RAM speed; the long tail lives on NVMe at a fraction of the cost.

Capacity is disk, not memory

There is no maxmemory and no LRU: nothing is ever evicted because the box ran low on RAM, so a key you wrote is a key you can read. Sizing stops being a guess about which fraction of your data deserves to stay resident. And if a node does run out of room, it refuses new writes rather than quietly discarding what you already stored — the opposite of what a memory cache does under pressure.

Failovers you can sleep through

Replication runs under an enforced lag bound, promotion is epoch-fenced so split-brain is structurally impossible, and a failed node's data is still there when it returns. A master that ends up with no replica at all — the one state a lag bound cannot measure — stops accepting writes after a bounded grace rather than pile up work nothing is copying.

One endpoint, any scale

Slot-sharded behind a stateless proxy. Your client never sees cluster topology, migrations, or failovers — any Redis or Valkey client, no SDK, no cluster mode. Growth is horizontal: add node pairs and slots migrate to them live, under a copy-rate throttle, while the endpoint stays exactly where it was. There is no configured size ceiling to hit — see how far the architecture goes.

No warm-up, ever

A RAM cache that restarts is an empty cache, and an empty cache is an origin stampede. A Flint node restarts with its working set already on disk and serves it immediately; failovers hand traffic to a replica that has the data; new replicas seed themselves from a checkpoint. Cold start is not an event you plan around.

Secure out of the box

TLS on every client connection and mutual TLS on every internal hop by default. Tokens hashed at rest; credentials and certificates rotate automatically with zero downtime.

Runs itself

The operations agent above is not a bolt-on: metering, replica healing, credential retirement and capacity planning are agent actions with journaled evidence, designed in from the first commit.

Proven, not promised

Every command is conformance-tested against a reference implementation, and every failure claim has a runnable drill — including randomized chaos with a ledger oracle.

Works with the client you already have

$ valkey-cli -h cache.yourco.flint.dev --tls -a $FLINT_TOKEN
> SET session:42 "..."        OK        # in the WAL before the ack
> GET session:42              "..."     # RAM-speed on the hot tier
> LPUSH jobs task-1           (integer) 1
> ZADD leaderboard 100 alice  (integer) 1
> JSON.SET user:42 $ '{"plan":"pro","tags":["a"]}'   OK

Strings, hashes, sets, lists, sorted sets, TTLs, JSON documents, and cursor-based SCAN — the working Redis surface, minus the foot-guns (no cross-slot surprises, no data-losing restarts).

Both wire protocols, negotiated per connection. Clients that open with HELLO 3 — the default in current redis-py and node-redis, credentials passed inside the handshake — get RESP3 and receive their own native types back: HGETALL as a dict, SMEMBERS as a set, ZSCORE as a float. Older clients stay on RESP2 unchanged. Nothing to configure either way, and the whole conformance corpus runs over both.

import redis                          # no options, no shims
r = redis.Redis(host="cache.yourco.flint.dev", password=TOKEN, ssl=True)
r.hgetall("user:42")                  # {'plan': 'pro'}   ← a dict
r.zscore("leaderboard", "alice")      # 100.0             ← a float
r.json().get("user:42", "$.plan")     # ['pro']

Try it against the real thing. The managed service runs today at try.crestwayai.com:7379 — TLS-terminated, per-tenant auth, the same architecture described here, though it tracks tagged releases rather than the tip, so it is not always the exact build a benchmark on this page was measured on. Point any Redis or Valkey client at it and the snippet above is the whole integration. Ask for a tenant and we'll send a namespace and token — we issue them by hand while the service is in early access, so tell us roughly what you want to throw at it.

Operated to numbers

Crestway AI runs the fleet end to end — all you own is an endpoint and an SLO. These are the objectives we operate to, and every one of them has a runnable drill behind it.
objectivecommitmenthow it's held
Availabilitydesigned for 99.99% monthly per-tenant error-minute accounting from the proxy's own metrics
Failover recovery (RTO)under 10 seconds measured 757 ms kill→writable on a 7-host EC2 run over a real network — the slowest honest observation we have, which is why it is the one published (loopback runs read 404–514 ms and do not pay a network RTT). That leaves ~13× margin under the commitment. It is also the DIRECT-to-master path: through the proxy edge a client sees no outage at all, only a slower write (633 ms worst stall, zero client-visible errors)
Loss window on failover (RPO)at most 10 seconds' worth of acknowledged writes enforced at 1 s by default — past the lag cap the master sheds writes rather than let the at-risk set grow, and a master that has lost its replica entirely stops accepting after a bounded grace
Restart persistencezero acknowledged-write loss on restart; host loss bounded at half a second write-ahead log before every ack, fsynced on a 500 ms cadence; a restarted node comes back warm with its data

Read the loss window as a volume, not a stopwatch. What the cap enforces is how much can ever be at risk: once replication falls behind by more than the cap, the master stops accepting new writes rather than let the at-risk set grow. A second bound covers the case the cap cannot see — with no replica left, there is no lag to measure, so a master that finds itself alone keeps serving only for a bounded grace and then sheds. We publish “ten seconds' worth of writes” instead of “nothing older than ten seconds” because the first is what the code actually enforces, and a promise that outruns its mechanism is not a promise.

These are design objectives backed by measured drills — the formal SLA with service credits ships with general availability, once the numbers have months of fleet history behind them. The proofs are runnable today: failover, lease-fenced split-brain, and randomized chaos drills in the open repo. The two that back the loss window are the strictest, because a backpressure path that never fires looks identical to one that works: one drill tightens the lag cap until the master genuinely sheds and checks that nothing shed is ever miscounted as lost, and the other freezes a replica outright to confirm a master left alone stops accepting on schedule and resumes by itself the moment its replica returns.

Command support

Every command below ships with a conformance test validated against a reference Redis-protocol implementation and both Flint engines — if it is listed, it behaves the way your client already expects. Grey chips are supported option forms. One honest exception: stock Redis and Valkey have no JSON type, so the JSON family has no reference in that run — those cases were checked reply-for-reply against the RedisJSON module itself, built from source, and the handful of places we deliberately differ are written down in docs/command-support.md.

Strings

SETSETNXSETEXGETGETDELGETSETMSETMGETAPPENDSTRLENGETRANGESETRANGEINCRDECRINCRBYDECRBYINCRBYFLOATSET NX/XXSET EX/PX/EXAT/PXATSET KEEPTTLSET GET

Keyspace & TTLs

DELUNLINKEXISTSTYPEEXPIREPEXPIREEXPIREATPEXPIREATTTLPTTLEXPIRETIMEPEXPIRETIMEPERSISTSCANSCAN MATCH/COUNT/TYPE

JSON documents

JSON.SETJSON.GETJSON.DELJSON.FORGETJSON.TYPEJSON.NUMINCRBYJSON.ARRAPPENDJSON.ARRLENJSON.SET NX/XX$ and legacy paths

Hashes

HSETHSETNXHGETHMGETHGETALLHDELHLENHEXISTSHINCRBYHSTRLENHSCANHSCAN MATCH/COUNT/NOVALUES

Sets

SADDSREMSISMEMBERSMISMEMBERSMEMBERSSCARDSPOPSRANDMEMBERSSCANSSCAN MATCH/COUNT

Lists

LPUSHRPUSHLPOPRPOPLLENLRANGELINDEXLSETLTRIMLREMLINSERTLPOSLPOS RANK/COUNT/MAXLEN

Sorted sets

ZADDZSCOREZMSCOREZINCRBYZREMZCARDZRANGEZREVRANGEZRANGEBYSCOREZREVRANGEBYSCOREZRANKZREVRANKZCOUNTZPOPMINZPOPMAXZREMRANGEBYSCOREZREMRANGEBYRANKZSCANWITHSCORESLIMITexclusive bounds & ±inf

Connection & server

PINGECHOAUTHHELLODBSIZEFLUSHALLRESP2 & RESP3HELLO AUTHCOMMAND/SELECT (compat)

Excluded by design: cross-slot multi-key commands, MULTI/EXEC/WATCH, pub/sub, streams, blocking commands, KEYS/RANDOMKEY, and EVAL/EVALSHA — these conflict with sharded multi-tenancy or reintroduce the single-threaded bottlenecks Flint exists to avoid. Need one of them? Tell us the workload — patterns with broad demand get first-class commands.

Priced by what you store, not what you provision

About one tenth the per-gigabyte price of ElastiCache Serverless — and the arithmetic is one click away.
servicerate for data storedper GB-month
ElastiCache Serverless$0.084 / GB-hour$61.32 + ECPU charges
Flint Cache$0.00684932 / GB-hour$5.00

Both rates × 730 hours. Those figures divide out to closer to a twelfth; we say a tenth because a headline number should be the one that still holds after AWS changes a price, and rounding a comparison in our own favour is how a claim stops being checkable. ElastiCache Serverless also bills ECPUs on top of the storage rate, so the gap in a real bill is wider again than these rows show — we compare storage to storage because that is the part quoted the same way on both sides. Against node-based ElastiCache the ratio is smaller, roughly half, because you are then buying and managing instances rather than a service. Rates as published August 2026, us-east-1.

Capacity, not memory

You pay for gigabytes held, not for RAM provisioned. A RAM cache prices the most expensive medium in the machine and bills you for the headroom you sized for peak; Flint holds the same working set on NVMe.

Actual bytes, not peak

Usage is metered hourly on what is actually stored, through AWS Marketplace — not on a provisioned high-water mark you chose months ago and have been paying for since.

No sizing exercise

There is no instance class to pick, no memory ceiling to forecast, and no eviction policy to tune against a budget. Store what you store; grow when you grow.

One bill, one endpoint

Capacity, durability, replication and the proxy tier are the service — not line items you assemble. Billing arrives through your existing AWS account.

Request playground access

Tell us what you want to throw at it and we'll send a namespace and token for try.crestwayai.com:7379. Tenants are issued by hand during early access, so this reaches a person, not a queue — usually same day.

We use this to set up your tenant and reply — nothing else, no list, no third-party marketing. Prefer mail? info@crestwayai.com reaches the same person.

Open core

The entire Flint stack — storage engine, server, proxy, control plane, and the tooling that proves it — is source-available under the Elastic License 2.0: free to run yourself, at any scale, for any purpose except reselling it as a service. Crestway operates the managed fleet — the autonomy, metering, and consoles — so you don't have to.

The repository is opengithub.com/Crestway-AI-LLC/flint-cache. Every drill, benchmark harness and conformance case behind the numbers on this page ships in it — the point of publishing the source is that the claims become checkable instead of quotable.

Tagged releases carry Linux x86_64 binaries and a manifest.json with their sha256. Every release from v0.1.0-rc.28 onward is signed with minisign, and the public key is in the repository root — so you can prove the bytes came from us and not merely that they are undamaged.