Drupal 8 now has page caching enabled by default
After more than a year and probably hundreds of patches, yesterday it finally happened! As of 13:11:56 CET, April 8, 2015, Drupal 8 officially has page caching enabled by default!1 And not the same page caching as in Drupal 7: this page cache is instantly updated when something is changed.
The hundreds of patches can be summarized very simply: cache tags, cache tags, cache tags. Slightly less simple: cacheability metadata is of vital importance in Drupal 8. Without it, we’d have to do the same as in Drupal 7: whenever content is created or a comment is posted, clear the entire page cache. Yes, that is as bad as it sounds! But without that metadata, it simply isn’t possible to do better.2
I’ve been working on this near-full time since the end of 2013 thanks to Acquia, but obviously I didn’t do this alone — so enormous thanks to all of you who helped!
This is arguably the biggest step yet to make Drupal Fast By Default. I hate slow sites with a passion, so you can probably see why I personally see this as a big victory :)
Benchmark
Out of the box, Drupal 8 is now between 2 and 200 times faster than Drupal 7 for anonymous users: Drupal 8 will respond in constant time, for Drupal 7 it depends on the complexity of the page.
On my machine ( ab -c1 -n 1000
, PHP 5.5.11, Intel Core i7 2.8 GHz, warm caches,):
Drupal 7
- Front-page: 18.5 ms/request (55 requests/s)
node/1
: 23.5 ms/request (43 requests/s)- More complex pages: easily hundreds of milliseconds, only few requests per second.
Drupal 8
Always 8.3 ms/request (120 requests/s)3.
Win-win
The real beauty is that it’s a win-win: enterprise (Acquia), medium, small, tiny (hobbyist) all win:
- Enterprise sites get very nice reverse proxy/CDN-based hosting
- Tiny sites can easily serve 100 requests/second (>8 million requests/day) on shared hosting.
So my work was sponsored by Acquia, but benefits everyone!
People have been expressing concerns that Drupal 8 has become too complex, that it doesn’t care about site builders anymore, that it is only for enterprises, etc. I think this is a good counterexample.
Yes, we added the complexity of cacheability metadata, but that only affects developers — for whom we have good documentation. And most importantly: site builders reap the benefits: they don’t even have to think about this anymore. Manually clearing caches is a thing of the past starting with Drupal 8!
Page cache is just a built-in reverse proxy
Drupal’s page cache is just a built-in reverse proxy. It’s basically “poormansvarnish”.
Drupal 8 bubbles all cacheability metadata up along the render tree, just like JavaScript events bubble up along the DOM tree. When it reaches the tree’s root, it also bubbles up to the response level, in the form of the X-Drupal-Cache-Tags
header.
The page cache uses that header to know what cache tags it should be invalidated by. And because of that, other (“real”) reverse proxies can do exactly the same. The company behind Varnish even blogged about it. And CDNs are even starting to support this exact technique out of the box, for example Fastly.
Last but not least: all of Drupal 8’s integration tests use the page cache by default, which means all of our integration tests effectively verify that Drupal works correctly even if they’re behind a reverse proxy!
New possibilities for small sites (and shared hosting)
On one end of the spectrum, I see great shared hosting providers starting to offer Varnish even on their smallest plans. For example: Gandi offers Varnish on their €4/month plans. If users can configure Varnish — or even better, if they pre-configure Varnish to support Drupal 8’s cache tag-based invalidation — then almost all traffic will be handled by Varnish.
For 90% or more of all sites, this would quite simply be good enough: very cheap, very fast, very flexible.4
I can’t wait until we see the first hosting provider offering such awesome integration out of the box!
New possibilities for enterprise sites (and enterprise hosting)
On the other hand of the spectrum, enterprise hosting now gains the ability to invalidate (purge) all and only the affected pages on a CDN5. Without having to generate a list of URLs that a modified piece of content may appear on, and then purge those URLs. Without having to write lots of hooks to catch all the cases where said content is being modified.
At least equally important: it finally allows for caching content that previously was generated dynamically for every request, because it was a strong requirement that the information always be up-to-date6. With cache tag support, and strong guarantees that cache tags indeed are invalidated when necessary, such use cases now can cache the content and still be confident that updates will immediately propagate.
New possibilities for developers
Finally, the addition of cache tags and by extension, all render cacheability metadata (cache tags, contexts and max-age), allow for greater insight and tooling when analyzing hosting, infrastructure, performance and caching problems. Previously, you had to analyze/debug a lot of code to figure out why something that was cached was not being invalidated when appropriate by said code.
Because it’s now all standardized, we can build better tools — we can even automatically detect likely problems: suspiciously frequent cache tag invalidations, suspiciously many cache tags … (but also cache contexts that cause too many variations, too low or too high maximum ages …).
Next steps
Warm cache performance is now excellent, but only for anonymous users.
Next week, at Drupal Dev Days Montpellier, we’ll be working on improving Drupal 8’s cold cache performance (including bootstrap and routing performance). That will also help improve performance for authenticated users.
But we already have been working several weeks on improving performance for authenticated users. Together with the above, we should be able to outperform Drupal 7. This is the plan that Fabian Franz and I have been working towards:
- smartly caching partial pages for all users (including authenticated users): d.o/node/2429617, which requires cache contexts to be correct
- sending the dynamic, uncacheable parts of the page via a BigPipe-like mechanism: d.o/node/2429287
-
That’s commit
25c41d0a6d7806b403a4c0c555f7dadea2d349f2
. ↩ -
In other words: all of this is made possible thanks to optimal cache invalidation. Yes, that quote. ↩
-
We’re also working on making the page cache faster. 5 ms/request, or 200 requests per second should be possible. ↩
-
And not something any other CMS offers as far as I know — if there is one, please leave a comment! ↩
-
Keep an eye on the Purge module for Drupal 8. It will make it very easy to apply cache tag-based invalidation to self-hosted reverse proxies (Varnish, ngninx…), but also to put your entire site behind a CDN and still enjoy instantaneous invalidations! ↩
-
You could already use
#cache[expire]
in Drupal 7, but in Drupal 8, the combination of#cache[max-age]
and#cache[tags]
means that you have both time-based invalidation and instantaneous tag-based invalidation. Whichever invalidation happens first, invalidates the cached data. And therefore: updates occur as expected. ↩
- Acquia
- Drupal
- WPO
- performance