Cache penetration and negative caching

Caching and Redis Mid-level Python 3.13+ PostgreSQL 17+ Reviewed By Best Latest Apps

Predict the output

A missing id is looked up twice. How many database reads?

Python 3.13
from typing import cast

import redis

r = redis.Redis(decode_responses=True)
DB: dict[int, str] = {}
reads = 0


def find(pid: int) -> str | None:
    global reads
    hit = cast(str | None, r.get(f"p:{pid}"))
    if hit is not None:
        return None if hit == "" else hit
    reads += 1
    val = DB.get(pid)
    r.set(f"p:{pid}", val or "", ex=30)
    return val


find(999)
find(999)
print(reads)

Options
Hint 1 of 1

What does the first call store?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A 1

Correct. The first miss stores an empty marker; the second lookup stops at the cache.

Caching 'not found' as an empty marker means the next lookup is answered by Redis. Without it, every request for a missing id goes to the database.

Why not the others?
  • B 2. Without the marker it would be 2.
  • C 0. The first lookup has to ask the database.
  • D A KeyError. DB.get returns None for missing ids.

30-second answer

Cache the absence: store a short-lived 'not found' marker for missing ids, so repeated lookups for the same id stop at the cache. For random ids that never repeat, put a Bloom filter of existing ids in front: it says 'definitely not present' with no false negatives, so you skip the database for most invalid ids. Add input validation and rate limits per client too.

Practise saying it · 30 s. No recording, just a timer

Defend against cache penetration.

Say your answer out loud, then check which of these points you covered:

  • Cache the absence briefly
  • Bloom filter: no false negatives
  • Validate ids
  • Rate-limit clients

Deep dive

Keep negative TTLs short so newly created items appear quickly; delete the marker on create.

Bloom filters have false positives (a few invalid ids get through) but never false negatives.

Redis Stack and modules offer Bloom filters; a plain bitset works too.

Validate id format first; malformed ids shouldn't reach any store.

Common mistakes

  • Long-lived not-found markers that hide new rows.
  • No limit on how many distinct missing ids one client can request.
  • Rebuilding the Bloom filter so rarely that new items are rejected.

Senior take & follow-ups

Name negative caching, Bloom filters with their error direction, and validation and rate limits.

Follow-up questions

Think of your answer first, then open the hint.

  1. Can a Bloom filter say 'present' wrongly?

    Show hint

    Yes, with a tunable false-positive rate; never the reverse.

  2. How do you remove from a Bloom filter?

    Show hint

    You can't in a standard one; rebuild or use a counting variant.

Suggest a fix if something here is wrong or out of date.