| Users / Traffic | Cache Size | Cache Hit Rate | Latency | Cache Nodes | Eviction Policy |
|---|---|---|---|---|---|
| 100 users | Small (MBs) | High (~90%) | Low (~1ms) | 1 node | LRU or TTL |
| 10K users | Medium (GBs) | High (~85-90%) | Low (~1-2ms) | 3-5 nodes | LRU + TTL |
| 1M users | Large (10s GBs) | Moderate (~80%) | Low (~2-3ms) | 10-20 nodes, sharded | LRU + TTL + LFU |
| 100M users | Very Large (100s GBs to TBs) | Moderate (~75-80%) | Low (~3-5ms) | 50+ nodes, sharded + replication | Advanced eviction + tiered caching |
Distributed caching (Redis, Memcached) in HLD - Scalability & System Analysis
At small scale, the cache easily handles requests with a single node. As traffic grows beyond 10K users, the first bottleneck is the cache node memory and CPU. A single Redis or Memcached instance can handle around 100K operations per second but limited memory (~tens of GBs). When cache size or QPS grows beyond this, the node becomes CPU or memory bound.
Also, network bandwidth between app servers and cache nodes can become a bottleneck at very high QPS (millions of ops/sec).
- Horizontal scaling: Add more cache nodes and shard keys across them to distribute load and memory usage.
- Replication: Use read replicas for read-heavy workloads to increase throughput and availability.
- Eviction policies: Use LRU, LFU, TTL to keep cache size manageable and remove stale data.
- Client-side sharding: Distribute keys at the client or proxy layer to avoid single node overload.
- Tiered caching: Combine in-memory cache with local caches or slower caches for large datasets.
- Network optimization: Use fast networks and colocate cache nodes near app servers to reduce latency.
- Monitoring and autoscaling: Track cache hit rates, latency, and resource usage to scale nodes dynamically.
- At 1M users, assume 10 requests per second per user -> 10M QPS total.
- Redis single node handles ~100K ops/sec -> need ~100 nodes for caching all requests.
- Cache size depends on data size; e.g., 1MB per user cached data -> 1TB total cache needed.
- Network bandwidth: 100 nodes x 1 Gbps each -> 100 Gbps total bandwidth needed.
- Storage cost: RAM is expensive; consider cost vs benefit of caching vs DB load.
Start by explaining what distributed caching is and why it helps reduce database load and latency.
Discuss scaling limits of a single cache node (memory, CPU, network).
Explain horizontal scaling with sharding and replication.
Mention eviction policies and cache consistency challenges.
Use numbers to justify when to add nodes or optimize network.
Your database handles 1000 QPS. Traffic grows 10x to 10,000 QPS. What do you do first?
Answer: Add a distributed cache layer (Redis/Memcached) to offload read requests from the database, reducing DB load and latency. Then monitor cache hit rate and scale cache nodes as needed.
Practice
Solution
Step 1: Understand the role of distributed cache
Distributed caches store frequently accessed data in fast memory to reduce the number of database queries.Step 2: Identify the main benefit
This reduces the load on the database and speeds up data retrieval for repeated requests.Final Answer:
To reduce database load by storing frequently accessed data in memory -> Option AQuick Check:
Distributed cache reduces DB load = C [OK]
- Thinking cache permanently stores all data
- Confusing cache with database backup
- Assuming cache replaces the database
Solution
Step 1: Recall Redis command for setting data
Redis uses the commandSET key valueto store a value under a key.Step 2: Verify other options
GETretrieves data,STOREandPUTare not valid Redis commands.Final Answer:
SET key value -> Option AQuick Check:
Redis set command = SET key value [OK]
- Confusing GET with SET
- Using non-existent commands like STORE or PUT
- Mixing Redis commands with SQL syntax
cache.set('user:1', 'Alice')
name = cache.get('user:1')
print(name)What will be printed?
Solution
Step 1: Analyze the cache set operation
The key 'user:1' is set with the value 'Alice' in the cache.Step 2: Analyze the cache get operation
Retrieving 'user:1' returns the stored value 'Alice', which is then printed.Final Answer:
'Alice' -> Option BQuick Check:
Set then get returns stored value = 'Alice' [OK]
- Expecting key name instead of value
- Assuming None if not careful with key format
- Thinking it causes an error without context
Solution
Step 1: Understand Memcached key expiration
Memcached keys have a TTL (time to live). If TTL is too low, keys expire quickly causing cache misses.Step 2: Eliminate incorrect options
Memcached supports key-value storage, does not depend on database status, and does not use SQL queries.Final Answer:
The cache keys are expiring too quickly due to a low TTL setting -> Option CQuick Check:
Low TTL causes cache misses = A [OK]
- Thinking Memcached lacks key-value support
- Assuming database status affects cache directly
- Confusing Memcached with SQL databases
Solution
Step 1: Identify concurrency challenges in distributed cache
When multiple servers update the same key, race conditions can cause inconsistent data.Step 2: Choose atomic update methods in Redis
Redis supports transactions and Lua scripts to ensure updates happen atomically, preventing conflicts.Step 3: Evaluate other options
Allowing uncoordinated updates risks inconsistency; disabling caching reduces performance; Memcached lacks built-in atomic scripting.Final Answer:
Use Redis transactions or Lua scripts to perform atomic updates -> Option DQuick Check:
Atomic updates ensure consistency = D [OK]
- Ignoring concurrency causing stale data
- Thinking Memcached handles concurrency automatically
- Disabling cache unnecessarily reduces speed
Ready to prove it?
Pass the test and this pattern moves unknown
