Cache Me If You Can
A talk I gave at the Laravel Aarhus Meetup on caching strategies in Laravel. From basic cache-aside to cache warming, tagged invalidation, and the patterns I use at TV2 to handle 90,000 requests per second.
I gave a talk called "Cache Me If You Can" at the Laravel Copenhagen Meetup at Monta on September 23rd. Caching is one of those topics that everyone thinks they understand until they have to cache-invalidate a news site that handles 90,000 requests per second during breaking events.
Why this talk
At TV2 Regionerne, caching isn't an optimization. It's the architecture. Without a multi-layer cache strategy, the Statamic-based sites would fall over during any significant traffic event. With it, election night peaks at 90K req/sec without breaking a sweat.
The talk covered the patterns I use in production, from the basics through to things I haven't seen documented elsewhere.
The layers
Application cache -- Laravel's Cache::remember() for expensive queries and computed data. The foundation. But the default TTL-based invalidation is too slow for a news site. If a journalist publishes a breaking story, it needs to appear immediately, not after the cache expires in 60 seconds.
Tagged cache invalidation -- Cache tags let you invalidate groups of related cache entries without clearing everything. When an entry in a collection is updated, invalidate all cache entries tagged with that collection. Precise, fast, and no stale content.
Edge caching with Fastly -- TV2 uses Fastly as a CDN. The interesting part is programmatic cache invalidation via the Fastly API. When a journalist publishes, the CMS fires a webhook that purges the specific URLs from Fastly within 150ms. Globally. This is how the sites serve 90K req/sec from cache while still showing fresh content within seconds of publication.
Cache warming -- Proactively building cache entries before they are needed. Before an election night, I run a cache warmer that crawls every URL the site will serve and pre-populates both the application cache and the CDN. When traffic hits, every request is a cache hit from the first second.
The traps
The biggest trap is caching too aggressively and then not having a reliable invalidation strategy. I've seen teams cache everything with a 1-hour TTL and then wonder why content updates take an hour to appear. The second trap is cache stampedes: when a popular cache entry expires and hundreds of requests simultaneously try to rebuild it. Laravel's Cache::flexible() and atomic locks solve this.
Good conversation at the meetup. One question led to a long discussion about whether flat-file Statamic even needs application-level caching (spoiler: it does, because blueprint resolution and augmentation are the expensive parts, not reading files from disk).
If you are in Denmark and interested in Laravel, check out the meetup groups: Copenhagen, Aarhus, and Odense. Or the umbrella site at laraveldk.org.