Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
A comprehensive guide to caching at every layer of the stack -- from browser and CDN to application, database, and distributed systems. Proper caching dramatically reduces latency, lowers infrastructure costs, and improves user experience.
Caching Fundamentals
Core Concepts
Term
Definition
Cache Hit
Requested data found in cache; served without hitting the origin
Cache Miss
Data not in cache; must be fetched from the origin and optionally stored
TTL (Time-To-Live)
Duration a cached entry remains valid before expiration
Eviction
Removal of entries from cache when capacity is reached or policy triggers
Stale Data
Cached data that is outdated relative to the source of truth
Cache Warming
Pre-populating a cache before traffic arrives
Cache Stampede
Many concurrent requests for the same uncached key overwhelming the origin
Eviction Policies
Policy
Behavior
Best For
LRU (Least Recently Used)
Evicts the entry not accessed for the longest time
General-purpose workloads
LFU (Least Frequently Used)
Evicts the entry accessed the fewest times
Frequency-skewed access patterns
FIFO (First In, First Out)
Evicts the oldest entry regardless of access
Simple, predictable rotation
TTL-Based
Evicts entries after a fixed duration
Time-sensitive data
Random
Evicts a random entry
When simplicity matters more than precision
ARC (Adaptive Replacement Cache)
Dynamically balances recency and frequency
Workloads with mixed access patterns
HTTP Caching
HTTP caching is the first line of defense. Proper headers prevent unnecessary network requests entirely.
Cache-Control Header
# Cache publicly for 1 hour, allow stale content for 60s while revalidating
Cache-Control: public, max-age=3600, stale-while-revalidate=60
# Private cache (browser only), revalidate every time
Cache-Control: private, no-cache
# Never cache (sensitive data)
Cache-Control: no-store
# Immutable assets (hashed filenames)
Cache-Control: public, max-age=31536000, immutable
Cache-Control Directives Reference
Directive
Meaning
public
Any cache (CDN, proxy, browser) may store the response
private
Only the browser may cache; proxies must not
no-cache
Cache may store but must revalidate with origin before serving
no-store
Do not cache under any circumstances
max-age=N
Response is fresh for N seconds
s-maxage=N
Overrides max-age for shared caches (CDN/proxy)
stale-while-revalidate=N
Serve stale content for N seconds while fetching fresh copy
stale-if-error=N
Serve stale content for N seconds if origin returns an error
immutable
Content will never change; skip revalidation entirely
must-revalidate
Once stale, must revalidate before use -- no stale serving
The Vary header tells caches that the response differs based on certain request headers.
# Cache separate versions by encoding and language
Vary: Accept-Encoding, Accept-Language
# Cache separate versions for authenticated vs anonymous
Vary: Authorization, Accept
# Nginx -- long-lived cache for hashed assets, short for HTML
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location / {
expires 5m;
add_header Cache-Control "public, no-cache";
}
CDN Caching
Cloudflare Page Rules / Cache Rules
# Cache everything on the /api/public/* path for 1 hour
URL pattern: example.com/api/public/*
Cache Level: Cache Everything
Edge Cache TTL: 3600
Browser Cache TTL: 300
# Bypass cache for authenticated routes
URL pattern: example.com/api/user/*
Cache Level: Bypass
CloudFront Cache Policy (AWS CDK)
// AWS CDK -- CloudFront distribution with cachingimport * as cloudfront from'aws-cdk-lib/aws-cloudfront';
import * as origins from'aws-cdk-lib/aws-cloudfront-origins';
import * as s3 from'aws-cdk-lib/aws-s3';
const bucket = new s3.Bucket(this, 'AssetsBucket');
const cachePolicy = new cloudfront.CachePolicy(this, 'ApiCachePolicy', {
cachePolicyName: 'api-cache-1h',
defaultTtl: Duration.hours(1),
minTtl: Duration.minutes(1),
maxTtl: Duration.days(1),
headerBehavior: cloudfront.CacheHeaderBehavior.allowList(
'Accept',
'Accept-Language'
),
queryStringBehavior: cloudfront.CacheQueryStringBehavior.all(),
cookieBehavior: cloudfront.CacheCookieBehavior.none(),
enableAcceptEncodingGzip: true,
enableAcceptEncodingBrotli: true,
});
new cloudfront.Distribution(this, 'CDN', {
defaultBehavior: {
origin: new origins.S3Origin(bucket),
cachePolicy,
viewerProtocolPolicy:
cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
},
});
Fastly VCL Snippet
# Fastly VCL -- custom cache logic
sub vcl_recv {
# Strip cookies for static assets to improve cache hit ratio
if (req.url ~ "\.(css|js|png|jpg|svg|woff2)$") {
unset req.http.Cookie;
}
# Pass authenticated requests directly to origin
if (req.http.Authorization) {
return(pass);
}
}
sub vcl_fetch {
# Cache API responses for 5 minutes at the edge
if (req.url ~ "^/api/public/") {
set beresp.ttl = 300s;
set beresp.http.Cache-Control = "public, max-age=300";
}
}
Application-Level Caching Patterns
Cache-Aside (Lazy Loading)
The application checks the cache first. On a miss, it fetches from the origin, stores in cache, and returns.
# Python -- cache-aside with Redisimport redis
import json
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
defget_user(user_id: str) -> dict:
cache_key = f"user:{user_id}"# 1. Check cache
cached = r.get(cache_key)
if cached:
return json.loads(cached)
# 2. Cache miss -- fetch from DB
user = db.query("SELECT * FROM users WHERE id = %s", (user_id,))
# 3. Store in cache with TTL
r.setex(cache_key, 3600, json.dumps(user))
return user
Read-Through Cache
The cache itself is responsible for loading data on a miss. The application always reads from the cache.
Pre-populate caches before traffic hits to avoid cold-start miss storms.
# Cache warming on deployment or scheduleimport asyncio
asyncdefwarm_cache():
"""Warm frequently accessed data into cache."""# 1. Warm top products
top_products = await db.query(
"SELECT id FROM products ORDER BY views DESC LIMIT 1000"
)
for batch in chunked(top_products, 50):
tasks = [warm_product(p['id']) for p in batch]
await asyncio.gather(*tasks)
# 2. Warm configuration data
configs = await db.query("SELECT * FROM app_config")
pipe = r.pipeline()
for config in configs:
pipe.setex(
f"config:{config['key']}",
7200,
json.dumps(config['value'])
)
pipe.execute()
asyncdefwarm_product(product_id: str):
product = await db.fetch_product(product_id)
await r.setex(
f"product:{product_id}",
3600,
json.dumps(product)
)
# Run at startup or via cron# asyncio.run(warm_cache())
Monitoring Cache Performance
Key Metrics
Metric
Formula
Healthy Range
Hit Ratio
hits / (hits + misses)
> 90% for most workloads
Miss Ratio
misses / (hits + misses)
< 10%
Eviction Rate
evictions / time
Should be low and stable
Latency (p50/p99)
Time per cache operation
p50 < 1ms, p99 < 5ms
Memory Usage
bytes used / bytes allocated
60-85% is ideal
Key Count
Total keys in cache
Monitor for unbounded growth
Redis Monitoring
# Redis INFO command -- key metrics
redis-cli INFO stats | grep -E "keyspace_hits|keyspace_misses|evicted_keys"# Calculate hit ratio
redis-cli INFO stats | awk -F: '
/keyspace_hits/ { hits=$2 }
/keyspace_misses/ { misses=$2 }
END { printf "Hit ratio: %.2f%%\n", hits/(hits+misses)*100 }
'# Monitor slow operations
redis-cli SLOWLOG GET 10
# Memory analysis
redis-cli MEMORY DOCTOR
redis-cli INFO memory
Prometheus Metrics for Application Cache
# Python -- Prometheus metrics for cache monitoringfrom prometheus_client import Counter, Histogram, Gauge
cache_hits = Counter('cache_hits_total', 'Cache hit count', ['cache_name'])
cache_misses = Counter('cache_misses_total', 'Cache miss count', ['cache_name'])
cache_latency = Histogram(
'cache_operation_duration_seconds',
'Cache operation latency',
['cache_name', 'operation'],
buckets=[0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05]
)
cache_size = Gauge('cache_size_bytes', 'Cache memory usage', ['cache_name'])
defcached_get(key: str, fetch_fn, cache_name: str = 'default'):
with cache_latency.labels(cache_name, 'get').time():
result = cache.get(key)
if result isnotNone:
cache_hits.labels(cache_name).inc()
return result
cache_misses.labels(cache_name).inc()
value = fetch_fn()
with cache_latency.labels(cache_name, 'set').time():
cache.set(key, value)
return value
Common Pitfalls and Solutions
Stale Data
Problem: Cache serves outdated data after the source of truth changes.
Solutions:
Use short TTLs for frequently changing data
Implement event-based invalidation on writes
Use stale-while-revalidate to serve stale while refreshing
Thundering Herd
Problem: When a popular cache key expires, hundreds of requests simultaneously hit the origin.
Use stale-while-revalidate to continue serving expired content
import random
defttl_with_jitter(base_ttl: int, jitter_pct: float = 0.1) -> int:
"""Add random jitter to TTL to prevent synchronized expiration."""
jitter = int(base_ttl * jitter_pct)
return base_ttl + random.randint(-jitter, jitter)
Cache Penetration
Problem: Repeated requests for keys that do not exist in the origin (e.g., invalid IDs), bypassing the cache every time.
Solutions:
Cache negative results (null/empty) with a short TTL
Use a Bloom filter to reject definitely-absent keys
# Cache null results to prevent penetrationdefget_item(item_id: str):
key = f"item:{item_id}"
cached = r.get(key)
if cached == "__NULL__":
returnNone# Known absentif cached:
return json.loads(cached)
item = db.get_item(item_id)
if item isNone:
r.setex(key, 300, "__NULL__") # Cache the absence for 5 minreturnNone
r.setex(key, 3600, json.dumps(item))
return item
Cache Breakdown
Problem: A single hot key expires and the origin cannot handle the sudden load.
Solution: Never let the hot key expire -- refresh it proactively.
defget_hot_key(key: str, fetch_fn, ttl: int = 3600):
"""Ensure hot keys are refreshed before expiry."""
remaining = r.ttl(key)
if remaining > 60:
# Plenty of time, serve from cachereturn json.loads(r.get(key))
# TTL is low or expired -- refresh
value = fetch_fn()
r.setex(key, ttl, json.dumps(value))
return value
Quick Reference: Choosing a Caching Strategy
Scenario
Recommended Approach
Static assets (JS, CSS, images)
Browser cache + CDN, long TTL, content-hash filenames
API responses (public, read-heavy)
CDN + Redis, moderate TTL, ETag validation
User-specific data
Browser cache (private), short TTL, event-based invalidation
Database query results
Application-level cache-aside with Redis
Expensive computations
Memoization (in-process) or Redis for shared results
Session data
Redis with sliding TTL
Configuration / feature flags
Read-through cache, event-based invalidation
High-write workloads
Write-behind cache with async flush
Search results / aggregations
Pre-computed cache warming + moderate TTL
Summary Checklist
Identify hot paths and measure current latency
Choose the right caching layer (browser, CDN, app, distributed)
Set appropriate TTLs based on data freshness requirements
Implement cache invalidation tied to data mutation events
Add jitter to TTLs to prevent thundering herd
Cache negative results to prevent cache penetration
Use locking or probabilistic refresh to prevent stampedes
Monitor hit ratio, latency, eviction rate, and memory usage
Plan cache warming for cold starts and deployments
Document cache keys, TTLs, and invalidation triggers for the team