Brand logo
HomeCloud ComputingSecuritySoftware DevelopmentAI ApplicationsStartupsGeneral
  1. Home
  2. /
  3. softwaredevelopment
  4. /
  5. replacing-memory-bound-redis-fleet-lavik-nvme-ssd

Engineering a Redis Cost Optimization: Consolidating a Memory-Bound Fleet onto Lavik on NVMe SSD

Ask a delivery team what limits its key-value tier and the answer is usually a bill, not a benchmark. When growth is capacity-bound rather than compute-bound, every step up in retained data triggers another shard, another replica and another pair of machines to patch — while the application gains little extra serving capacity from it. The published Lavik numbers describe a different lever: application values live on NVMe SSD instead of DRAM, the interface stays Redis-compatible, and the engine is measured at 1.14 million GETs per second, faster than Redis on DRAM in that comparison. What follows is the topology, the cost model, the migration steps, the misconceptions and the FAQ — the parts an engineering team needs to turn an architectural claim into a release plan.

All of it rests on a single capacity comparison: 300 E2s_v4 Redis VMs against two L16as_v4 data VMs plus one E2s_v4 Meta-only voter, where a Meta member runs on each VM and only the primary and follower retain the dataset.

1. In agent workloads the growth signal is state, not request volume

A human-facing service typically keeps a profile, a session and a feature set per user. An agent product multiplies that shape: a research assistant, a coding assistant and several background workers each hold execution state, observations and working context, and a worker that runs only occasionally still has to be readable the moment it resumes. The drivers of capacity are therefore agent count, state size and how long data remains useful — not always traffic.

Run the arithmetic at one billion retained agents: 1 KB of features is roughly 1 TB of values; 10 KB reaches 10 TB; 100 KB reaches 100 TB. Holding two copies pushes those totals to 2 TB, 20 TB or 200 TB before keys, indexes or replication are counted. Applications still expect low-latency reads and updates through familiar Redis clients and data structures, and keeping every retained value in expensive DRAM is what makes that combination hard to afford. Lavik exists to make NVMe SSD capacity practical for latency-sensitive work.

Value payload for one billion retained agents · decimal units

Bytes per agentUnique value payloadTwo copies, values only
1 KB1 TB2 TB
10 KB10 TB20 TB
100 KB100 TB200 TB

2. The most expensive habit in a memory-bound fleet: buying RAM by buying servers

Take 300 Standard_E2s_v4 Azure VMs, each with two vCPUs, 16 GiB RAM and no local SSD, arranged as 150 primaries and 150 replicas. That purchase delivers 600 vCPUs and 4,800 GiB of RAM, of which 2,400 GiB sits on the primary side. When RAM fills first, each expansion buys additional CPU, networking and operating systems largely to obtain more memory — while what the application actually needs is more retained profiles or longer session lifetimes. That mismatch is the entry point for Redis cost optimization: choose storage density independently of the processors needed to serve traffic.

Both layouts are quoted in the same region and purchasing model — East US 2, Linux pay-as-you-go, in US dollars — using Microsoft's published rate of $0.126 per hour for Standard_E2s_v4 and $1.376 per hour for Standard_L16as_v4. Across 730 hours per month, the 300 E2s_v4 VMs serving Redis cost $27,594, while the Lavik side — two L16as_v4 data VMs and one smaller voter — totals $2,100.94 per month. Each data VM ships 16 vCPUs, 128 GiB RAM and 3.84 TB of local NVMe SSD; the voter needs no local SSD and no dataset copy.

Adding flash does not by itself solve latency. Redis describes Flex as giving flash access in milliseconds and advises against broad access patterns, large working sets and frequent movement between RAM and flash; for an application with a sub-millisecond latency budget, a millisecond flash path is too slow. Agent traffic that repeatedly revisits different profiles and contexts makes this distinction consequential, because the engine must stay efficient on a dataset far larger than memory.

Measured against the Redis layout, the monthly VM bill falls by $25,493.06 — 92.4% — for an annualized saving of $305,916.72. Lavik's three VMs expose 34 vCPUs and 272 GiB RAM across the deployment, with the two NVMe-equipped nodes handling data and the smaller VM completing the failover quorum; Redis's 300 VMs expose 600 vCPUs, much of which a memory-bound workload may not need. The prices below cover self-hosted VMs only — OS disks, backups and traffic are additional deployment costs.

