Render caching

Drupal 8

Sascha Grossenbacher

Caching?

Goal

Improve performance

 

How

Store the result of slow calculations so that they do not need to be executed again

API Basics

Set (Key, Data, Expiration, Tags)

 

Get (Key)

 

Delete (Key)

 

Invalidate (Tags)

Three types of caching

#1 Page cache

Every anonymous user sees exactly the same page.

 

The page cache stores full pages in the cache, with huge performance gains for anonymous users.

 

Internal vs. External Page Cache 

Internal Page Cache

The internal page cache in Drupal 8 is a module 

 

Page cache off: 13.11 requests / second

Page cache on: 280.09 requests / second

( Fresh installation, empty frontpage, PHP 5.6) 

External Page Cache

Edge cache like Varnish or a Service like fastly, cloudfront

 

Thousands of requests / second, distributed

 

Expiration time setting in Drupal 8 only affects external caches, internal is always indefinite

#2 Data caching

Internal data, Direct usage of the Cache API

 

Module list, Configuration, Entity storage, Plugins

#3 Render Cache

Large parts of the website are the same for authenticated users

 

Comparable to D7 block caching, views/panel output cache

Render Caching

The challenge

There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors.

 

http://martinfowler.com/bliki/TwoHardThings.html

 

The 4 Questions

Cache Key

Cache Tags

Cache Contexts

Max Age

https://www.drupal.org/developing/api/8/render/arrays/cacheability

Cache Key

Is my data worth caching?

 

If yes, what identifies my data?

 

Example: Displaying node 1 with the teaser view mode

Cache Contexts

Does my output vary?

Per theme, language, user, permissions, query arguments, timezone, ...

Cache contexts are hierachical: user, user.permissions

 

Danger: Not setting the correct contexts can result in sensitive data being shown to normal users

 

Example: Displaying a link based on a permission check for the current user

https://www.drupal.org/developing/api/8/cache/contexts

Cache Tags

What things does my data depend on?

 

What changes require that my data is regenerated?

 

Example: Displaying node 1 with the teaser view mode

Tags required for: the node, node author, image style, text format, ...

Max Age

When does my output become outdated?

 

Permanent vs. N seconds vs. Not cacheable

 

 

Objects know their tags/context

Displaying entities/views/... automatically adds the correct tags and contexts

 

Relevant when building your own render arrays:

hook_node_view()

Custom blocks

Metadata Bubbling

Cache Tags are Everywhere

... and awesome

 

The internal page cache respects cache tags too!

 

Even external caching can respect cache tags through a header

 

 

 

Invalidations can be implemented in Varnish and are supported by fastly.com

Views Custom Cache Tag (NP8)

Views cache plugin

 

Makes the used list cache tag configurable

 

Requires code to define/invalidate cache tags, for example:

 

 

 

https://github.com/md-systems/views_custom_cache_tag

node:$type
node:region:$region
node:section:$section

Invalidation example

Changes

  1. A new node (7) is created in the "Sport" section
    Invalidations: node:sport, node_list
  2. Node 2 is changed
    Invalidations: node:2, node:sport, node_list

Next request

#post_render_cache (Placeholders)

Sometimes, small parts of e.g. a node vary for every user

 

Embedded forms, Personalized information, CSRF tokens

 

Example: Flag links inside nodes

Client side additions

Similar to #post_render_cache, but in JS

 

Works even with page cache, but requires additional requests (use Local Storage)

 

HTML 5 data attributes

Example: Paywall hints

<article data-paywall-entity-id="node/12"

Summary

Partial caching in Drupal 7 is usually time based and hard to invalidate. Creating/Changing content invalidates the whole page cache.

 

With Drupal 8, the render and cache usually has no expiration time and is immediately invalidated. With little to no custom code.

Questions?

Render Caching

By Sascha Grossenbacher