Cache Me if You Can: Caching Simplified

AKRAM BOUTZOUGA
5 min readOct 30, 2024

--

Imagine you run a coffee shop called Byte Brew. Every day, you get hundreds of orders for the same popular drinks. You notice that some customers order the same coffee every day, and you keep making each drink from scratch, even though you already know what they want. What if you could just pre-make these popular drinks to serve them faster? This pre-preparation is what caching does in the world of software. Caching “remembers” data to save time and resources, just like a coffee shop saving time by preparing popular drinks in advance.

The Basics of Caching

In our tale, meet the protagonist: Cache the Memory Keeper. Cache has a mission: to speed things up and save resources wherever possible. He does this by storing results of common requests so they can be accessed faster the next time. Here’s how Cache works in different scenarios:

  1. Browser Cache (Cache’s first job): When you visit a website, your browser keeps a “mini-notebook” of images, scripts, and stylesheets so the next time you return, it doesn’t need to re-download everything. Just like taking a coffee to-go that’s ready when you return, a browser cache speeds up your return visits.
  2. Server Cache (Cache’s promotion): This is when Cache takes on bigger responsibilities, like storing frequently accessed data from a database. Imagine the server is like a giant library, and Cache decides to keep a mini-library of the most popular books (data) right by the front desk so patrons can get them faster.

Real-World Example: Many websites store popular user profile information, like names or profile pictures, in a server cache so that users don’t wait each time they access their accounts.

Caching Strategies — Cache’s Toolbox

Cache has learned a few tricks over the years to balance his memory load. Here are some of the strategies he uses:

  1. Time-to-Live (TTL): Cache sets a timer for each item he stores, similar to how coffee might go stale if left too long. TTL ensures data expires after a set period. For example, if Cache stores user login data for 15 minutes, users won’t have to log in again if they return within that time.
  2. Lazy Loading: Sometimes Cache is a bit lazy (by design). He won’t store a result until it’s requested at least once, saving memory by not caching data no one uses. Lazy loading works like preparing a coffee only when a customer actually orders it, rather than pre-making it and risking waste.
  3. Write-Through and Read-Through Caching: Cache is diligent in some cases, updating data whenever a change is made. Think of it like a recipe notebook; every time the recipe is improved, Cache updates the stored recipe immediately so it’s always accurate.

Technical Example: Python’s functools.lru_cache is a great way to implement lazy loading and caching in code. Here’s an example of how Cache uses lru_cache to save time:

from functools import lru_cache
import time

@lru_cache(maxsize=5) # Cache the 5 most recent results
def calculate_square(n):
time.sleep(2) # Simulate a time-consuming calculation
return n * n

print(calculate_square(4)) # Takes 2 seconds, calculates and caches
print(calculate_square(4)) # Fetches from cache, almost instant

Types of Caching — Cache in Action in Different Scenarios

Cache wears many hats, depending on the job. Here’s how Cache shows up in different parts of the software world:

  1. Content Delivery Network (CDN): Cache works on a global scale here, making a web of servers around the world that store copies of popular static files. When users from different locations access these files, they’re served locally, avoiding delays from long-distance server requests.
  2. Application Cache: Cache takes the form of memory storage tools like Redis or Memcached in applications. Imagine Cache is running a coffee shop that serves millions of drinks daily, and each drink’s recipe is stored in Redis (his trusty recipe book) to make sure he gets it right every time.

Technical Example: Let’s set up a Redis cache to store user data. First, install Redis on your system, then run this code:

import redis

# Connect to Redis
client = redis.StrictRedis(host='localhost', port=6379, db=0)

def get_user_info(user_id):
if client.exists(user_id):
print("Fetching data from Redis cache")
return client.get(user_id)

# Simulate fetching data from a database
print("Fetching data from database")
data = f"User data for {user_id}"
client.setex(user_id, 300, data) # Cache data with a TTL of 5 minutes
return data

print(get_user_info("user_123")) # Fetches and caches
print(get_user_info("user_123")) # Fetches from Redis cache

Cache Invalidation — Cache’s Hardest Task

Cache has a problem: he can’t keep stale data. Knowing when to refresh or discard old data is crucial. There’s nothing worse than making a user wait only to give them outdated information.

  1. Manual Invalidation: This is like Cache’s “refresh button,” used when data is definitely out-of-date, and Cache manually clears the stored result.
  2. Automatic Invalidation with TTL: Cache’s personal assistant, the TTL timer, helps by automatically invalidating data after a set time. It’s like throwing away coffee after a certain freshness window to ensure quality.

Real-World Example: When a user logs out, Cache manually clears the session data from memory to ensure no one else can access it if they use the same browser.

Measuring Cache Effectiveness

Cache loves feedback! To check how well he’s doing, he uses Cache Hit and Cache Miss statistics:

  • Cache Hit: When Cache successfully serves data from memory. More hits mean he’s doing his job well.
  • Cache Miss: When Cache can’t serve data from memory and has to retrieve it from the original source, costing more time.

Example: Python’s lru_cache decorator has a cache_info() method, which provides stats on cache hits, misses, and current cache size.

calculate_square.cache_info()  # Shows hit/miss statistics

Conclusion:

As we’ve seen, caching is like giving your application a superpowered memory, where it recalls common data and serves it quickly, just like a fast-lane barista or a well-organized librarian. Cache reduces wait times, minimizes repeated work, and ensures that frequently needed information is just an instant away. By carefully choosing caching strategies — like setting expiration times, using popular caching tools like Redis, and tracking cache hits and misses — you can design applications that feel fast, responsive, and efficient.

--

--

AKRAM BOUTZOUGA
AKRAM BOUTZOUGA

Written by AKRAM BOUTZOUGA

Junior Calisthenics Engineer, Ai Enthusiast. Coding and Flexing! 💻💪

No responses yet