Azure East US 2 · Linux pay-as-you-go · USD · 730 hours per month; unit-cost columns are normalized to 1M average QPS, that is 1 million QPS.

DeploymentUSD / VM-hourMonthly USDAnnual USDUSD / million operations at 1M average QPS
Redis · 300 × Standard_E2s_v4$0.126$27,594.00$331,128.00$0.01050
Lavik · 2 × L16as_v4 + 1 × E2s_v4$1.376 (L16as_v4); $0.126 (E2s_v4)$2,100.94$25,211.28$0.00080

3. Assembling the reference topology, one decision at a time

  1. Size the data tier. Combine two Standard_L16as_v4 VMs with one Standard_E2s_v4 VM. Each data node carries 16 vCPUs, 128 GiB RAM and four 960 GB local NVMe devices, totaling 3.84 TB per data VM, and runs a Data process plus a Meta member.
  2. Complete the quorum without a data-sized machine. The E2s_v4 node runs the third Meta member on two vCPUs and 16 GiB RAM, forming a three-member Raft quorum for automatic failover while storing control-plane metadata only, not application data.
  3. Normalize cost to capacity. Because each data node stores a full dataset copy, the single-copy basis remains 3.84 TB, which lands the deployment at $547.12 per TB-month. Redis's 150 primaries provide 2,400 GiB, about 2.577 decimal TB, which is $10,707.88 per TB-month. Replica capacity is counted once, and both figures sit before database overhead and operational free-space reserves.
  4. Decide the failure path in advance. If the primary VM fails, the follower and the dedicated voter retain a two-of-three Meta majority to coordinate promotion of the eligible follower; the surviving follower holds the remaining data copy and the voter supplies control-plane participation.
  5. Split what belongs in memory. Lavik uses DRAM where it has the most value on the request path — the key index, metadata and active buffers — and puts values on NVMe SSD, separating growth in value bytes from growth in index memory. Size RAM from key count and key lengths, together with buffers, hugepages and replication backlog; in the published large-dataset experiment a billion-key layout fits a 125.8 GiB host while its values occupy about 1 TB.

What actually makes the SSD path fast

SPDK makes the storage path explicit. Lavik submits NVMe operations through userspace queue pairs and polls for completions, removing the kernel block-I/O submission path with its syscall and wakeup overhead. Asynchronous requests keep storage work in flight while workers make progress on other commands, and polling trades CPU time for prompt completion handling — how well that time is used depends on queue depth, completion batching and CPU placement. Modern NVMe devices supply the parallel queues and internal concurrency; the engine still has to deliver enough independent work to exploit them.

Lavik's Bycorf workers use coroutines, owner-local mutable state and explicit dispatch between workers, so other runnable work proceeds while one command waits on storage. Ownership keeps common operations close to the state they modify and reduces coordination between cores, which matters at a million operations per second, where small amounts of scheduling, synchronization or allocation overhead accumulate into substantial CPU demand. Designing execution and storage together lets the engine use SSD parallelism without turning every I/O into a stalled request-processing thread.

The optimizations run through the whole request path. Eligible disk GETs can use an admitted index snapshot on the connection worker, avoiding owner dispatch when the fast path applies; parsing handles batches of up to 128 commands; small pipeline replies coalesce into 64 KiB writes; per-worker append streams avoid a staging-buffer allocation for every logical slot. The Redis-compatible interface stays familiar to applications while the implementation underneath is built around efficient concurrent storage access. Lavik's request path, in short: coroutine workers, an in-memory key index and asynchronous SPDK I/O keep NVMe storage busy.

Large objects receive the same attention. Lavik 0.1.0 supports grouped storage for Strings, Hashes, Sets, Lists, Sorted Sets and Streams, with large strings using 8 KiB segments and collections using independently addressed groups, so a focused operation works on the relevant part instead of rewriting an entire object. For an agent profile with frequently changing features and much larger retained state, that layout is the difference between a small update and unnecessary work across the whole record.

4. The evidence: values on SSD, throughput above an in-memory server

In the published head-to-head, Lavik 0.1.0 SPDK is measured against Redis 8.10.2 and Valkey 9.1.2 on the same 16-vCPU Azure server. A separate load generator issues uniform random GETs and SETs over private networking, with 1 KiB values and pipeline depth one. Redis and Valkey serve their values from DRAM; Lavik uses its NVMe storage path. Throughput and client-observed latency are shown together so a team can pick an operating point against its own budget.

