Caching Craft

When Timeouts Aren't An Option

Why?

  • Yii isn't a perfect framework
  • Craft isn't a perfect framework
  • All requests take time to process

Example

A page takes 300ms to process on the server side.

4 requests = 1200ms

4 req/s = 1.2s processing time per second!

(Grossly oversimplified)

If my site is receiving 4req/s I'll be rich anyway...

Fair point, but request frequency isn't always easy to guess...

  • A page might make multiple ajax calls
  • A page might redirect to another page
  • Some web dev from 1999 might have built a global navigation using <frame>s

A funny anecdote about a bot that wasn't a bot.

How does caching help?

  • Caching elements of a page can reduce the amount of work PHP needs to do
  • Caching entire pages can allow us reduce the number of requests reaching PHP
  • Caching within our wider infrastructure can allow us to serve a response without even knowing the request took place (someone else's problem)

Infrastructure

Web Server

PHP

Caching in PHP

  • Easy to implement
    • Native support in Twig templates {% cache %}
  • Caches don't have to be linked directly to URLs
    • Global headers
    • Elements shared across a subset of pages
  • Content aware
    • Cache invalidation easy easier
  • Plugin support to extend functionality
    • Blitz
    • Cache Flag

Caching in PHP

  • PHP is still executed on every request
    • Remember we said our frameworks aren't perfect?
    • Plugins can also do whatever they like
  • Craft's native caching can cause problems
    • Database storage - 😭
    • Row count based on: cache keys * elements referenced in the cache blocks. This can be a big number!
    • Can be mitigated by disabling `cacheElementQueries` in general.php 

DEMO PLEASE

Caching in the Web Server

  • Easy-ish to implement if you're setting up your server manually.
    • Can be more difficult when using a provisioner (forge, serverpilot etc)
  • Very fast
    • Nginx and varnish are designed for this
  • PHP isn't involved at all
    • No framework overhead
    • Much better resource usage
  • Plugin support to extend functionality
    • Blitz server rewrites (but requires custom config)
    • SRCache / Lua for Nginx

Caching in the Web Server

  • Not content aware
    • Cache busting needs to be implemented manually and is usually pretty dumb
    • Cache exceptions can be a pain to manage
  • Not Craft aware
    • Easy to accidentally cache admin-only content 
  • Caches are URL based
    • No sub-page caching for things like global headers
      • (Unless you use something like SSI but this has it's own caveats)
    • Difficult to bust cache using tags or prefixes

Another Demo

Caching at the Edge

  • Requests are mostly handled by someone else
    • We outsource some scalability concerns
    • DoS protection
  • Content is distributed on a CDN
    • Geographically closer to users
    • Topographically closer to users
  • Probably the fastest solution for TTFB
  • Bonus: Also handles static file distribution for us
  • Plugin support to extend functionality
    • Blitz (for cache purging)
    • Upper (for cache purging)

Caching at the Edge

  • Not content aware
    • Cache invalidation needs to be custom or plugin
    • Cache invalidation takes some amount of time and sometimes (often?) silently fails.
  • CDNs are large
    • Cloudflare has 300+ edge nodes, each is an individual cache, each will hit your origin server
  • It isn't foolproof
    • 404 / 500 caching (or not)
    • Accidental cache busting can lead to a re-cache flood

Caching at the Edge

  • You no longer control your infrastructure
    • Cloudflare downtime (recent Argo failure)
    • Policy changes
    • It's free, are you the product?
  • Cloudflare can be a bit ban-happy and likes to show captchas to people outside the US and Europe.
  • Cloudflare can delete your caches arbitrarily if you're using the free or Pro plan. Business and enterprise customers get priority.
  • SSL decryption needs to occur at the edge, CF can read all request content, cache leaks, trust issues?

Yet Another Demo

Gotchas

You can use un-cached ajax requests to mix cached and dynamic content.

Blitz getUri() and csrfInput()

Some plugins will grab content via ajax to avoid any caching

Nginx SSI

Each ajax request will boot Yii, Craft + all plugins. 

You can accidentally turn one page load into 5+ !

Gotchas

Combining caching methods can have unintended consequences

Infrastructure

Web Server

PHP

Cache Miss

Cache Miss

Generate response

Store Cache

Store Cache

Caching Craft

By Matt

Caching Craft

  • 745