Implementing Caching Logic

1. Implementing Cache-Aside Pattern

Example: Read-through

public User get(long id) {
    var cached = cache.get(id);
    if (cached != null) return cached;
    var user = repo.findById(id).orElseThrow();
    cache.put(id, user);
    return user;
}

2. Implementing Write-Through Cache

AspectDetail
WriteTo cache and DB synchronously
ReadFrom cache (always fresh)
ProStrong consistency
ConWrite latency higher

3. Implementing Write-Behind Cache

AspectDetail
WriteTo cache; async to DB
ProLow write latency, batching
ConData loss risk on crash
UseMetrics, analytics, non-critical

4. Implementing Cache Invalidation Logic

StrategyDetail
TTLTime-based; eventual consistency
Explicit on writeEvict matching keys
Event-drivenInvalidate on domain event
Versioned keyBump version on data change
Warning: Cache invalidation is one of the two hard problems in CS — design for staleness tolerance.

5. Implementing In-Memory Caching

Example: Caffeine

Cache<Long, User> cache = Caffeine.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(Duration.ofMinutes(10))
    .recordStats()
    .build();
User u = cache.get(id, repo::findById);

6. Implementing Distributed Caching

SystemTrait
RedisSingle-master + replicas; rich types
MemcachedSimple key/value; multi-threaded
HazelcastEmbedded, JVM
Apache IgniteCompute + cache

7. Implementing Cache Hierarchies

Request → L1 (in-memory, <1ms) → miss → L2 (Redis, ~1-5ms) → miss → DB
                                  ↑                              ↓
                            backfill on miss ← - - - - - - - - - ┘
  

8. Implementing Cache Warming

TriggerDetail
App startupLoad hot keys
Scheduled jobRefresh popular content
Event-drivenPre-load on related event
PredictiveML-based prefetch

9. Designing Cache Key Generation

PracticeDetail
Namespace prefixuser:123
Include versionv2:user:123 for migrations
Tenant scopetenant:42:user:123
Avoid PIIHash sensitive parts
Hash long keysSHA-256 if > 250 chars

10. Handling Cache Stampede

TechniqueDetail
Single-flightCoalesce concurrent loads (Caffeine does this)
Probabilistic early expireRefresh slightly before TTL
Mutex/lock per keyOnly one loader allowed
Stale-while-revalidateServe stale, refresh async

11. Using Cache Annotations

Example: Spring Cache

@Cacheable(value = "users", key = "#id")
public User get(long id) { return repo.findById(id).orElseThrow(); }

@CachePut(value = "users", key = "#u.id")
public User update(User u) { return repo.save(u); }

@CacheEvict(value = "users", key = "#id")
public void delete(long id) { repo.deleteById(id); }

12. Implementing Cache Metrics

MetricWhat to Track
Hit ratiohits / (hits + misses)
Eviction rateCapacity pressure
Load time p99Slow miss path
SizeMemory usage
Stampede eventsConcurrent loads coalesced