The idea
Some answers are slow to get: the database may have to read its disk and do real work. A cache is a small, fast store in memory that keeps copies of answers, so asking again is quick.
Cache-aside, step by step
A shop page needs the price of tea, so the app runs get_price("tea") and asks the cache first. The cache is empty, so cache.get returns None. That is a cache miss: no copy yet.
On a miss the app does the slow work: db.load("tea") asks the database, which finds the row and sends back $3. This is the trip the cache will save next time.
Before replying, cache.set("tea", "$3", ex=60) stores a copy for 60 seconds. Then the app returns $3. This pattern is called cache-aside: the app looks in the cache first and fills it itself on a miss.
A second visitor asks for tea. This time cache.get finds $3, so the app returns it at once and never touches the database. That is a cache hit: the more hits, the less work for the database.
Keeping copies fresh
Then another program changes the price to $4 straight in the database. The cache is not told. The next read is a hit and returns $3: stale data, an old copy that no longer matches the truth.
Every copy has a time to live (TTL). ex=60 tells Redis to delete it 60 seconds after it was set. The next read misses and loads the fresh $4. A longer TTL means more hits, but staler data.
When the app itself changes the price, it can do better: save $5 in the database, then delete the cached copy, so the next read loads $5. Phil Karlton called cache invalidation one of the two hard things in computer science.
Full caches and layers
Later the cache is full: three copies, tea, cake and pie, and tea was just read. Jam misses, so one copy must go. LRU, least recently used, picks cake: it has waited longest.
The same idea repeats at every layer. Your browser keeps copies of files (Cache-Control: max-age). A CDN keeps copies on servers near you. The app keeps Redis. The database keeps busy parts of its disk in memory.
What happens
;; step 1/10 · idea
cache a small, fast store that keeps copies
here: Redis, keys and values in memory
database the source of truth, slower to ask
main memory read about 100 ns
new disk spot (seek) about 8,000,000 ns (8 ms)
cache now [ empty | empty | empty ]
The figure's cache has exactly three slots so eviction is easy to see. A real Redis is limited by memory (maxmemory), and by default it refuses new writes when full (noeviction) unless you choose a policy such as allkeys-lru. Redis does not track exact LRU order: it samples a few keys and evicts the oldest of the sample, which comes close to true LRU. The figure shows exact LRU.