
ElastiCache for Valkey Just Became a Durable Data Store. Here's What That Actually Means (Part 1: Architecture & Trade-offs)
This is Part 1 of a two-part series. This post covers the internal architecture of Durability, its consistency semantics, constraints, operational design, cost, multi-Region patterns, and how it changes the way you connect Valkey to Aurora. Part 2 covers hands-on benchmarking and fault injection testing.
Series: ElastiCache for Valkey Just Became a Durable Data Store (2 articles)
- 1ElastiCache for Valkey Just Became a Durable Data Store. Here's What That Actually Means (Part 1: Architecture & Trade-offs) This article
Introduction
While studying for an AWS certification exam, I picked up an assumption that I carried with me for years whenever I used ElastiCache: cache data is disposable. If a failover happened, whatever hadn't been replicated yet was gone. If the cluster restarted, everything was gone, and you had to warm the cache back up. So the rule I internalized was simple: anything you write to ElastiCache that you can't afford to lose, write to RDS or Aurora first.
That's more or less why the cache-aside pattern became the default. It exists to work around a cache that can't be trusted to keep your data.
That assumption stopped being universally true in June 2026. AWS announced "Durability for Amazon ElastiCache for Valkey," and ElastiCache can now be used as a durable data store.
As a headline, "ElastiCache is now durable" is where most coverage stops. But once you're actually deciding whether to adopt this, you want to know what's happening under the hood and where the edges of the guarantee are. So I read through the official documentation and pulled together what I found. This post digs into:
- The internal architecture of the Multi-AZ transactional log (how durability and replication end up being the same mechanism)
- Consistency semantics (does the primary's strong consistency survive a failover, and what do reads from a replica actually guarantee)
- How to read AWS's own published benchmark numbers (why async is faster than no-durability at all, and why sync reads degrade under high load)
- Constraints and operational design (DurabilityLag, backpressure, the write throughput ceiling, why this doesn't play well with PrivateLink, and what it means for your application code)
- ElastiCache vs. MemoryDB and the Global Datastore trade-off (durability and Global Datastore can't be combined)
Hands-on benchmarking with memtier_benchmark and fault injection testing with FIS are in Part 2.
I'm assuming familiarity with basic ElastiCache/Valkey operations, replication and failover in general, and the concepts of eventual and strong consistency.
The old architecture, and what made it painful
The standard way to use ElastiCache was the cache-aside pattern.

This pattern created a few recurring pain points.
1. Data loss on failover
ElastiCache's replication was an asynchronous stream from primary to replica. If the primary node went down, any write that hadn't yet reached a replica was gone. You could get an ACK for a write and still lose it.
2. Total data loss on restart
A restart after maintenance or a failure wiped the cache clean, which could send a flood of requests straight to the database, a classic cache stampede. You either needed a separate warm-up mechanism or a database that could absorb that load.
3. Running two stores for one dataset
You had to maintain ElastiCache for fast reads and RDS for durability, at the same time, forever. Both the cost and the design complexity doubled.
If you needed to solve these problems, the answer used to be MemoryDB (more on that later).
The internal architecture of Durability
Two durability modes
Synchronous writes (Sync)
Before returning an ACK to the client, the write is persisted to a Multi-AZ transactional log spanning two or more AZs. An acknowledged write survives failures. Write latency stays in single-digit milliseconds, and reads stay at microseconds. This mode adds an 18% surcharge on top of the node's hourly rate (more on cost later).
Asynchronous writes (Async)
The write is persisted to the transactional log in the background, after the ACK is returned. Up to 10 seconds of acknowledged writes can be lost in a failure. Both writes and reads stay at microseconds, and there's no additional cost.

The transactional log isn't a "persistence device." It's a replication path
This is the most interesting part of the whole feature, in my opinion. The Multi-AZ transactional log isn't just a place to park a WAL (write-ahead log). It has effectively become the data distribution path inside the cluster.

Here's what the official docs and blog posts describe about how this works:
- A replica doesn't stream directly from the primary. It receives writes that were committed to the transactional log, in the same order they executed on the primary, and applies them
- During a failover, a replica catches up on the log before being promoted. A new primary only starts accepting writes after it has caught up on committed data. In Sync mode, this is exactly the mechanism that produces zero data loss
- Recovering a failed node doesn't put load on the primary. A replacement replica is restored independently from the log (plus a snapshot). The old problem of replica resync eating the primary's CPU and bandwidth is gone by construction
- The system survives every node in a shard dying at once. Every node gets replaced, all of them sync from the log, and once committed data is restored, one node is automatically elected the new primary. In Sync mode, this scenario also produces zero data loss
In other words, the old topology of asynchronous primary-to-replica replication gets replaced, once durability is enabled, with primary-to-log-to-replica. That's the same architecture MemoryDB has used from the start (persistence and replication both routed through a Multi-AZ transactional log), so it seems fair to read this as a proven MemoryDB architecture being brought over to ElastiCache. (AWS hasn't stated that the implementations are identical.)
Consistency semantics
The official Consistency page lays this out clearly, and it's the part worth getting exactly right.
Sync mode
- Reads and writes on the primary are strongly consistent. Every acknowledged write is guaranteed to be reflected in subsequent reads from the primary
- That strong consistency survives a failover, because a new primary only gets promoted after catching up on committed data in the log
- Reads from a replica (via
READONLY) are eventually consistent. The most recent write might not be visible yet, and the lag is observable through CloudWatch metrics - Reads from a single replica are sequentially consistent, though. Writes are applied in the same order they executed on the primary, so you'll never see a newer value and then a stale one on the same replica
Async mode
- Consistency during normal operation is identical to Sync
- Strong consistency breaks across a failover. Up to 10 seconds of acknowledged writes can be lost, so reads on the new primary might not reflect writes that were already acknowledged
- Async isn't recommended for workloads that need strong consistency guarantees, which AWS states explicitly
The asymmetry is worth internalizing: Async carries no penalty during normal operation, and only degrades its consistency guarantee during a failure. That's a useful axis for deciding which workloads belong on which mode.
How to read AWS's own benchmark numbers
The AWS Database Blog published measurements on r7g.4xlarge at an 80:20 read:write ratio.
50K TPS
| Mode | Write P50/P90 | Read P50/P90 |
|---|---|---|
| No durability | 147us / 185us | 260us / 301us |
| Async | 112us / 152us | 245us / 289us |
| Sync | 2.15ms / 2.36ms | 245us / 288us |
100K TPS
| Mode | Write P50/P90 | Read P50/P90 |
|---|---|---|
| No durability | 160us / 196us | 263us / 301us |
| Async | 128us / 158us | 245us / 286us |
| Sync | 2.72ms / 3.12ms | 879us / 992us |
Look closely at this table and two things stand out.
1. Async writes are faster than no durability at all
Write P50 goes from 147us to 112us at 50K TPS, and from 160us to 128us at 100K TPS. Enabling durability makes writes faster. That runs against intuition, since adding a sync step should slow things down, but I think it can be explained by the architecture change described above. With durability enabled, replication to replicas happens through the transactional log, which frees the primary from the job of pushing a replication stream to replicas itself. That's my hypothesis for why command processing gets lighter. It could be within measurement noise, but the fact that the reversal holds consistently across both TPS tiers suggests it isn't just chance.
2. Sync reads degrade under high load, too
The claim that "reads stay at microseconds" is technically true, but at 100K TPS, Sync's read P50 is 879us, about 3.5x the other modes. It's still measured in microseconds, but in practice that's close to 1ms. If you're targeting high throughput with Sync, you need to budget not just for the 2-3ms write, but for the read tail latency too. The 2-3ms write figure for Sync itself looks reasonable once you account for cross-AZ round-trip time plus the log's quorum write.
Configuration and constraints (you can't enable this after the fact)
This is the point people most often get wrong, and the official docs are unambiguous about it. Whether durability is on or off can only be decided when the cluster is created.
- You cannot retrofit durability onto an existing non-durable cluster
- Once enabled, you cannot disable it
- The only thing you can change later is switching between sync and async (
ModifyReplicationGroup)
This asymmetry matters for how you design a new cluster. If you decide you want durability after the cluster is already running, your only option is to build a new cluster and cut over the endpoint. But if you enable Async up front, there's no extra charge (as covered below, Async's node price is the same as no-durability), and you can move to Sync later in about 50 seconds with no downtime. If your design can absorb the constraints (CME, TLS, a supported instance family), my personal recommendation is to default new clusters to Async enabled. Free only refers to price, though; you still have to build a cluster-aware client and reject-time retry logic, and CMD, Serverless, or unsupported families are simply out of scope.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# specify durability at creation time (this is the only point where it can be enabled)
aws elasticache create-replication-group \
--replication-group-id my-durable-cluster \
--engine valkey \
--engine-version 9.1 \
--cache-node-type cache.r7g.large \
--num-node-groups 1 \
--replicas-per-node-group 1 \
--multi-az-enabled \
--automatic-failover-enabled \
--transit-encryption-enabled \
--durability sync
# switch between sync and async (durable clusters only)
aws elasticache modify-replication-group \
--replication-group-id my-durable-cluster \
--durability async \
--apply-immediately--durability accepts sync, async, disabled, or default (default is resolved by ElastiCache from the engine version and configuration, and currently resolves to disabled). You can check which mode is actually in effect through the EffectiveDurability property in the API response. Snapshots store EffectiveDurability, and restoring from a snapshot carries the durability setting forward.Enabling durability automatically turns on encryption at rest (a service-managed KMS key or your own CMK, visible in the
StorageEncryptionType field). Encryption in transit (TLS) must be enabled at creation. That means a durable cluster is always a TLS connection.Constraints at a glance
| Item | Constraint |
|---|---|
| Engine | Valkey 9.0 or later (9.1 added in late June 2026; durability supports 9.0+, so it works on 9.1 too) |
| Instance families | R7g, R6g, M7g, M6g, C7gn only |
| Cluster mode | Cluster Mode Enabled (CME) required. CMD (Cluster Mode Disabled) isn't supported |
| Topology | Multi-AZ required, at least one replica per shard required |
| Encryption | Encryption at rest is enabled automatically; TLS must be enabled at creation |
| Write throughput | Up to 100 MiBps per primary |
| Not supported | ElastiCache Serverless, Global Datastore, Outposts, Local Zones, data tiering |
| Migration | Online migration from self-hosted Valkey/Redis OSS isn't supported |
| With search indexes | Writes to indexed keys can be throttled (more below) |
The CME requirement matters more than it looks. If your application is used to the simplicity of CMD's single endpoint, you'll need to move to a cluster-aware client (slot awareness, handling
MOVED redirects). MULTI/EXEC is also subject to the same single-slot constraint, which means designing hash tags ({...}).This also spills into network design. You technically can register nodes as NLB IP targets, but a CME-aware client receives each node's real address via
CLUSTER SLOTS or MOVED after connecting, and it connects to that address directly. So you can't hide the cluster behind a single VIP and expect it to work. This isn't an ElastiCache-specific limitation; it's a property of the cluster protocol in general, and the consequence is that you can't expose a durable cluster to another account through PrivateLink (which requires an NLB behind it). If you need to share access across accounts within the same Region, use VPC Peering (this lets you reference a security group across accounts). Cross-Region Peering itself works fine, but per AWS's own documentation , this security-group-referencing mechanism specifically does not work across Regions; you have to fall back to CIDR blocks instead. If a PrivateLink boundary is genuinely required by your security posture, don't expose Valkey directly; put an API layer in front of it and publish that instead.The 100 MiBps per-primary ceiling feeds directly into shard sizing. For a 1 KiB write, the amount written to the log (including key and metadata) works out to roughly 1.1-1.2 KiB per write, which puts the theoretical ceiling for a single shard at somewhere around 80,000-90,000 writes/sec. If your expected write volume exceeds that, shard from the start (increase
--num-node-groups). Once you hit the ceiling, the TrafficManagementActive metric flips to 1 and writes get throttled.Write throttling when search indexes are in play
If you're using search indexes (Valkey 9.0's vector/full-text search) on a durable cluster, writes targeting indexed keys are conditionally throttled. The specifics are interesting.
- The decision is based on whether the search module's writer-thread CPU utilization, averaged over a rolling 2-hour window, exceeds 50%. Short bursts don't trigger it
- Throttling means delay, not rejection. Commands never error out; they just get slower
- If current CPU is at or below 50%, the system won't throttle further even if the 2-hour average is above the threshold, so write capacity never drops below 50% of normal
- Only write commands touching indexed keys are affected:
HSET-family commands,JSON.*commands,DEL/RENAME/COPY/RESTORE. Writes to non-indexed keys and all reads are unaffected - You can observe this through
SearchWriteThrottleActive,SearchWriteThrottledClientsCount,SearchWriteThrottleEvents, andSearchWriteCPUUtilization
Read this as a mechanism protecting the transactional log's bandwidth from amplified writes caused by index updates. If you're designing for durable clusters with sustained, high-volume ingest and search combined, put
SearchWriteCPUUtilization on a dashboard from day one.Operational design (metrics and backpressure)
Durable clusters get dedicated CloudWatch metrics.
| Metric | Meaning | How to use it operationally |
|---|---|---|
| DurabilityLag | Age, in ms, of the oldest write that's acknowledged but not yet durable. Always 0 in Sync | This is Async's effective RPO. As it approaches 10,000ms, writes start getting rejected, so alert around the 5,000ms range |
| DurabilityBufferExceededErrorCount | Count of write commands rejected because the durability buffer exceeded 10 seconds. Always 0 in Sync | Nonzero means your application's writes are erroring. Watch this alongside your client's retry configuration |
| TrafficManagementActive | 1 if throttling is active because the transactional log's throughput ceiling was exceeded | If this stays at 1 continuously, that's a signal to shard or change node type |
Here's exactly what happens in Async mode. The primary continuously tracks the age of the oldest write that's acknowledged but not yet durable (the durability buffer). Once that age exceeds 10 seconds, the primary rejects all incoming writes until the log catches up on persistence. Reads keep returning at microsecond latency the whole time, and once the log catches up, writes resume automatically. In other words, "up to 10 seconds of loss" isn't a best-effort estimate; it's a hard ceiling enforced by backpressure.
This has two operational implications.
- If you're using Async, client-side retries are a hard requirement. Write rejections from a buffer overrun come back as a cluster-down error, and if your application doesn't have automatic retry with exponential backoff configured, a transient log-side congestion event becomes an outright outage (the official docs point to their client best practices post for exactly this reason)
- Async's RPO is observable. "Up to 10 seconds" is a ceiling, not a typical value;
DurabilityLagunder normal conditions is far lower than that. You can measure your workload's actual effective RPO and use it to decide whether Sync or Async is the right fit
What changes in your application code
Durability is implemented at the infrastructure layer, so no command or API changes at all. What changes is everything around it. Here's a summary of the constraints and operational points above, from the application's point of view.
| What it means | |
|---|---|
| Changes (required) | Moving off a non-durable cluster requires CME + TLS support (a cluster-aware client, hash tag design; see the constraints table). Async requires exponential backoff retries to handle write rejections on buffer overrun (see above). Sync moves writes from microseconds to 2-3ms, which means redesigning timeouts, connection pooling, and pipelining |
| You can remove | Warm-up/reload logic after a restart or failover. The "write to the RDB first, just in case" ordering constraint (Valkey-first is now viable). With Sync, compensation and reconciliation batches built around the assumption that acknowledged data can vanish |
| Unchanged | A write that errors out is still indeterminate (you don't know if it landed). Retry-on-failure and idempotent design are still required. Reads from a replica (READONLY) are still eventually consistent. You still have to decide whether you can tolerate Async's rollback window (up to 10 seconds) across a failover |
Enabling durability doesn't make consistency someone else's problem. All it guarantees is that acknowledged writes don't disappear. How you handle writes that never got acknowledged, and replica consistency, still needs the same design discipline you'd apply to ElastiCache without durability.
ElastiCache vs. MemoryDB: AWS's recommendation has changed
The old rule was: if you're in a single Region and can't tolerate data loss, MemoryDB was the only option. That's no longer true.
AWS's official documentation (as of June 2026) states:
You should consider using MemoryDB if your workload requires multi-Region active-active replication with conflict-free data types (CRDTs). For single-Region durable workloads, consider using ElastiCache with durability enabled.
MemoryDB is now positioned specifically for multi-Region active-active workloads that need CRDTs, and nothing else.
Architecturally, ElastiCache's durability sits in the same design lineage as MemoryDB's Multi-AZ transactional log, as described above. MemoryDB writes always ACK after persisting to the local Multi-AZ transactional log, which is the exact same ACK semantics as ElastiCache's Sync mode. It's fair to say a single-Region MemoryDB equivalent has arrived inside ElastiCache.
Comparison
| Aspect | ElastiCache + Durability | MemoryDB |
|---|---|---|
| Durability | Single-Region (Multi-AZ) | Single/Multi-Region |
| Multi-Region active-active | No | Yes (CRDT) |
| Write latency | ms (Sync) / us (Async) | ms |
| Read latency | us | us |
| Async mode (us writes + 10s RPO) | Yes | No (always synchronous) |
| Cost | Tokyo, r7g.large, 2 nodes: Async $307/mo, Sync $362/mo | Tokyo, r7g.large, 2 nodes: $379/mo |
Which one should you pick
- Do you need durability?
- No → ElastiCache (no durability)
- Yes → Do you need multi-Region active-active?
- No → ElastiCache with durability (Sync/Async)
- Yes → MemoryDB
Cost comparison (Tokyo Region, r7g.large, 1 primary + 1 replica x 730 hours)
Prices pulled from AWS's public pricing API and pricing pages (as of June 2026). Sync Durability adds an 18% surcharge on the node's hourly rate; Async adds nothing.
| Configuration | Node price/hr | Monthly (2 nodes) | Notes |
|---|---|---|---|
| ElastiCache Valkey (no durability) | $0.2104 | ~$307 | -- |
| ElastiCache Valkey (Async) | $0.2104 | ~$307 | No additional charge |
| ElastiCache Valkey (Sync) | $0.2483 ($0.2104 x 1.18) | ~$362 | +18% on node price |
| MemoryDB Valkey | $0.2597 | ~$379 | -- |
The gap between Sync Durability's monthly cost (~$362) and MemoryDB's (~$379) is just $17. "ElastiCache is cheaper if all you want is durability" is technically correct, but once you're on Sync it's close to a rounding error. Where ElastiCache is clearly cheaper is Async ($307, no additional cost at all), which means the real price inflection point is the Sync/Async decision, not ElastiCache vs. MemoryDB. The functional inflection point is whether you need multi-Region active-active.
Long-term commitment discounts widen the gap further
Everything above compares on-demand pricing. Look at long-term commitment discounts and the picture shifts. There are two things going on here.
Both services have Reserved Nodes, but only ElastiCache has a Valkey-priced one
Both ElastiCache and MemoryDB offer 1-year and 3-year Reserved Nodes (RIs), with up to 55% off at full upfront payment on either side. But MemoryDB's Reserved Nodes are priced against the Redis OSS engine, as stated explicitly in the official docs, and there's no Valkey-specific Reserved Node offering. You can apply it to Valkey nodes through size-flexible reservations, but the discount is still computed against the Redis OSS on-demand rate ($0.371/hr), not Valkey's on-demand rate ($0.2597/hr).
Here's the effective 3-year-all-upfront rate for r7g.large in Tokyo, pulled from AWS's pricing API:
| On-demand | 3-year all-upfront effective rate | Discount | |
|---|---|---|---|
| ElastiCache Valkey | $0.2104/hr | $0.0947/hr | ~55% |
| MemoryDB (Redis OSS-priced) | $0.371/hr | $0.1669/hr | ~55% |
The discount percentage is the same on both sides, about 55%, but the baseline it's discounted from is pinned to the more expensive engine (Redis OSS) on the MemoryDB side. The on-demand gap was about 23% ($0.2597 vs. $0.2104). At 3-year all-upfront, the effective-rate gap widens to about 76% ($0.1669 vs. $0.0947).
MemoryDB isn't on the Database Savings Plans coverage list, either
Database Savings Plans, announced at re:Invent in December 2025, gives you up to 35% off with a 1-year usage commitment and no upfront payment. ElastiCache for Valkey is explicitly covered: 20% off for provisioned, 30% off for Serverless. AWS's list of covered services (Aurora, RDS, DynamoDB, ElastiCache, DocumentDB, Neptune, Keyspaces, Timestream, DMS, OpenSearch Service) doesn't include MemoryDB. I haven't found an explicit statement excluding it, but it's consistently absent across every list I checked.
So even for the case where you just want a lightweight, 1-year commitment discount, ElastiCache Valkey has a path that MemoryDB doesn't. On either axis, 3-year Reserved Nodes or Database Savings Plans, ElastiCache Valkey's long-term commitment discounts are meaningfully more generous.
Going multi-Region: Global Datastore or MemoryDB
ElastiCache has a multi-Region feature called Global Datastore, and there's an important constraint attached to it. Global Datastore can't be combined with durability (stated explicitly in the official Limitations page). That means going multi-Region on ElastiCache means giving up durability in favor of Global Datastore, and if you need both durability and multi-Region at the same time, MemoryDB is your only option. Your choices come down to three:
- Single-Region + durability -> ElastiCache with durability
- Multi-Region (DR/reads) -> ElastiCache Global Datastore (no durability)
- Multi-Region + durability -> MemoryDB Multi-Region (active-active)
ElastiCache Global Datastore (active-passive)

- The write ACK happens after the write completes in the primary Region. Propagation to the secondary is asynchronous
- Failover on a primary Region failure is manual by default (you can automate it with SNS + Lambda)
- No additional service charge (you only pay for nodes); supported from Valkey 7.2 onward
- Meant for DR, read offloading, and geographic optimization. A node-level failure within a Region can still lose data as before, since durability isn't supported here
MemoryDB Multi-Region (active-active)

- The write ACK happens after persistence to the local Region's Multi-AZ transactional log. Propagation to other Regions is asynchronous (usually under 1 second)
- Conflicts resolve automatically through CRDTs. Concurrent writes to the same key resolve via last-writer-wins (key-level for strings, field-level for hashes/sets/sorted sets)
- Local writes keep being accepted even during a Region partition, and they converge via CRDT once connectivity is restored
- Availability SLA is 99.999%
(Note: Tokyo and Osaka are both AWS Regions inside Japan, commonly paired for in-country disaster recovery. The same pattern applies to any two Regions on either side of a multi-Region setup.)
Comparison summary
| ElastiCache Global Datastore | MemoryDB Multi-Region | |
|---|---|---|
| Topology | Active-Passive | Active-Active |
| Durability within the local Region | None (can't combine with durability) | Yes (Multi-AZ transactional log) |
| Write ACK | After the write in the primary Region | After local Multi-AZ persistence |
| Writes from other Regions | Not allowed | Allowed |
| Conflict resolution | Doesn't happen | CRDT + last-writer-wins |
| Failover | Manual by default | Automatic |
| Use case | DR, read offloading | A global app that writes from multiple Regions |
If all you want is to go multi-Region, Global Datastore covers most of those cases, but you give up durability within a Region to get it. There's currently no way to build "RPO of zero within a Region, DR across Regions" on ElastiCache alone, and that gap is where MemoryDB still has a clear edge.
Do you still need a relational database?
Short answer: yes. To be clear about terminology, "RDB" in this section means relational database, not Valkey's RDB snapshot file format.
Adding durability to ElastiCache doesn't change Valkey's structural limits.
| Operation | Valkey's limit | Alternative service |
|---|---|---|
| Joins across tables, complex aggregation, window functions | Only limited aggregation commands | RDS/Aurora, Redshift/Athena |
| ACID transactions spanning multiple shards | Only within a single slot (needs hash tag design) | RDS/Aurora |
| Schema management, foreign key constraints | None | RDS |
| Cheap, large-scale persistence | Assumes the whole dataset fits in memory (data tiering can't be combined with durability) | RDS/S3 |
| Large-scale full-text search, graphs, long-term time-series analysis | 9.0 has search, but it doesn't scale to this | OpenSearch / Neptune / Timestream |
| Regulatory audit logging | Limited feature set | Aurora + CloudTrail |
The old two-tier picture, ElastiCache as the cache and the RDB as the persistent store, shifts. ElastiCache now also handles the fast, persistent tier, while the RDB is reserved for complex queries and large-scale data. The RDB doesn't become unnecessary; its job changes.
Pairing Valkey with Aurora: which pattern to use
Durability makes "write to Valkey first, then flow it to Aurora" a realistic option. Previously, you had to write to Aurora first because you couldn't trust Valkey's data to stick around. There are four common patterns, and I'll frame the choice as a decision table.
| Pattern | Write path | Real-time-ness | Consistency | Good fit |
|---|---|---|---|---|
| 1. Write-Through | App writes to both Valkey and Aurora | Immediate | Strong (hard to guarantee) | Operations that need an audit trail |
| 2. Valkey First (outbox) | App -> Valkey -> Aurora async | Fastest | Eventual | Sessions, scores, IoT |
| 3. Aurora First + CDC | App -> Aurora -> reflected into Valkey | Sub-second | Strong | Product/price master data |
| 4. CQRS | Writes to Aurora, reads from Valkey | Sub-second | Reads are eventual | Large-scale e-commerce, dashboards |
Patterns 1, 3, and 4 have existed all along. What durability changes for them is stability: the Valkey-side view no longer vanishes on a failure, so you can drop the warm-up design entirely. In pattern 3, Valkey's data stays intact even if CDC delivery pauses. In pattern 4, continued reads from Valkey during an Aurora outage are now guaranteed within the range of already-replicated data. In pattern 1, you still need compensation logic for a Valkey success followed by an Aurora failure (and since this is CME,
MULTI/EXEC still needs hash tags to keep everything in one slot).Summary
Picking by use case
| Use case | Choice |
|---|---|
| Cache only (RDB is the source of truth) | ElastiCache (no durability) |
| Cache, but I want data to survive a restart | ElastiCache Async Durability |
| Sessions, real-time balances, payment tokens (can't lose data, needs strong consistency) | ElastiCache Sync Durability |
| DR setup, offload reads to a secondary Region (no need for durability within a Region) | ElastiCache Global Datastore |
| Multi-Region active-active, or durability within a Region combined with multi-Region | MemoryDB Multi-Region |
| Complex queries, aggregation, OLAP | RDS/Aurora/Redshift, alongside ElastiCache |
What this post covered
- Internal architecture: the Multi-AZ transactional log does double duty as both persistence and replication, and that's exactly why Sync's "an acknowledged write never disappears" guarantee holds, with the primary's strong consistency preserved across a failover (a replica is eventually consistent, plus sequentially consistent). Async trades that guarantee for lower latency, at the cost of up to a 10-second rollback window on failure
- Constraints: durability can only be enabled at creation (no retrofitting, no disabling, only sync/async is switchable later). The service requires CME, Multi-AZ plus a replica, TLS, and a supported instance family. It can't be combined with Global Datastore, Serverless, or data tiering, and the CME requirement means you can't share it through PrivateLink either
- Application impact: commands don't change, but CME forces your client to become cluster-aware (hash tags for multi-key operations), Async needs retry logic for its write rejections, and Sync needs a reworked latency budget.
DurabilityLagis your effective RPO to watch, with backpressure kicking in at 10 seconds - Cost: on Tokyo r7g.large with 2 nodes, that's Async at $307/mo (no surcharge), Sync at $362/mo (+18%), and MemoryDB Valkey at $379/mo, and ElastiCache's edge grows the longer your commitment (3-year Reserved Nodes or Database Savings Plans)
Part 2 puts these claims to the test.
Series: ElastiCache for Valkey Just Became a Durable Data Store (2 articles)
- 1ElastiCache for Valkey Just Became a Durable Data Store. Here's What That Actually Means (Part 1: Architecture & Trade-offs) This article
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article