This week in caching: OPcache, beyond the defaults
Three reads that go past the copy-paste php.ini snippet everyone shares:
— Why opcache.revalidate_freq is the wrong knob — explains that on a deploy you want validate_timestamps=0 + an opcache_reset on release, not a 60s revalidate loop; clears up the most common stale-code bug.
— Sizing memory_consumption with opcache_get_status() — shows how to read cached_scripts vs max_cached_keys so you stop guessing at 128M; gold if you keep hitting OOM restarts.
— JIT is not a cache (and won't fix your TTFB) — sober take on why PHP 8 JIT helps CPU-bound math, not typical web request paths.
Credit to the PHP internals folks and Brent Roose's write-ups.
Bookmark: the opcache_get_status() walkthrough — one function call tells you if your config is actually sized right.
Three reads that go past the copy-paste php.ini snippet everyone shares:
— Why opcache.revalidate_freq is the wrong knob — explains that on a deploy you want validate_timestamps=0 + an opcache_reset on release, not a 60s revalidate loop; clears up the most common stale-code bug.
— Sizing memory_consumption with opcache_get_status() — shows how to read cached_scripts vs max_cached_keys so you stop guessing at 128M; gold if you keep hitting OOM restarts.
— JIT is not a cache (and won't fix your TTFB) — sober take on why PHP 8 JIT helps CPU-bound math, not typical web request paths.
Credit to the PHP internals folks and Brent Roose's write-ups.
Bookmark: the opcache_get_status() walkthrough — one function call tells you if your config is actually sized right.
This week in caching: the stale-while-revalidate rabbit hole
Four pieces on serving slightly-old content so nobody waits on a cold cache:
— RFC 5861 in plain English — what stale-while-revalidate and stale-if-error actually promise, and which CDNs honor them.
— SWR at the edge vs in SWR (the React hook) — disambiguates the two things that share a name; skip if you already know the difference.
— Async revalidation gotchas — the thundering-herd problem when 10k users all trigger the background refresh at once, and request coalescing as the fix.
— Browser-side: Cache-Control with stale-while-revalidate — Chromium support notes for the response header version.
Credits: Harry Roberts and the Fastly docs team.
Bookmark: the request-coalescing piece — it's the part most SWR tutorials quietly skip.
Four pieces on serving slightly-old content so nobody waits on a cold cache:
— RFC 5861 in plain English — what stale-while-revalidate and stale-if-error actually promise, and which CDNs honor them.
— SWR at the edge vs in SWR (the React hook) — disambiguates the two things that share a name; skip if you already know the difference.
— Async revalidation gotchas — the thundering-herd problem when 10k users all trigger the background refresh at once, and request coalescing as the fix.
— Browser-side: Cache-Control with stale-while-revalidate — Chromium support notes for the response header version.
Credits: Harry Roberts and the Fastly docs team.
Bookmark: the request-coalescing piece — it's the part most SWR tutorials quietly skip.
This week in caching: stopping the stampede
What happens when a hot key expires and a thousand requests rebuild it at once. Roundup:
— Probabilistic early expiration (XFetch) — the Vargas algorithm that recomputes a value slightly before TTL based on how long the last build took; the cleanest math on dogpile prevention.
— Locking vs leasing — memcached's lease tokens compared to Redis SETNX locks, with the deadlock failure mode of naive locks.
— Why a tiny TTL jitter beats a fixed TTL — adding random seconds so 100k keys don't all expire on the same second.
Credits to the original RedisLabs and Facebook memcache papers.
Bookmark: the XFetch explainer — once you see the formula you can't unsee how many sites need it.
What happens when a hot key expires and a thousand requests rebuild it at once. Roundup:
— Probabilistic early expiration (XFetch) — the Vargas algorithm that recomputes a value slightly before TTL based on how long the last build took; the cleanest math on dogpile prevention.
— Locking vs leasing — memcached's lease tokens compared to Redis SETNX locks, with the deadlock failure mode of naive locks.
— Why a tiny TTL jitter beats a fixed TTL — adding random seconds so 100k keys don't all expire on the same second.
Credits to the original RedisLabs and Facebook memcache papers.
Bookmark: the XFetch explainer — once you see the formula you can't unsee how many sites need it.
Pairs well with this channel
@BackupOrDie — Strong opinions on backup strategy, because the people who skip it always learn the… Quietly one of the better feeds in the space.
@BackupOrDie — Strong opinions on backup strategy, because the people who skip it always learn the… Quietly one of the better feeds in the space.
This week in caching: the second hard problem
Invalidation, the half of the famous joke nobody solves cleanly:
— TTL vs event-based vs versioned keys — a decision matrix for when to expire on a clock, on a write, or by bumping a key suffix.
— Cache-aside vs write-through vs write-behind — the consistency trade-offs of each, with the dual-write race that bites cache-aside.
— Tag-based invalidation — how surrogate keys (Fastly) and cache tags (Symfony) let you purge 'everything touching product 451' in one call.
— Why deleting beats updating on write — the lazy-fill argument against keeping cache in sync.
Credits: the AWS caching whitepaper and Symfony cache docs.
Bookmark: the cache-aside dual-write race writeup — the bug that ships to prod looking correct.
Invalidation, the half of the famous joke nobody solves cleanly:
— TTL vs event-based vs versioned keys — a decision matrix for when to expire on a clock, on a write, or by bumping a key suffix.
— Cache-aside vs write-through vs write-behind — the consistency trade-offs of each, with the dual-write race that bites cache-aside.
— Tag-based invalidation — how surrogate keys (Fastly) and cache tags (Symfony) let you purge 'everything touching product 451' in one call.
— Why deleting beats updating on write — the lazy-fill argument against keeping cache in sync.
Credits: the AWS caching whitepaper and Symfony cache docs.
Bookmark: the cache-aside dual-write race writeup — the bug that ships to prod looking correct.
This week in caching: HTTP caching headers, decoded
The headers that decide whether a return visit even hits your server:
— Cache-Control: immutable — the directive that tells browsers to skip revalidation entirely for fingerprinted assets; underused outside Facebook.
— ETag vs Last-Modified — why strong ETags break behind some proxies and when 304s actually save you bandwidth.
— no-cache is not no-store — the eternally confused pair, spelled out with what each does to the back button.
— Vary: the foot-gun — how Vary: User-Agent fragments your cache into uselessness.
Credits to Jake Archibald's caching best-practices post, still the canonical reference.
Bookmark: Archibald's piece — if you read one thing on HTTP caching this year, this.
The headers that decide whether a return visit even hits your server:
— Cache-Control: immutable — the directive that tells browsers to skip revalidation entirely for fingerprinted assets; underused outside Facebook.
— ETag vs Last-Modified — why strong ETags break behind some proxies and when 304s actually save you bandwidth.
— no-cache is not no-store — the eternally confused pair, spelled out with what each does to the back button.
— Vary: the foot-gun — how Vary: User-Agent fragments your cache into uselessness.
Credits to Jake Archibald's caching best-practices post, still the canonical reference.
Bookmark: Archibald's piece — if you read one thing on HTTP caching this year, this.
This week in caching: edge vs origin, the real trade-offs
Where the cache lives changes everything downstream:
— Edge caching personalized pages — ESI and edge-side composition so logged-in users still get cached shells with dynamic holes punched in.
— Cache key cardinality at the edge — why caching by geo or device blows up your storage and hit rate simultaneously.
— Origin shield — the often-missed CDN layer that collapses requests so your origin sees one miss, not 200 PoPs worth.
— Compute-at-edge isn't free caching — when Workers/Lambda@Edge add latency instead of removing it.
Credits: Cloudflare and Fastly architecture docs.
Bookmark: the origin-shield explainer — single biggest origin-load win most teams haven't turned on.
Where the cache lives changes everything downstream:
— Edge caching personalized pages — ESI and edge-side composition so logged-in users still get cached shells with dynamic holes punched in.
— Cache key cardinality at the edge — why caching by geo or device blows up your storage and hit rate simultaneously.
— Origin shield — the often-missed CDN layer that collapses requests so your origin sees one miss, not 200 PoPs worth.
— Compute-at-edge isn't free caching — when Workers/Lambda@Edge add latency instead of removing it.
Credits: Cloudflare and Fastly architecture docs.
Bookmark: the origin-shield explainer — single biggest origin-load win most teams haven't turned on.
This week in caching: full-page cache landmines
FPC is the biggest speed win and the biggest footgun. Field notes:
— Caching the logged-in state by accident — the classic where user A sees user B's cart because the cache key ignored the session.
— CSRF tokens in cached HTML — why your forms 419/403 after enabling FPC, and the ESI/AJAX fix.
— Flash messages and one-time content — how cached HTML strands 'order confirmed' banners on the wrong page.
— The cache that never warms — bot-only cache fills leaving real users on cold misses.
Credits to the Magento and Drupal performance communities, who've stepped on all of these.
Bookmark: the session-leak writeup — the bug that becomes a security incident.
FPC is the biggest speed win and the biggest footgun. Field notes:
— Caching the logged-in state by accident — the classic where user A sees user B's cart because the cache key ignored the session.
— CSRF tokens in cached HTML — why your forms 419/403 after enabling FPC, and the ESI/AJAX fix.
— Flash messages and one-time content — how cached HTML strands 'order confirmed' banners on the wrong page.
— The cache that never warms — bot-only cache fills leaving real users on cold misses.
Credits to the Magento and Drupal performance communities, who've stepped on all of these.
Bookmark: the session-leak writeup — the bug that becomes a security incident.
This week in caching: chasing hit ratio
Your CDN bill and TTFB both track this number. Reads:
— Reading the CDN cache-status header — decoding HIT/MISS/EXPIRED/STALE and the newer standardized Cache-Status header.
— Why your ratio is lower than you think — the long tail of rarely-requested URLs that never get a second hit (tiered caching as the answer).
— Compression and caching order — caching pre-compressed vs compressing per response, and why getting it backwards wastes CPU.
— Cache hit ratio vs cache offload — the two metrics people conflate; one can look great while the other is terrible.
Credits: the Fastly and Akamai measurement guides.
Bookmark: the standardized Cache-Status header explainer — finally a portable way to debug across CDNs.
Your CDN bill and TTFB both track this number. Reads:
— Reading the CDN cache-status header — decoding HIT/MISS/EXPIRED/STALE and the newer standardized Cache-Status header.
— Why your ratio is lower than you think — the long tail of rarely-requested URLs that never get a second hit (tiered caching as the answer).
— Compression and caching order — caching pre-compressed vs compressing per response, and why getting it backwards wastes CPU.
— Cache hit ratio vs cache offload — the two metrics people conflate; one can look great while the other is terrible.
Credits: the Fastly and Akamai measurement guides.
Bookmark: the standardized Cache-Status header explainer — finally a portable way to debug across CDNs.
This week in caching: Memcached vs Redis, past the meme
The comparison everyone has an opinion on, done carefully:
— When Memcached actually wins — multithreaded, slab allocation, lower memory overhead per key for pure string KV; not dead, just specialized.
— Redis data structures as a cache feature — sorted sets for leaderboards, hashes for partial updates without re-serializing the whole object.
— Memory fragmentation realities — jemalloc behavior and why your RSS dwarfs your dataset.
— Eviction policies that matter — allkeys-lru vs allkeys-lfu and the workload where LFU quietly outperforms.
Credits to the Redis and Memcached maintainer docs.
Bookmark: the slab-allocation explainer — the reason Memcached still ships in 2026.
The comparison everyone has an opinion on, done carefully:
— When Memcached actually wins — multithreaded, slab allocation, lower memory overhead per key for pure string KV; not dead, just specialized.
— Redis data structures as a cache feature — sorted sets for leaderboards, hashes for partial updates without re-serializing the whole object.
— Memory fragmentation realities — jemalloc behavior and why your RSS dwarfs your dataset.
— Eviction policies that matter — allkeys-lru vs allkeys-lfu and the workload where LFU quietly outperforms.
Credits to the Redis and Memcached maintainer docs.
Bookmark: the slab-allocation explainer — the reason Memcached still ships in 2026.
This week in caching: warming the cache before users do
Cold caches after a deploy or purge cost you the worst TTFB of the day:
— Sitemap-driven crawl warming — replaying your sitemap.xml through the cache post-deploy so the first real visitor gets a HIT.
— Prioritizing by traffic, not URL count — warming your top 200 pages from analytics beats crawling all 50k.
— Staggered warm vs big-bang — why hammering your origin to warm everything at once just moves the outage.
— Keeping warm: keep-alive crawlers — lightweight pings that re-warm hot pages just before TTL.
Credits: the WP Rocket and Cloudflare cache-reserve docs.
Bookmark: the traffic-weighted warming approach — 80% of the benefit for 1% of the crawl.
Cold caches after a deploy or purge cost you the worst TTFB of the day:
— Sitemap-driven crawl warming — replaying your sitemap.xml through the cache post-deploy so the first real visitor gets a HIT.
— Prioritizing by traffic, not URL count — warming your top 200 pages from analytics beats crawling all 50k.
— Staggered warm vs big-bang — why hammering your origin to warm everything at once just moves the outage.
— Keeping warm: keep-alive crawlers — lightweight pings that re-warm hot pages just before TTL.
Credits: the WP Rocket and Cloudflare cache-reserve docs.
Bookmark: the traffic-weighted warming approach — 80% of the benefit for 1% of the crawl.
This week in caching: the Vary header, the quiet hit-rate killer
Small header, outsized damage. Curated:
— Vary: Accept-Encoding done right — the one Vary value you almost always want, and why normalizing it matters.
— Vary: Cookie = no cache — how a single cookie in the Vary list effectively disables shared caching.
— Key normalization instead of Vary — CDN cache-key rules as a surgical alternative to fragmenting on a full header.
— Client Hints and the future of Vary — how Vary: Sec-CH-* changes responsive image caching.
Credits to the MDN docs and Andrew Betts' edge-caching talks.
Bookmark: the cache-key-vs-Vary comparison — the trick that recovers a tanked hit ratio.
Small header, outsized damage. Curated:
— Vary: Accept-Encoding done right — the one Vary value you almost always want, and why normalizing it matters.
— Vary: Cookie = no cache — how a single cookie in the Vary list effectively disables shared caching.
— Key normalization instead of Vary — CDN cache-key rules as a surgical alternative to fragmenting on a full header.
— Client Hints and the future of Vary — how Vary: Sec-CH-* changes responsive image caching.
Credits to the MDN docs and Andrew Betts' edge-caching talks.
Bookmark: the cache-key-vs-Vary comparison — the trick that recovers a tanked hit ratio.