Part 9 of Learn AWS from Scratch

Caching with ElastiCache

Why reading from the database on every request is slow and expensive, how an in-memory cache solves it, the Valkey, Redis and Memcached engines, the ways to keep data fresh, and a hands-on where you build a cache and a leaderboard.

In this article
  1. What a cache is
  2. Choosing an engine
  3. How your application uses it
  4. More than a cache
  5. Security and monitoring
  6. Hands-on: a cache and a leaderboard
  7. Summary
  8. Test yourself

In part eight we built a strong database. But imagine your store's home page shows the same 20 products to every visitor. Thousands of visitors means the database runs the same query thousands of times and returns the same answer.

The solution is simple: keep the answer somewhere fast, and go back to it instead of asking the database every time. That's a cache.

What a cache is

A cache is a temporary copy of data that takes time or effort to fetch. Memory is far faster than disk, so an answer usually arrives in under a millisecond. That gives you:

  • Higher speed for the user.
  • Less load on the database, so you can serve more visitors with a smaller one.

The key rule: a cache isn't the source of truth. If you lose all of it, your application gets a bit slower, but no important data is lost.

ElastiCache is a managed cache service: AWS handles the servers, patches and failover. Unlike RDS, though, you have to change your application's code, because the application decides what to store and when to read it.

Choosing an engine

Valkey and Redis OSS Memcached
Data types Strings, lists, sets, sorted sets and more Simple values
Copies and failover Read replicas, Multi-AZ and automatic failover No copies in a cluster you design yourself
Persistence Snapshots you can restore from None; data lives only in memory
Scaling Partitioned data with replicas Partitioned across nodes, and multi-threaded
Good for Most cases: caching, sessions, leaderboards A simple cache where losing data doesn't hurt

You have two ways to run it:

Serverless A cluster you design
Setup Little more than a name You choose node types, partitions and replicas
Scaling Automatic You plan it yourself
Billing Data size and operations Per node, per hour
Good for Irregular load, and the easiest start Steady load and tight cost control

How your application uses it

Lazy loading

This is the most common approach, also called cache-aside: your application asks the cache first, goes to the database if the answer isn't there, then stores the answer for next time.

Application Cache Database 1. Is the answer cached? Yes: instant answer The database did no work No, it isn't there 2. Read from the database The answer 3. Store it with a TTL
The application asks the cache first. If the answer is there the request is done; if not, it reads from the database and stores the answer for next time.

In code, it looks roughly like this:

Python
def get_product(product_id):
    key = f"product:{product_id}"

    cached = cache.get(key)
    if cached:
        return json.loads(cached)

    product = db.fetch_product(product_id)
    cache.set(key, json.dumps(product), ex=300)  # Valid for 5 minutes
    return product
  • Pros: it stores only what's actually requested, and if the cache fails the application carries on from the database.
  • Cons: the first request is slow, and data can be stale until it expires.

Write-through

Whenever you write to the database, you write to the cache as well.

  • Pros: the cache is always current.
  • Cons: an extra write every time, and the cache can fill with data nobody reads.

Many applications combine the two: lazy loading, plus updating the cache on writes for important data.

TTL and eviction

Each key has a lifetime (TTL) after which it disappears, so stale data doesn't stay forever. The right value depends on the data:

Data A sensible TTL Why
Home page and lists 30 to 60 seconds Even a short TTL removes most of the load
Product details Minutes It's fine if it lags slightly
User session The session length, such as 30 minutes Renewed with activity
Final balance or stock Don't cache it It has to be accurate

When memory fills up, the cache evicts some keys, usually the least used. If this happens a lot, your cache is too small.

More than a cache

Sessions: remember the table in part seven? When you keep sessions in ElastiCache, any server can read them, so users don't get signed out when their server disappears.

Leaderboards: a sorted set keeps items ordered by score and gives you the top entries instantly, instead of sorting millions of rows in the database.

Rate limiting: an INCR counter with a TTL counts each user's requests per minute and blocks anyone over the limit.

Security and monitoring

  • Network: by default the cache is reachable only from inside your network, so let its security group accept traffic only from the servers' security group.
  • Encryption: turn it on in transit and at rest; it's always on with Serverless.
  • Access: use users and permissions or IAM authentication on Valkey and Redis, and SASL on Memcached.

In CloudWatch, watch these metrics:

Metric What it tells you
CacheHitRate How many requests found their answer in the cache. If it's low, review what you store and your TTLs
Evictions How many keys were pushed out by lack of memory
Memory usage Whether you need a bigger cache

Hands-on: a cache and a leaderboard

We'll use your server from part three. From CloudShell, create a security group that accepts traffic from the server's security group. Serverless uses ports 6379 and 6380:

Bash
aws ec2 create-security-group --group-name cache-sg \
  --description "Cache access" --query GroupId --output text

aws ec2 authorize-security-group-ingress --group-id sg-CACHE-GROUP \
  --protocol tcp --port 6379-6380 --source-group sg-SERVER-GROUP

