Zaris is a distributed key/value store built for .NET, with its own binary protocol and native .NET clients. With 2.0.0, every Zaris node can also expose a Redis-protocol (RESP2) listener — so existing Redis clients, in any language, can connect to it without code changes.
Why put a Redis face on a .NET store
Redis has the widest client-library support of any key-value protocol. Adding RESP compatibility means polyglot teams get one replicated, highly-available store that every service can talk to today, regardless of language. The RESP front-end is opt-in and disabled by default per node.
The core hash is Redis-slot-aligned
Zaris uses the same key hashing Redis Cluster uses: CRC16(key) % 16384. That means cluster-aware Redis clients can route straight to the owning node, with no proxy in between:
redis client ──CRC16(key) % 16384 → slot → owner ──▶ node that holds the key ──▶ reply
Collections use a whole-value model
Native data structures (hashes, lists, sets, sorted sets) go through read-modify-write with compare-and-swap semantics, so concurrent writes don't conflict across replicas.
Transactions run on real 2PC, not a simulation
MULTI/EXEC executes on Zaris's native two-phase-commit transaction machinery rather than faking it — counter commands like INCR/DECR stay properly isolated inside a transaction block.
Three ways to fail over
- Load balancer (recommended) — any node accepts any key; dead nodes just drop out of rotation.
- Sentinel — Zaris answers Sentinel discovery commands so clients can re-resolve.
- Cluster — CRC16-aligned slot topology, same as Redis Cluster.
What's in, and what's cleanly out
Testing against StackExchange.Redis: ~126 commands supported, ~92 cleanly not supported, zero failures. Supported: core strings, collections, Streams with consumer groups, MULTI/EXEC/WATCH, pub/sub. Not supported, by design: Lua scripting, geo commands, HyperLogLog, persistence commands — these assume infrastructure Zaris doesn't have.
Pin your client versions
The listener speaks RESP2 only. Pin your Redis client library version rather than floating it, so you don't get an unexpected negotiation attempt at a newer protocol version.
Connecting
redis-cli -h node-a.internal -p 6379 SET user:42 "ada"
redis-cli -h node-a.internal -p 6379 GET user:42
import redis
r = redis.Redis(host="node-a.internal", port=6379)
r.set("user:42", "ada")
print(r.get("user:42"))
// StackExchange.Redis, unchanged
var mux = ConnectionMultiplexer.Connect("node-a.internal:6379");
var db = mux.GetDatabase();
db.StringSet("user:42", "ada");
Full RESP config, the command compatibility matrix, and migration notes are in the docs.
Top comments (0)