Skip to content

ElastiCache

First PublishedByAtif Alam

ElastiCache is a managed in-memory data store running Redis or Memcached. It sits between your application and your database, serving frequently accessed data at sub-millisecond latency.

Without cache:
Client ──► App ──► Database (10–100ms)
With cache:
Client ──► App ──► Cache (< 1ms, hit) ──► return
└──► Cache miss ──► Database (10–100ms) ──► store in cache ──► return

Caching reduces database load, lowers latency, and improves throughput. A cache hit is typically 100x faster than a database query.

FeatureRedisMemcached
Data structuresStrings, hashes, lists, sets, sorted sets, streams, bitmapsStrings only
PersistenceYes (snapshots + AOF)No (in-memory only)
ReplicationYes (primary + replicas)No
Cluster modeYes (automatic sharding)Yes (client-side sharding)
Pub/SubYesNo
TransactionsYes (MULTI/EXEC)No
Lua scriptingYesNo
Use casesCaching, sessions, leaderboards, queues, pub/sub, real-time analyticsSimple key-value caching

Choose Redis for most use cases — it’s more versatile. Choose Memcached only for simple caching with multi-threaded performance.

Cluster Mode Disabled (Single Shard):

Read
Client ──► Primary ──────► Replica 1 (AZ-a)
(write) ──────► Replica 2 (AZ-b)
  • One primary node (writes) + up to 5 replicas (reads).
  • All nodes hold the full dataset.
  • Good for: datasets that fit in one node (up to ~340 GB).

Cluster Mode Enabled (Multiple Shards):

Client ──► Shard 1: Primary + Replicas (keys A–M)
──► Shard 2: Primary + Replicas (keys N–Z)
──► Shard 3: Primary + Replicas (keys ...etc)
  • Data is partitioned across shards (each shard is a primary + replicas).
  • Up to 500 shards.
  • Good for: large datasets, high write throughput (writes scale with shards).
TypevCPUsMemoryUse Case
cache.t3.micro20.5 GBDev/test (free tier eligible)
cache.t3.medium23.09 GBSmall production
cache.r6g.large213.07 GBProduction caching
cache.r6g.xlarge426.32 GBLarge datasets
cache.r6g.4xlarge16105.81 GBHigh-memory workloads

Graviton (r6g, r7g) nodes are ~20% cheaper than Intel equivalents.

Terminal window
# Cluster mode disabled (1 primary + 2 replicas)
aws elasticache create-replication-group \
--replication-group-id my-redis \
--replication-group-description "Production cache" \
--engine redis \
--engine-version 7.0 \
--node-type cache.r6g.large \
--num-cache-clusters 3 \
--automatic-failover-enabled \
--multi-az-enabled \
--at-rest-encryption-enabled \
--transit-encryption-enabled \
--cache-subnet-group-name my-cache-subnets \
--security-group-ids sg-redis

The most common pattern — the application manages the cache:

import redis, json
r = redis.Redis(host='my-redis.abc.ng.0001.use1.cache.amazonaws.com', port=6379)
def get_user(user_id):
# 1. Check cache
cached = r.get(f"user:{user_id}")
if cached:
return json.loads(cached) # cache hit
# 2. Cache miss — query database
user = db.query("SELECT * FROM users WHERE id = %s", user_id)
# 3. Store in cache with TTL
r.setex(f"user:{user_id}", 3600, json.dumps(user)) # 1 hour TTL
return user
ProsCons
Only caches data that’s actually requestedFirst request for each key is slow (cache miss)
Cache failures don’t break the appData can become stale (until TTL expires)
Simple to implementApplication must handle both cache and DB

Write to cache and database at the same time:

def update_user(user_id, data):
# Write to DB
db.execute("UPDATE users SET ... WHERE id = %s", user_id, data)
# Write to cache
r.setex(f"user:{user_id}", 3600, json.dumps(data))
ProsCons
Cache is always up to dateEvery write hits both cache and DB (slower writes)
No stale dataCache fills with data that may never be read

Write to cache first, then asynchronously write to the database:

App ──write──► Cache ──async──► Database

Very fast writes, but risk of data loss if the cache fails before the DB write. Rarely used with ElastiCache — more common with specialized caching layers.

The hardest part of caching. Strategies:

StrategyHow It WorksTrade-off
TTL-basedCache expires after N secondsSimple; data can be stale for up to TTL
Event-basedDelete cache when data changesConsistent; requires invalidation logic
Version keysuser:123:v5 — increment version on changeNo delete needed; old versions expire via TTL
# Store session in Redis (instead of server memory)
r.setex(f"session:{session_id}", 1800, json.dumps({
'user_id': 'user_123',
'role': 'admin',
'login_time': '2026-02-16T10:00:00Z'
}))
# Any app server can read the session
session = json.loads(r.get(f"session:{session_id}"))

Redis-backed sessions work across multiple app servers — critical for load-balanced applications.

# Add scores
r.zadd("leaderboard", {"alice": 950, "bob": 870, "charlie": 1020})
# Top 10 players
top_10 = r.zrevrange("leaderboard", 0, 9, withscores=True)
# [('charlie', 1020), ('alice', 950), ('bob', 870)]
# Player's rank
rank = r.zrevrank("leaderboard", "alice") # 1 (0-indexed)

Sorted sets maintain order automatically — O(log N) for inserts and rank lookups.

def is_rate_limited(user_id, limit=100, window=60):
key = f"ratelimit:{user_id}"
current = r.incr(key)
if current == 1:
r.expire(key, window) # set TTL on first request
return current > limit
# Publisher
r.publish("notifications", json.dumps({
'user_id': 'user_123',
'message': 'Your order has shipped'
}))
# Subscriber
pubsub = r.pubsub()
pubsub.subscribe("notifications")
for message in pubsub.listen():
if message['type'] == 'message':
data = json.loads(message['data'])
send_push_notification(data)
PracticeHow
Network isolationPlace in private subnets. Allow only app security groups.
Encryption at restEnable at-rest-encryption-enabled (KMS)
Encryption in transitEnable transit-encryption-enabled (TLS)
AuthEnable Redis AUTH token (password) or IAM authentication
No public accessElastiCache is VPC-only — no public endpoints
ElastiCache (Redis)DynamoDB DAX
TypeGeneral-purpose cacheDynamoDB-specific cache
ManagesYour caching logicTransparent (no code changes)
Data sourceAny (RDS, APIs, DynamoDB, etc.)DynamoDB only
Use caseFlexible caching, sessions, leaderboardsAccelerate DynamoDB reads

If you only need to cache DynamoDB reads, DAX is simpler. For everything else, use ElastiCache.

  • ElastiCache Redis is a managed in-memory store for caching, sessions, leaderboards, rate limiting, and pub/sub.
  • Cache-aside is the default pattern: check cache → miss → query DB → store in cache.
  • Set TTLs on all cached data to prevent staleness. Event-based invalidation for consistency-critical data.
  • Use cluster mode enabled for large datasets and high write throughput. Use cluster mode disabled for simpler setups.
  • Place ElastiCache in private subnets with encryption at rest and in transit.
  • Choose Redis over Memcached in almost all cases — richer data structures, persistence, replication.