Then create the cache using the ID you got back:

Bash
aws elasticache create-serverless-cache \
  --serverless-cache-name series-cache \
  --engine valkey \
  --security-group-ids sg-CACHE-GROUP

aws elasticache describe-serverless-caches \
  --serverless-cache-name series-cache \
  --query "ServerlessCaches[0].[Status,Endpoint.Address]" --output table

When the status shows available, sign in to the server through EC2 Instance Connect and connect:

Bash
sudo dnf install -y valkey
valkey-cli -h YOUR-CACHE-ENDPOINT --tls -c -p 6379

Try a TTL:

Output
SET product:1 "Keyboard"
GET product:1

SET offer:today "20% off" EX 30
TTL offer:today

Repeat TTL a few times and watch the countdown. After 30 seconds, GET offer:today returns (nil).

Now a leaderboard:

Output
ZADD leaderboard 120 sara 300 omar 90 lina
ZINCRBY leaderboard 250 lina
ZREVRANGE leaderboard 0 2 WITHSCORES

You'll see lina in first place with 340 points, with no sorting on your side. Leave with exit.

Bash
aws elasticache delete-serverless-cache --serverless-cache-name series-cache

aws ec2 delete-security-group --group-id sg-CACHE-GROUP

Summary

  • A cache is a fast, temporary copy, not the source of truth.
  • Start with Valkey, and with Serverless if your load is irregular or you want an easy start.
  • Lazy loading is the most common approach, and write-through keeps the cache current.
  • The TTL sets how much staleness you accept, and some data shouldn't be cached at all.
  • It also works for sessions, leaderboards and rate limiting.

Test yourself

Before you move on, try these questions to check you've got this part. Each one is a practical scenario, and the explanation appears once you answer.

Question 1 of 5

A store's home page runs the same query on RDS thousands of times a minute, and the database's CPU is high. The data changes only a few times an hour. What gives the fastest responses and takes the most load off the database?

Show the answer

Correct answer: C

The answer rarely changes, so the database doesn't need to work it out again each time. Memory answers in under a millisecond, and even a short TTL removes most of the load.

  • A: The standby doesn't serve reads, so the load stays the same.
  • B: This buys capacity, but the same query still runs every time.
  • D: Redshift is for large reports, not for answering a page quickly.

Review: What a cache is in this part, and Caching strategies in the AWS docs.

Question 2 of 5

A mobile game shows the top 100 players live. The leaderboard must keep working if a cache node fails, with automatic failover. Which option fits?

Show the answer

Correct answer: A

A sorted set keeps players ordered by score and returns the top entries instantly, and Valkey supports replicas with automatic failover.

  • B: Memcached stores simple values, and it has no copies in a cluster you design.
  • C: Sorting millions of rows on every request puts heavy load on the database.
  • D: S3 isn't built for a file that changes constantly and must be read live.

Review: Choosing an engine in this part, and Comparing engines in the AWS docs.

Question 3 of 5

A store uses lazy loading with a one-hour TTL, so customers can see an old price for up to an hour after it changes. Prices must now update within a minute, while keeping the benefit of the cache. What should the team do?

Show the answer

Correct answer: D

Lazy loading alone leaves data stale until it expires. Handling the cache on each write keeps it current, and a shorter TTL limits the damage if a write is ever missed.

  • A: This solves staleness, but brings all the load back to the database.
  • B: This makes the problem worse.
  • C: The stale value comes from the cache, not from the database.

Review: Write-through in this part, and Caching strategies in the AWS docs.

Question 4 of 5

An application fills its cache at startup, giving every key the same TTL. At the end of that period, the database gets a sharp spike in load, and the pattern repeats. What's the simplest fix?

Show the answer

Correct answer: B

When keys expire together, requests for all of them go to the database at the same moment. Randomizing the TTL spreads those expiries over time.

  • A: The problem is in the database at the moment of expiry, not in the cache's size.
  • C: Keys would never refresh, so stale data would stay.
  • D: This protects the cache from failures, and the keys still expire together.

Review: TTL and eviction in this part, and Best practices for TTLs and jitter in the AWS docs.

Question 5 of 5

A team sees the Evictions metric rising and CacheHitRate falling on its cache. Which two actions address this? (Choose two.)

Show the answer

Correct answer: A + C

Evictions mean the cache is full and is pushing keys out, which turns into misses. Either make room with more memory, or stop filling it with what nobody reads.

  • B: This helps the database, but it doesn't change the cache's memory.
  • D: Encryption has nothing to do with evictions, and you'd lose its protection.
  • E: S3 is far slower, and this removes the point of having a cache.

Review: Security and monitoring in this part, and ElastiCache for e-commerce in the AWS docs.

You now know RDS, Aurora and ElastiCache, and AWS has many more. In part ten we answer the question that confuses everyone: which database should you choose?