At 1,280 connections Lavik delivers 1,145,772 GET QPS and 971,950 SET QPS: GET throughput 12.5% higher than Redis and 18.1% higher than Valkey, SET throughput 2.2% higher than Redis, with GET P99 at 3.999 ms versus Redis's 4.415 ms. This is the architectural result that makes consolidation worth considering — NVMe-backed capacity arriving with higher throughput than an in-memory server, rather than forcing the application to exchange performance for cheaper storage.

Same 1,280-connection runs · QPS rounded to whole operations; all latency columns in milliseconds

System / operationQPSAverageP50P95P99P99.9
Lavik 0.1.0 SPDK GET1,145,7721.1171.0311.5113.999 ms7.135
Lavik 0.1.0 SPDK SET971,9501.3171.1192.7834.4797.199
Redis 8.10.2 GET1,018,7351.2561.0872.4794.415 ms7.103
Redis 8.10.2 SET951,0531.3461.1352.9434.5117.231
Valkey 9.1.2 GET970,2881.3191.1192.5114.415 ms7.455
Valkey 9.1.2 SET808,1031.5831.4552.5594.0477.199

Latency also depends on how hard a server is driven. At the billion-key operating point with 80 connections, Lavik delivers 385,514 GET QPS at 0.439 ms P99.9; at 640 connections it reaches more than a million GETs per second. An infrastructure team can read those curves as a menu of throughput and tail-latency combinations, and keeping headroom for bursts is more useful than sizing a production deployment solely from the highest point on a throughput chart.

The billion-key dataset contains 1.024 TB of raw values — about 7.6 times the server's RAM — and reaches 1,069,126 GET QPS, so performance extends well beyond a memory-sized dataset. The smaller-instance results tell the same capacity story: on two vCPUs and 16 GiB nominal RAM, growing the dataset from one million to 100 million 1 KiB values changes peak GET throughput only from 215,521 to 215,463 QPS, and SET retains 95.2% of its smaller-dataset peak. That matters for a compact service and a large agent platform alike: capacity can grow without a matching increase in serving nodes.

GET and SET across 80–1,280 connections. Ten-million-key tests use 30-second windows, 10M-key comparisons use 30-second windows, and billion-key tests use 60-second windows and distinct client seeds.

Agent state must also be written. In the separate io_uring YCSB experiment, Lavik processes 529,501 operations per second for a 50/50 read/update mix and 577,373 for a 95/5 mix. These are structured-record operations — HGETALL reads and LAVIK.HREPLACE updates against 100 million records with ten 128-byte fields — which show the design is relevant beyond a pure GET workload, including feature records whose contents change as an agent progresses through a task.

Separate io_uring YCSB experiment · 100M records, 10 × 128 B fields, 256 workers, no replicas

Lavik workloadTotal QPSREAD P99.9 msUPDATE P99.9 ms
50% HGETALL / 50% HREPLACE529,5015.0832.831
95% HGETALL / 5% HREPLACE577,3731.8181.578

One million operations per second corresponds to 86.4 billion operations per day if sustained. Measured serving performance at that level, combined with NVMe storage density, is a strong case for reevaluating a memory-bound fleet: start from the actual traffic envelope — command mix, peak demand, bursts and latency target — allocate compute to that envelope, and let NVMe SSD provide the capacity for everything the application needs to remember.

5. Fewer nodes means less cluster machinery to operate

Memory-driven growth also expands the topology engineers must run. Redis Cluster distributes 16,384 hash slots and uses a full-mesh cluster bus whose specification gives each node N−1 outgoing and N−1 incoming bus connections, so across the cluster there are N(N−1) initiated connections:

  • 89,700 at 300 nodes
  • 359,400 at 600
  • 999,000 at 1,000

Those are cluster-bus connections, separate from application traffic. Adding memory through more nodes enlarges this coordination fabric as agent state expands. The cluster uses gossip, heartbeat probes and failure reports to maintain membership and health; local failure suspicion must be reconciled with reports from other nodes, and failover requires authorization and configuration epochs. During a network partition or rolling restart, engineers still have to work out which primaries, replicas and paths remain reachable — and more members mean more placements and relationships to diagnose even when request-processing capacity is sufficient. Resharding adds data movement, ownership changes and client redirects; maintenance adds patching, restarts, monitoring and replica placement.

