memorydb
Redis you are allowed to lose, and Redis you are not

The flat already has a key-value store in it. It is a DynamoDB table with a device identifier in the partition key, a few hundred items, and I have never once thought about which availability zones hold it. That is the correct amount of thought to give a table like that.
So Amazon MemoryDB, which went generally available on the nineteenth of August, is not a service with any business being in my flat. I read it anyway, because it makes a claim about a shape I have built badly before: a Redis sitting in front of a database, and a few hundred lines of code whose entire job is to stop the two of them from disagreeing.
The claim
MemoryDB is compatible with Redis 6.2 — the same data types, the same commands, the same clients. Everything lives in memory, so reads are quoted in microseconds. The difference is underneath: writes go to a transactional log spread across multiple availability zones, and the FAQ puts the consequence in one sentence — only data that has been successfully persisted to that log is visible.
That is not a persistence setting. It is an ordering rule, and it is a
different thing from every durability option Redis ships with. An RDB snapshot
loses whatever happened since the last dump. Append-only with everysec loses
about a second. Append-only with always is an fsync on one machine, which
survives the process dying and does not survive the machine dying. Replication
in ElastiCache is asynchronous, so a failover can drop the tail of the write
stream, which is why every team I have worked on treats an ElastiCache cluster
as something you are allowed to lose and rebuild from the real database.
MemoryDB is the other thing. Writes are acknowledged after they are durable in more than one zone, reads on the primary are strongly consistent, and a replica being promoted has to catch up on the log before it starts serving. The positioning follows from that: AWS is selling it as a primary database, not a cache.
The trade is on the write path
Reads in microseconds, writes in single-digit milliseconds. It is worth saying that plainly rather than letting the adjectives hide it: on the numbers in the announcement, a MemoryDB write is measured in milliseconds where the Redis it is compatible with is measured in microseconds. That gap is not a defect. It is the product. You are paying the cost of a multi-zone log append on every write, and in exchange the write is still there after a node disappears.
Which makes "is MemoryDB a better Redis" the wrong question. The useful one is what fraction of my traffic is writes, and whether I care about the tail of the write latency distribution more than the mean.
Some shapes survive this easily. A session store that is read twenty times for
every write barely notices; the reads are still microseconds and the writes are
rare. A cache of rendered fragments, same. Other shapes do not survive it at
all. A rate limiter doing INCR on the way into every request is nearly pure
write traffic, and adding milliseconds to it means adding milliseconds to every
request the system serves. A job queue that pushes and pops constantly is in
the same category.
Whether pipelining or MULTI amortises the log append across a batch is the
obvious follow-up question, and I do not want to guess at the answer. It is
exactly the sort of claim I would want to see on a graph — the same client, the
same payload, the same concurrency, one run batched and one not — before
believing either version of it.
The replica endpoint became a correctness decision
Reads on the primary are strongly consistent. Reads on a replica are eventually consistent, with the lag published to CloudWatch. Each shard takes a primary and up to five replicas, and a cluster can reach five hundred nodes.
In ElastiCache, sending reads to replicas is a throughput decision, and the worst case is that somebody sees a slightly stale cache entry — which is what a cache is. In MemoryDB, where the same data is the system of record, the identical configuration line decides whether a user can read back what they just wrote.
The awkward part is that plenty of client libraries offer this as a performance
toggle. READONLY on a cluster connection, or a "read from replicas" flag in
the configuration, is one line that a reasonable engineer turns on during a load
test and never revisits.
# MemoryDB clusters are always sharded and always encrypted in transit,
# so the client needs both -c and --tls.
redis-cli -c --tls -h clustercfg.notes.xxxxxx.memorydb.eu-west-1.amazonaws.com -p 6379
> SET note:1 "written at the primary"
OK
> GET note:1
"written at the primary"
That sequence is guaranteed. The same GET issued against a replica is not —
it is a question about replication lag at that instant. If I adopted this, the
rule I would write down is that reads served from replicas are a deliberate,
named, per-call-site choice, not a connection-level default, and that anything
in a read-after-write path is pinned to the primary.
Getting one, in September
The part that surprised me: there is no infrastructure-as-code path yet.
CloudFormation has no AWS::MemoryDB::* resource types, the AWS provider has no
aws_memorydb_cluster, and the
provider issue
asking for the resources has been open since the week of the launch. Three weeks
after GA the ways to create a cluster are the console, the CLI, and the SDKs.
So the CLI, and a note in the repository saying this is temporary:
aws memorydb create-subnet-group \
--subnet-group-name notes-subnets \
--subnet-ids subnet-0a1b2c3d subnet-4e5f6a7b \
--description "MemoryDB, private subnets"
aws memorydb create-cluster \
--cluster-name notes \
--node-type db.r6g.large \
--num-shards 1 \
--num-replicas-per-shard 1 \
--subnet-group-name notes-subnets \
--security-group-ids sg-0123456789abcdef0 \
--acl-name notes-acl \
--tls-enabled
aws memorydb describe-clusters --cluster-name notes \
--query 'Clusters[0].[Status,ClusterEndpoint.Address,NumberOfShards]'
Three things in there are not optional and are easy to meet for the first time
at the wrong moment. A cluster only exists inside a VPC, so there is a subnet
group and a security group before there is a database. Authentication is Redis 6
ACLs rather than a single auth token, so the ACL and its user exist first.
Traffic is encrypted, so every client needs TLS configured — which is where a
local redis-cli from a package manager tends to fail, since not every build
ships with TLS support.
An existing cluster can come across without a rewrite: restore a MemoryDB cluster from an ElastiCache backup, or from an RDB file in S3. Nodes are R6g, so it is Graviton2 underneath.
What it removes, and what it does not
The code it deletes is cache-aside, and it is more code than anyone remembers. The invalidation on every write path. The guard so that a hundred concurrent misses do not all go to the database. The cold-start path for when someone deployed and the cache is empty. The reconciliation job for the entries that drifted anyway. None of that is interesting, all of it has bugs, and most of it only fails under load.
What it does not remove is the reason the database was there. MemoryDB is Redis:
you get its data structures and nothing else. No secondary indexes, no joins, no
query planner, no ad-hoc reporting. Every access path has to be something you
designed a key for in advance. If the answer to "how do we find all the accounts
in this state" is currently a WHERE clause, it does not become a MemoryDB
lookup by wishing.
It also does not remove the memory bound. The working set lives in RAM across the shards, which is the same constraint as before, except that now it applies to the whole dataset rather than the hot part of it. Making the durable store the in-memory store means paying for RAM proportional to the data, permanently.
What it costs to have
Three components: on-demand node hours, the volume of data written to the cluster, and snapshot storage. The first is a floor — a node is rented by the hour whether or not anything is talking to it, and a durable database is not something you pause overnight. The second is the one I would watch, because a per-gigabyte charge on data written is an unusual line for anything Redis-shaped and it points at the same place everything else in this post points at: the write is the expensive operation here.
At launch the regions are N. Virginia, Ireland, Mumbai and São Paulo. From Sofia that means Ireland, and it means Frankfurt is not an option yet, which matters if the rest of the stack is already there.
The VPC requirement has a tail as well. If the callers are Lambda functions, they now need to be in the VPC too, which means elastic network interfaces, subnets with capacity, and either a NAT gateway or a set of VPC endpoints for every other AWS API those functions were happily calling over the internet. That bill is not on the MemoryDB pricing page.
Where I would actually use it
The test I would apply is not "would this be faster". It is: is Redis already the source of truth for something, and have we been quietly pretending it is not? Session state that logs everyone out on a failover. A queue whose contents are reconstructible in theory and have never once been reconstructed in practice. Counters that back a billing number and get described as approximate in the one meeting where somebody asks. In those cases the durability was always required; it was just unfunded.
For a genuine cache in front of a real database, I would leave ElastiCache alone. Paying log-append latency on every write to protect data you are happy to lose is buying a guarantee you have no use for.
And for the flat, none of this. A DynamoDB table costs pennies, survives a zone without my involvement, and does not require a rented node or dragging every Lambda into a VPC to reach it. The interesting thing about MemoryDB is not that I need it. It is that it retires an argument I have had more than once, about whether the cache is allowed to be wrong — by making that a property you buy rather than a convention you enforce in review.
Written by
Deyan Peev
Founding Engineer · Sofia, Bulgaria


