Skip to main content

BigPipe in Drupal 8

BigPipe was conceived at facebook as a solution to load dynamic pages quickly. Its a way of loading various sections of your web-page in parallel so end-users don't have to wait for the DOM to be completely ready to start interacting with the website. In this article, we will be talking about the architectural changes that allowed this kind of rendering & dive into big_pipe module to see how it works.

P.S: A common misconception with bigpipe is that it increases the performance of the webserver stack to return pages faster. The reality is that the load time for a page stays the same, the advantage being that a user can start interacting with a section of the page as soon as its ready (ala Perceived performance).

Perceived performance

In the screenshot above, the request completion time is the same for both: big_pipe enabled & disabled. However, the page is ready for user-interaction at 44 ms in case of big_pipe enabled, while for the disabled case, its 964 ms.

To understand Bigpipe caching strategy, lets first look at how caching works in Drupal 7 and Drupal 8

Caching in Drupal 7

Caching in Drupal 7

Caching in Drupal 8

Caching in Drupal 8

To understand the above examples better, lets take a look at the data being rendered in different regions.

Now, if we were talking about Drupal 7, the complete page would be cacheable for anonymous user. But, there would be no caching for authenticated user, even though there are parts of the page that can be cached. For authenticated requests in Drupal 7, one could use the modules like authcache to have better performance.

However in Drupal 8 core, this is doable using the dynamic page cache module in the core. Drupal 8 core has support for cacheability metadata, that aids dynamic page cache module. To enable the module, go to admin/modules -> select dynamic page cache & save the configuration.

(Stay tuned for our next post to read about Authcache Vs Dynamic page cache)

Dynamic Page cache

Cacheability metadata: Cache Tags & cache contexts

The background concept that brought dynamic page cache module in core was introduction of cacheablility metadata:Cache tags & Cache contexts

Auto-Placeholdering

One major way in which Facebook or any general implementation of BigPipe varies from the one in Drupal is its ability to identify regions that can benefit from BigPipe delivery.

When we talk about caching sections of a page, there could be sections that cannot be cached or caching them is an overhead. Drupal can now identify such sections of the page based on a few conditions(explained below) automatically. These sections are replaced by placeholders by Drupal core. So now while preparing the HTML response, Drupal doesn't need to wait for these non-cached(uncacheable) parts to pull fresh data. Rather, it can send out the skeleton markup with the non-cached parts of the page rendered as placeholders. The processing of these placeholders can be done via placeholder strategies defined. Drupal core has only one placeholder strategy called as single flush. But, it also provides a way for contrib modules to create their own strategies(This is where big_pipe module hooks in).

Auto Placeholdering Conditions

While rendering a page, all such blocks are identified & automatically replaced with placeholders. Drupal 8 core uses the following critera for placeholdering:

Caching is performed once the DOM is ready with cached content + placeholders. The next step is to flush these sections of the page with content (Single-flush strategy). Core provides only with single flush strategy wherein the complete page(with unchanged placeholders) is sent to Drupal\Core\EventSubscriber\HtmlResponsePlaceholderStrategySubscriber where placeholders are flushed out at once to replace them with actual content. Drupal 8 core allows contrib modules to define their own flush strategies leading to the support for BigPipe, ESI etc.

To read more about the cacheablility metadata & auto-placeholdering, I would recommend going through:

P.S: The flush strategies & placholdering is only applicable for HTML response.

Enter Big Pipe Module

At a high level, BigPipe sends a HTML response in chunks:

The major way in which Drupal's implementation differs from Facebook's implementation (and others) is in its ability to automatically figure out which parts of the page can benefit from BigPipe-style delivery using auto-placeholdering.

BigPipe can only work if JavaScript is enabled. BigPipe module in Drupal also allows to replace placeholders without JavaScript. Technically its not BigPipe, but use of multiple flushes termed as 'no-JS BigPipe'.

This allows us to use both no-JS BigPipe and "classic" BigPipe in the same response to maximize the amount of content we can send as early as possible.

Getting deeper into implementation:

Combining all of the above, when using both BigPipe placeholders and no-JS BigPipe placeholders, BigPipe sends: 1 HtmlResponse + M Embedded HTML Responses + N Embedded AJAX Responses.

BigPipe request flow

Disclaimer: The module is under active development now. Things you see below might change going forward. The section below will focus on diving into the code chunks from BigPipe module to see how it plays with the core. I have tried to put down parts of the module detailing how the module is hooking into the core.

How does the module hook into the core's placeholder strategy?

The module actually doesn't hook into the core's placholdering strategy, but defines a new one.

ChainedPlaceholderStrategy in core looks at the available placeholder strategies. These should be tagged with placeholder_strategy.

How does the module create placholders?

BigPipe module defines its own placeholder strategy Drupal\big_pipe\Render\Placeholder\BigPipeStrategy which implements PlaceholderStrategyInterface.

HtmlResponseAttachmentsProcessor doesn't know about BigPipe placeholders?

BigPipe module creates another service html_response.attachments_processor.big_pipe to override the the processing of attachments with the request.


BigPipeResponseAttachmentsProcessor 

extends HtmlResponseAttachmentsProcessor overriding function processAttachments to do the following:

Drupal core responds <html> using HTMLResponse which uses single flush. How to respond using n-flush strategy provided by BigPipe?

BigPipe module provides with BigPipeResponse which extends HtmlResponse. BigPipe module defines its own EventSubscriber to handle response using BigPipeResponse.

Where does BigPipe do the heavy-lifting of chunked response?

BigPipe defines another service to handle this big_pipe.

This service is actually responsible for the heavy lifting needed for chunk-ed response. The control is passed down to this service from BigPipeResponse class we discussed int he above section. Its responsible for:

Helper functions:

Where are the AJAX commands set in the BigPipe placeholders processed?

BigPipe defines its own library for handling assets & defines big_pipe.js in it.

Javascript is responsible for:

The complete magic recipe for rendering the blocks in parallel is above. 

Thats pretty much it from my end. I'd really like to thank Wim LeersFabianx and others who worked really hard on bringing this caching strategy to Drupal 8 and working on getting it into core with 8.1 release.

We'd love to talk about your business objectives

Written by