A storage-dense Lavik deployment reduces the number of Data processes needed for capacity and gives each one room to grow, with the Meta service managing topology and authority while native replication maintains followers. For a capacity-bound application, shrinking the fleet addresses two expenses at once: the servers purchased for memory and the operational work that comes with managing them.

6. Cutover runbook: move the workload, keep the service requirements

The logarithmic capacity model used before overhead counts one logical copy. Redis uses a 16 GiB primary and one replica per pair; each independent Lavik deployment adds two 3.84 TB data VMs and one smaller Meta-only voter, with all three VMs counted; the logarithmic chart repeats independent three-VM deployment units as capacity grows.

  1. Identify the candidate. The strongest consolidation case is recognizable: memory pressure keeps forcing expansion while CPU utilization and traffic remain below the fleet's serving capacity.
  2. Select a representative workload and size Lavik for its commands, key count, value distribution and busiest periods; a demanding tail-latency target or a CPU-intensive command mix may need additional serving capacity.
  3. Inventory commands and key shapes in the existing Redis deployment.
  4. Create the managed Lavik target and copy the baseline using RedisShake.
  5. Follow incremental changes from the source.
  6. Reconcile key counts, values and expirations before cutover.
  7. Pause source writes for the final catch-up, switch clients, and keep a rollback procedure that accounts for new writes.
  8. Build availability in from the start: place VMs in appropriate failure domains and keep Meta state on durable disks; Azure's local NVMe is temporary storage, so pair replication across VMs with external backups.
  9. Measure serving latency with replication, expiration and reclamation active, then rehearse primary failure and follower rebuild at the intended dataset size.
  10. Set recovery targets honestly. Lavik's Meta uses Raft for topology and authority, while Data replication is asynchronous; define the application's recovery-point and recovery-time targets accordingly, then verify them through failover drills.

The source shard count does not have to dictate the target's physical layout, and the migration guide provides release-pinned configuration and steps for turning the consolidation design into an executable migration.

7. Misconceptions worth retiring at design review

  • “Flash is inherently too slow, so SSD cannot serve this workload.” The published runs serve values from NVMe SSD at 1,145,772 GET QPS. The real caveat is that adding flash does not automatically solve latency — which is exactly why Redis Flex, described as giving flash access in milliseconds, advises against broad access patterns, large working sets and frequent RAM/flash movement for a sub-millisecond budget.
  • “More data means more application servers.” A 300 VM fleet buying 600 vCPUs and 4,800 GiB of RAM mostly to obtain memory is the pattern being questioned; storage density can be chosen independently of serving compute.
  • “Every retained value must live in DRAM.” The design keeps only the key index, metadata and active buffers in DRAM and places values on storage; the billion-key layout fits a 125.8 GiB host while its values occupy about 1 TB.
  • “A quorum member has to be a data-sized machine.” The voter supplies control-plane participation only, which avoids paying for an extra data-sized host.
  • “Sizing from the peak throughput point is enough.” The latency curves show throughput and tail behavior change with connection count; headroom for bursts beats sizing solely from the chart's highest point.
  • “The target must mirror the source shard count.” It does not have to; two complete dataset copies and three Meta voters are a topology choice, not a Redis shard mapping.
  • “Count replicas when normalizing cost per terabyte.” The capacity-normalized figures use a single-copy denominator — 2,400 GiB RAM (≈ 2.577 TB) for Redis primaries, 3.84 TB NVMe SSD for each Lavik data node.

8. The two fleets side by side

DimensionRedis fleetLavik deployment
Virtual machines300 E2s_v4 VMs (150 primaries, 150 replicas)two L16as_v4 data VMs plus one E2s_v4 Meta-only voter
Serving compute600 vCPUs34 vCPUs
Memory4,800 GiB of RAM, 2,400 GiB on the primary side272 GiB RAM
Capacity basis2,400 GiB RAM (≈ 2.577 TB)3.84 TB NVMe SSD per data node
Monthly / annual VM cost$27,594.00 / $331,128.00$2,100.94 / $25,211.28
Cost per TB-month$10,707.88$547.12
Measured GET throughputRedis 8.10.2: 1,018,735Lavik 0.1.0: 1,145,772 GET QPS
Quorum / coordination16,384 hash slots, full-mesh cluster busthree Meta members using Raft
Licensing note—Apache 2.0 open-source license

9. FAQ

Does the application have to change its client code?

No. The deployment is served through a Redis-compatible path, so applications keep their familiar Redis clients and data structures while values move from DRAM to NVMe SSD.

Which workloads are the best consolidation candidates?

