Caching at the Edge

CDNs for everyone

Motivation

The real challenge: making the entire web fast

wimleers.com/article/performance-calendar-2013-making-the-entire-web-fast


Silos are fast, the long tail is slow.

Let's fix that.

Why?

Why do this: a quick reminder.

The edge?

Using a CDN

assetsHTML

Why?

Because closer to the end user (less latency).

This talk is about using a CDN to cache the HTML.

Drupal 7

Invalidation: simple

max-age = 300

… but stale content!

Invalidation: advanced

Purge affected URLs

… but brittle!

In practice

  • Combination of both
  • Allow content editors to purge manually
  • … site-specific hacks

Authenticated users

Separate domain ⟷ passthrough

Nothing is cached!

Drupal 8

Better architecture.

No more hacks.

invalidationcache tags
authenticated userscache contexts
cache tagsdata dependencies
cache contextsrequest context dependencies
cache tagsinvalidate tag X
cache contextsknow what to Vary by
if it varies too much, placeholder it

On a Response:

  • X-Drupal-Cache-Tags header
  • X-Drupal-Cache-Contexts header

Demo 1: anon traffic

↪ cache tags

Today.

Simple.

Cached worldwide!

Acquia Cloud Edge
or
CloudFlare Enterprise

Near future…

Trivial.

Affordable for all: cached locally in Varnish

Affordable for many: cached worldwide (CDN)

Invalidation solved: benefits everyone!

And now… something even cooler!

Authenticated user caching

- in the edge -

MOTIVATION

Very Common Scenario

  • Only anonymous users
  • Varnish
  • FAST!
  • Wim just showed that.

Very Common Scenario

CDN

Everything is great!

The company is flourishing!

And they lived happily ever …

WAIT!

Because one fateful day …

... a shopping cart was added to the site.

And then it looked like this:

And the webserver ran away screaming in terror and was never to be found again.

You don't believe me?

Let's test that …

Scenario

  • Drupal 8
  • Authenticated users
  • CDN (Fastly) — not cacheable by default

Site is fast (180 ms), but the user experience is poor.

I don't want that …

Why does that happen?

Pages are Static + Dynamic

Pages have dynamic parts

Pages are too dynamic

So let's make the pages less dynamic

Problem solved!

UHM …

WAIT!

But the Web 3.0 is all about personalized experiences!

I need dynamic pages!

Or I am back to using plain HTML!

And don't forget about my shopping cart!

Fortunately!

Drupal 8 has a solution for that!

… and it is already in core!

Placeholders and Auto-Placeholdering!

No more of this!

Drupal 8 knows your page

It can automatically placeholder

And now we can use ESI!

  • Enable esi-8.x-1.x (fork; not yet released)
  • Edge-Side Includes replaces placeholders at the edge.
  • <esi:include src="/esi-fragment/esi_6c9a85d4002185c82" />

And we can use ESI with a CDN, too!

Demo 2: auth traffic

↪ cache tags + cache contexts

Fastly

  • Powers ftp.drupal.org
  • Helped us optimize the VCL

Easy to set up

Works for anonymous users out of the box.

Upload custom VCL

Needed for authenticated user caching.

So let's see!

ESI with auth caching

Standardized solution for a complex problem.

Out of Within reach for 99%.

Unmatched.

Some hosting providers will step up.

So, Drupal 8 can be super fast!

It can be cached at the edge.

Without the pain of other CMSes (including Drupal 7).

It just requires all of us to think of a few things while developing custom modules or contributed modules.

The thought process

The theory of how we make Drupal fast.

Dependencies, dependencies, dependencies!

  • Drupal 7 didn't track any dependencies
  • e.g. drupal_add_css(), drupal_add_js()
  • ⇒ Global state: impossible to cache
  • #attached asset libraries solve that

Dependencies, dependencies, dependencies!

  • Drupal 7 didn't track any dependencies
  • e.g. url()'s output depended on:
    • <front> configuration
    • HTTPS configuration
    • clean URL configuration
    • current site in multisite
  • ⇒ impossible to cache invalidate
  • … yet many of us did it anyway!

Correct invalidation in Drupal 8

  • Cache tags (data dependencies)
  • Cache contexts (context dependencies)
  • Cache max-age (time dependencies)

+

Cacheability bubbled during rendering!

In practice

Try to make this thought process a habit:

1.

I'm rendering something. That means I must think of cacheability!

2.

Is this something that's expensive to render, and therefore is worth caching?

↪︎ If "yes": cache keys.

$build['#cache']['keys'] = ['node', 5, 'teaser'];

3.

Does the representation of the thing I'm rendering vary per combination of permissions, per URL, per interface language, per … something?

↪︎ If "yes": cache contexts.

$build['#cache']['contexts'][] = 'user.permissions';
$build['#cache']['contexts'][] = 'url';

~ HTTP's Vary header

4.

What causes the representation of the thing I'm rendering become outdated?

↪︎ If "yes": cache tags.

$build['#cache']['tags'][] = 'node:5';
$build['#cache']['tags'][] = 'user:3';
$build['#cache']['tags'][] = 'taxonomy_term:23';

5.

When does the representation of the thing I'm rendering become outdated?

↪︎ If "yes": cache max-age.

$build['#cache']['max-age'] = Cache::PERMANENT;

~ HTTP's Cache-Control: max-age header

All relevant objects provide cacheability metadata!

interface CacheableDependencyInterface {
  public function getCacheContexts();
  public function getCacheTags();
  public function getCacheMaxAge();
}

Implemented by:

  • configuration + entities (content & config)
  • access results
  • block, context, condition plugins

BigPipe, hybrid render strategies

Come see our other session tomorrow!

Making Drupal fly - The fastest Drupal ever is here!

Peek at the future

Service workers

w3.org/TR/service-workers/

html5rocks.com/en/tutorials/service-worker/introduction/

A client-side reverse proxy!

Logic defined in JavaScript!

Zero latency!

caniuse.com/serviceworkers

…allowed Fabian & I to focus on this!

Questions?

wimleers.com/talk/caching-at-the-edge-cdns-for-everyone

Docs

d.o/developing/api/8/cache + /tags + /contexts + /max-age