Skip to main content

Cache-aside

Stage 7 · Orbital Maneuvering

Apollo's search service queries flight schedules repeatedly. Because flight timetables change infrequently, repeatedly querying PostgreSQL wastes database CPU and saturates connection pools.

The cache-aside pattern introduces an in-memory key-value store (Redis) to absorb repetitive read traffic.


Decision tree: the 4 cache-aside branches​

Diagram SC-02 — the four observable branches of cache-aside: Cache Hit, Cache Miss, Database Error, and Cache Outage.

  • Branch 1: Cache Hit:
    • Key exists in Redis. Returns response immediately (<5ms). Database is never queried.
  • Branch 2: Cache Miss:
    • Key absent. Reads from PostgreSQL, writes result to Redis with a TTL (e.g. EX 300), and returns response.
  • Branch 3: Database Failure on Miss:
    • If the database query times out, decide whether to serve stale data (fail-open) or return HTTP 503 (fail-closed).
  • Branch 4: Cache Outage (Cache Stampede Hazard):
    • If Redis crashes, bypassing the cache directs 100% of read queries directly onto PostgreSQL, potentially collapsing the database under a stampede.

TTL policies by data volatility​

  • Static route data (Airport codes, flight numbers): Long TTL (24 hours).
  • Flight schedules: Moderate TTL (5 minutes).
  • Seat inventory & live availability: Zero cache (query database authoritative locks directly).

Evidence and limits​

  • 1. Redis hit/miss ratio:
    kubectl exec -n apollo-airlines-apps deploy/redis -- \
    redis-cli INFO stats | grep -E "keyspace_hits|keyspace_misses"
  • 2. Verify key TTL expiration:
    kubectl exec -n apollo-airlines-apps deploy/redis -- \
    redis-cli TTL "route:JFK:LHR:2024-10-01"
  • 3. Header verification: Confirm response headers indicate cache state:
    curl -v http://localhost:30083/api/search?departure=JFK&arrival=LHR 2>&1 | grep -i "x-cache"