Capacity-bound ones: retained state keeps climbing while CPU utilization and traffic stay below the fleet's serving capacity. The growth drivers to measure are agent count, state size and retention horizon rather than request volume alone.

Is flash not a latency risk for a sub-millisecond budget?

Flash alone is not the answer — the published guidance on Redis Flex warns against broad access patterns and RAM/flash movement for exactly that budget. Lavik's path combines DRAM-resident index and buffers with SPDK userspace I/O, and the measured GET P99 at 1,280 connections is 3.999 ms against Redis's 4.415 ms.

Can it keep up with writes, not just reads?

At 1,280 connections the run records 971,950 SET QPS, 2.2% above Redis. The io_uring YCSB experiment adds structured-record work: 529,501 operations per second for a 50/50 read/update mix and 577,373 for a 95/5 mix.

What operational relief should a team expect?

Fewer nodes to place, patch, monitor and reshard. Redis Cluster's bus grows as N(N−1) initiated connections — 89,700 at 300 nodes — while the consolidated topology runs three members: two data nodes and a voter.

Is the failover model synchronous?

No. Meta uses Raft for topology and authority, while Data replication is asynchronous, so recovery-point and recovery-time targets must be set from that and verified through drills at the intended dataset size.

Any licensing constraint to flag?

Lavik is distributed under an Apache 2.0 open-source license.

10. Action checklist for the next two iterations

  1. Chart the memory-bound tier: which saturates first, RAM or CPU, and how far traffic sits below serving capacity.
  2. Export the command mix, key count, key lengths and value distribution; record the busiest periods and the tail-latency target users actually feel.
  3. Compute your own cost per retained terabyte from the current fleet, then compare it with the single-copy basis used here.
  4. Prototype the three-VM topology in a test region with the same purchasing model, and measure with replication, expiration and reclamation active.
  5. Rehearse primary failure and follower rebuild at the intended dataset size before committing RPO and RTO numbers.
  6. Run the RedisShake dry run — baseline copy, incremental sync, reconciliation of counts, values and expirations — with a rollback path that accounts for new writes.
  7. Decide where index data, buffers and hugepages live, and size RAM independently of value growth.
  8. Keep external backups outside the temporary local NVMe devices.

11. Benchmark and sizing notes

Benchmark setup: Azure Standard_L16aos_v4, Japan West zone 2, AMD EPYC 9V74, 16 logical CPUs, eight physical cores, 125.8 GiB RAM and six 1.92 TB NVMe devices. The F32als_v6 client uses 16 threads over private accelerated mlx5 networking and Linux TCP. All runs use a single server without Data replicas, with AOF disabled on Redis and Valkey.

  • Test windows: Ten-million-key and 10M-key comparisons use 30-second intervals with correlated seeds; billion-key tests use 60-second intervals with distinct seeds; reported durations also include 300-second.
  • Lavik configuration: 8 GiB of hugepages, defrag enabled and 16 completions per poll.
  • Thread selection: Redis I/O-thread counts are 16 for GET and SET; Valkey uses 16 for GET and eight for SET.
  • Concurrency in the published configuration: 256 client workers, 12 Lavik workers, four system/IRQ CPUs.
  • Annualized figures come from 730 hours per month across 12 monthly periods.
  • Unit-cost comparisons are normalized to 1M average QPS, i.e. 1 million QPS.
  • VM prices exclude OS disks, backups and traffic, and precede database overhead and operational headroom.

12. Give retained state somewhere affordable to grow

When the footprint moves from 1 TB to 10 TB and beyond, the price of each additional terabyte stops being an infrastructure detail and becomes a product constraint. The alternative the published numbers put on the table is a Redis-compatible NVMe key-value store measured above Redis on DRAM, with efficient large-object storage and an Apache 2.0 open-source license. Start from the commands your service issues, load a representative dataset, and measure the latency budget that matters to your users before you provision anything. Moving from 300 Redis nodes to three Lavik nodes is not shrinkage for its own sake: it is a way to size compute to the workload's real demand and leave room for the data to keep growing.

Brand logo

IT Insights

Cloud & Infrastructure Practice Media for Enterprise Technology Decision-Makers

Cloud ComputingSecuritySoftware DevelopmentAI ApplicationsStartupsGeneralAI Data News Global

© 2026 IT Insights.

Cookie Notice

We use cookies to improve your experience and analyze website traffic. Read our Privacy Policy to learn more.