A cache’s hit rate is not the most important metric to track; its miss rate is.

Let’s see a cache in action, specifically Redis, a popular in-memory data store often used as a cache. Imagine we have a web application that frequently needs to fetch user profile data. Instead of hitting the main database every time, we can cache this data in Redis.

Here’s a simplified Python snippet using redis-py:

import redis

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

def get_user_profile(user_id):
    cache_key = f"user_profile:{user_id}"
    # Try to get data from cache
    profile_data = r.get(cache_key)

    if profile_data:
        print(f"Cache HIT for user {user_id}")
        return json.loads(profile_data)
    else:
        print(f"Cache MISS for user {user_id}")
        # Data not in cache, fetch from primary data store (e.g., database)
        profile_data_from_db = fetch_from_database(user_id)
        if profile_data_from_db:
            # Store in cache for next time, with an expiration (TTL)
            r.setex(cache_key, 3600, json.dumps(profile_data_from_db)) # Cache for 1 hour
            return profile_data_from_db
        else:
            return None

# Simulate fetching from a database
def fetch_from_database(user_id):
    print(f"Fetching user {user_id} from database...")
    # In a real app, this would query a database
    return {"user_id": user_id, "name": f"User {user_id}", "email": f"user{user_id}@example.com"}

# Example usage
import json
print(get_user_profile(123))
print(get_user_profile(123)) # This will be a cache hit
print(get_user_profile(456))

When get_user_profile(123) is called the first time, r.get(cache_key) will return None, triggering a "Cache MISS." The application then fetches the data from the database, serializes it to JSON, and stores it in Redis using r.setex with a Time-To-Live (TTL) of 3600 seconds (1 hour). The next call, get_user_profile(123), will find the data in Redis, print "Cache HIT," and return it directly. get_user_profile(456) will be another miss.

The problem this solves is performance. Databases are typically much slower and more resource-intensive than in-memory caches. By storing frequently accessed data in a cache, we drastically reduce the load on the primary data store and improve application response times.

Internally, Redis (and most key-value caches) uses a hash table to store keys and their associated values. When you GET a key, Redis performs a hash lookup. If the key is present, it’s a hit; if not, it’s a miss. The SETEX command is a compound command that sets a key with a value and an expiration time.

The exact levers you control are:

  • Key Naming Strategy: How you structure your cache keys (f"user_profile:{user_id}") directly impacts whether a lookup succeeds or fails. Consistent naming is crucial.
  • Serialization Format: JSON, MessagePack, Protocol Buffers – the choice affects storage size and parsing speed.
  • Expiration (TTL): How long data stays in the cache. Too short, and you miss opportunities for hits; too long, and you risk serving stale data.
  • Eviction Policy: When the cache reaches its memory limit, what gets removed? Least Recently Used (LRU) is common.
  • Cache Size/Memory Limit: How much RAM you allocate to the cache.

While hit rate tells you how often you successfully found data, the miss rate tells you how often you failed to find data, which is the direct measure of work that still had to be done by your slower, primary system. A high hit rate (e.g., 99%) sounds great, but if your cache is small and evicting items too quickly, you might still be experiencing a significant number of misses for critical, frequently requested data. Conversely, a lower hit rate might be acceptable if the misses are for data that is rarely accessed or computationally expensive to generate. The miss rate directly correlates to the load on your backend services. If your cache miss rate suddenly jumps, it’s an immediate red flag indicating increased load on your database or API.

The next concept you’ll encounter is cache invalidation, which is how you ensure the data in your cache remains up-to-date with the source of truth.

Want structured learning?

Take the full Caching-strategies course →