Ruvio.

Clients

Ruvio has first-party clients for six languages. Every one covers all 287 commands in the compatibility matrix with a typed method, plus the options only Ruvio has (SET ... IFEQ, DELEX, FILLGET, LIMIT, Bloom, JSON.FIND and the rest).

A test in each client reads the matrix and fails when a command has no method. Each client has its own page in the Clients menu.

All numbers on these pages come from short runs on a shared 4-vCPU virtual machine, client and server on the same host, over loopback. They show relative cost and allocation, not release-grade throughput.

The six clients

ClientModelClusterRegistry todayTests (live server)
RustBlocking, std only, no dependenciesYescrates.io ruvio-client latestunit + coverage + live suites
C#Async, one multiplexed connectionYesNuGet Ruvio.Client latest198 client tests; 6 integration packages
Gocontext.Context on every call, one multiplexed connection, standard library onlyYesNot yet (needs a module tag)74 tests, race detector run
JavaBlocking facade and CompletableFuture, one multiplexed connectionYesNot yet (Maven Central)91 tests
PythonSync and asyncio, optional hiredis parserYesNot yet (PyPI)217 tests
Node.jsPromises, TypeScript types, ESM, no dependenciesYesNot yet (npm)63 tests

What they share

The same behaviors, in the idiom of each language:

  • One seed address. The client asks CLUSTER SLOTS, opens one connection per shard and routes by slot. A standalone server answers "cluster mode is disabled" and the client then works as a plain client.
  • MGET, MSET, DEL, UNLINK, EXISTS and TOUCH across slots are split per slot, sent in parallel, and the replies come back in your order. Other cross-slot calls fail before anything is sent.
  • MOVED repairs the slot table and the command is retried once. A command is never replayed after a transport failure.
  • Pipelines, MULTI/EXEC with WATCH, Pub/Sub on its own connection, blocking commands that do not stall the shared connection, and a generic execute for anything else.
  • Binary-safe values, server errors as typed errors, and nil replies as null, None, Optional or a second return value.

Not shared: the Rust client is blocking only, and the Rust and C# clients have no TLS today. No client handles ASK redirects or replica reads. Each page has the full list.

Built for speed and low memory

Users reach Ruvio through a client, so the clients follow the same rule as the server: no work that is not needed. All of them use these ideas, first proved in the C# client:

  • One shared connection. Concurrent callers share a socket and a first-in first-out queue of pending replies. There is no connection pool to size.
  • Write coalescing. Frames that are queued while a write is in flight leave in one write, up to 64 KiB. There is no timer and no batching delay; a lone call is sent at once.
  • Pre-encoded commands. Command names are stored as finished RESP fragments ($3\r\nGET\r\n). Integers are written straight into the output buffer.
  • In-place parsing. Replies are parsed from a reusable read buffer. An integer or +OK allocates nothing; a bulk allocates only the value you get back.

The same helper layer everywhere

Every client adds small tools on top of the raw commands, so the Ruvio-specific commands are easy to use correctly:

HelperBuilt onWhat it gives you
Distributed lockSET NX PX, SET IFEQ, DELEX IFEQAcquire, renew, release. Release never deletes a lock someone else took after yours expired. Scoped forms release for you.
Lease and semaphoreLEASE, SEMAPHORE, RELEASEA fence token, or a limited number of holders, released when the scope ends.
Rate limitLIMITAllowed or not, and how much is left, in one round trip.
Get or createFILLGET, FILLSETCache-aside where only one caller runs the factory; the others wait and read the result. Optional stale-while-revalidate.
IdempotencyIDEMRun an action once per key; repeated calls get the stored result.
Scan iteratorsSCAN, HSCAN, SSCAN, ZSCANLazy loops over the whole keyspace or one collection, across all shards.
Typed JSONJSON.*Read and write your own types with the language's standard JSON library.
Recent list, seen beforeLPUSHCAP, BF.MADD, BF.MEXISTSA list that keeps the last N items, and a "have I seen this" check.

Cluster

Start a three-shard server with shards = 3 and port_mode = "per-shard". Shard i listens on the base port plus i. Give any client one address and it finds the rest. Each page has a cluster example that was run against such a server. Database 0 only; there is no failover, ASK or live resharding in the server, so none of the clients handle them.

Speed, in one table

Concurrent GET/SET on one shared connection, 64 to 128 callers, standalone server, same VM for client and server. Taken from each client's own benchmark; the figures vary about 2x between runs on this machine.

ClientConcurrent GET (ops/s)Compared with
Go (64 goroutines)about 260k to 300k—
Node.js (128 in flight)about 600k to 880kioredis 5: about 105k (same run)
Python asyncio (64 coroutines)about 186k to 239kredis-py 8.1: about 8k (same run)
Java (64 threads)about 140k to 210k—
C# (16 callers)about 54k to 93k—
Rust (blocking, one thread)about 17k to 60k—

Do not rank the languages from this table: the host was shared with the server, the callers differ, and each row has its own run-to-run noise. A serial call is about 30 to 60 microseconds in every client, and that time is mostly the network round trip and the server, not the client.

The comparisons with ioredis and redis-py ran in the same session on the same server; they show the cost of one connection per request against a shared, coalesced one, not a general ranking of libraries.

Status and gaps

  • The repository holds all six. Only the Rust crate and the NuGet packages are on a registry, and those versions are older than the repository. Registry releases for the rest are not set up yet.
  • Cluster routing was tested on a three-shard server on one machine, not on a real Redis Cluster and not under failure.
  • Some commands were checked only up to the server's reply (ACL file commands without an ACL file, cluster commands on a standalone server). Each page says which.
  • Continuous integration for the new clients is not set up yet.

Which one to use

Use the client for your language. For .NET also look at the integration packages (distributed cache, rate limiting, idempotency, output caching, data protection, distributed lock). For examples of the commands themselves, see Commands and Examples.