Cache-Aside and Read-Through
Read strategies decide who fills the cache when a request misses. Cache-aside lets the app fill the cache, and read-through lets the cache fill itself.
Cache-aside, step by step
The app does the filling here. A repeated key shows the source switch from database to cache.
db = {"page-1": "Home", "page-2": "Help"}
cache = {}
def cache_aside(key):
if key in cache:
print(key, "from cache")
return cache[key]
print(key, "from database")
cache[key] = db[key]
return db[key]
for key in ["page-1", "page-1", "page-2", "page-1"]:
cache_aside(key)Read-through fills itself
The app never touches the database here. On a miss, the cache loads the value on its own.
db = {"page-1": "Home", "page-2": "Help"}
cache = {}
def read_through(key):
if key in cache:
print(key, "from cache")
return cache[key]
print(key, "cache filled itself from database")
cache[key] = db[key]
return db[key]
for key in ["page-1", "page-1", "page-2", "page-1"]:
read_through(key)Same requests, same reads
Both strategies face the same 5 requests. The database read counts match, because only the filler differs.
db = {"a": 1, "b": 2, "c": 3}
requests = ["a", "b", "a", "c", "a"]
def run(fill):
cache = {}
reads = 0
for key in requests:
if key not in cache:
reads += 1
cache[key] = fill(key)
return reads
print("cache-aside database reads:", run(lambda k: db[k]))
print("read-through database reads:", run(lambda k: db[k]))Example
db = {"song-1": "Blue", "song-2": "Red", "song-3": "Gold"}
requests = ["song-1", "song-2", "song-1", "song-3", "song-2", "song-1"]
cache_a = {}
for key in requests:
if key in cache_a:
print("cache-aside", key, "from cache")
else:
print("cache-aside", key, "from database")
cache_a[key] = db[key]
cache_b = {}
for key in requests:
if key in cache_b:
print("read-through", key, "from cache")
else:
print("read-through", key, "cache filled itself")
cache_b[key] = db[key]Key points
- Cache-aside: the app checks the cache, reads the database on a miss, then stores the answer in the cache.
- Read-through: the app asks the cache only, and the cache reads the database itself on a miss.
- Use cache-aside to control exactly which answers the app stores.
- Use read-through to keep the database reading code in one place, inside the cache.
In this example, both strategies serve the same 6 requests with the same pattern of sources. Each one reads the database 3 times and the cache 3 times, so the real choice is who writes the filling code.
Note
both strategies end the same way, with the next request for that key scoring a hit.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
In which strategy does the app itself read the database on a miss and then store the answer in the cache?