Original: http://www.facebook.com/note.php?note_id=389414033919
Translation: http://isd.tencent.com/?p=2419
Author: Changhao Jiang
Website speed is one of the most critical tasks at Facebook. In 2009, we successfully doubled Facebook’s website speed. Several key innovations from our engineering team made this possible. In this article, I will introduce one of our secret weapons, a great underlying technology we call BigPipe.
BigPipe is a fundamentally redesigned dynamic web page serving system. The general idea is to decompose web pages into small chunks called Pagelets, and pipeline them through various execution stages inside both the web server and the browser, similar to the pipelining execution in most modern microprocessors: multiple instruction pipelines go through different processor execution units to achieve optimal performance. Although BigPipe is a re-engineering of the existing web serving process, it requires no changes to existing web browsers or servers; it is implemented entirely in PHP and JavaScript.
Motivation
To better understand BigPipe, we need to understand the existing dynamic web serving system, whose history dates back to the early days of the World Wide Web, yet has changed little compared to its early form. Modern websites feature far more dynamic effects and interactivity than a decade ago, but traditional web serving systems have long been unable to keep pace with the demands of today’s Internet speeds. In the traditional model, the lifecycle of a user request is as follows:
1. The browser sends an HTTP request to the web server.
2. The web server parses the request, then reads the data storage layer, formulates an HTML document, and sends it to the client with an HTTP response.
3. The HTTP response travels across the Internet to the browser.
4. The browser parses the web server’s response, builds a DOM tree from the HTML document, and downloads referenced CSS and JavaScript files.
5. After CSS resources download, the browser parses them and applies them to the DOM tree.
6. After JavaScript resources download, the browser parses and executes them.
The traditional model is highly inefficient for modern websites, because many system operations are sequential and cannot overlap with each other. Optimization techniques such as lazy-loading JavaScript and parallel downloads have been widely adopted by the web community to overcome some limitations. However, these optimizations rarely address the bottleneck caused by the sequential execution order between the web server and the browser. While the web server is busy generating a page, the browser sits idle, wasting its cycles doing nothing. When the web server finishes generating the page and sends it to the browser, the browser becomes the performance bottleneck and the web server can do nothing to help. By overlapping the web server’s generation time with the browser’s rendering time, we not only reduce the end-to-end latency, but also make the page visible to the user much earlier in the visible area, thereby significantly reducing the user’s perceived latency.
Overlapping web server generation time with browser rendering time is particularly useful for content-rich websites like Facebook. A typical Facebook page contains many pieces of data from different sources: friend lists, friend activity, advertisements, and so on. In the traditional page rendering model, the user would have to wait until all these data queries return and the final document is generated, before it is sent to the user’s computer. Any single query’s latency will slow down the generation of the entire final document.
How BigPipe Works
To exploit the parallelism between the web server and the browser, BigPipe first decomposes the web page into multiple addressable Pagelets. Just as a pipelined microprocessor divides the instruction lifecycle into multiple stages (e.g., “instruction fetch”, “instruction decode”, “execute”, “register write-back”), BigPipe’s page generation process is divided into the following stages:
1. Request Parsing: The web server parses and sanity-checks the HTTP request.
2. Data Fetching: The web server fetches data from the storage layer.
3. Markup Generation: The web server generates the HTML markup for the response.
4. Network Transport: The response is transmitted from the web server to the browser.
5. CSS Downloading: The browser downloads the CSS required by the page.
6. DOM Tree Construction and CSS Styling: The browser constructs the DOM document tree, then applies its CSS rules.
7. JavaScript Downloading: The browser downloads JavaScript resources referenced in the page.
8. JavaScript Execution: The browser executes the page’s JavaScript code.
The first three stages are executed by the web server, and the last four stages are executed by the browser. Each Pagelet must go through all these stages sequentially, but BigPipe enables several Pagelets to be in different stages simultaneously.
(Pagelets of the Facebook homepage. Each rectangle corresponds to a Pagelet.)
The picture above uses the Facebook homepage as an example to illustrate how a web page is decomposed into Pagelets. The homepage includes several Pagelets: “Author Pagelet”, “Navigation Pagelet”, “News Feed Pagelet”, “Requests Box Pagelet”, “Ads Pagelet”, “Friend Suggestions”, and “Connections”, etc. They are independent of each other. While the “Navigation Pagelet” is being displayed to the user, the “News Feed Pagelet” might still be generating on the server.
In BigPipe, the lifecycle of a user request is like this: The browser sends an HTTP request to the web server. Upon receiving the HTTP request and performing some comprehensive checks on it, the web server immediately sends back an unclosed HTML document, which includes an HTML
tag and the opening tag of . The tag includes the BigPipe JavaScript library to parse the Pagelet responses received later. Inside the tag, there is a template that specifies the page’s logical structure and placeholders for Pagelets. For example:After flushing this first response to the client, the web server continues to generate Pagelets one by one. As soon as a Pagelet is generated, it is immediately flushed to the client in a JSON-encoded object that includes all the CSS, JavaScript resources needed for the Pagelet, its HTML content, and some metadata. For example:
On the client side, upon receiving a Pagelet via the instruction emitted by “onPageletArrive”, the BigPipe JavaScript library will first download its CSS resources; after the CSS resources are downloaded, BigPipe will display the Pagelet’s HTML markup via its innerHTML. Multiple Pagelets’ CSS can be downloaded at the same time, and they can be displayed in the order determined by their respective CSS download completion. In BigPipe, JavaScript resources have lower priority than CSS and page content. Therefore, BigPipe will not download any JavaScript within any Pagelet before all Pagelets are displayed. Then, all Pagelets’ JavaScript is downloaded asynchronously. Finally, the Pagelet’s JavaScript initialization code executes in the order determined by their respective download completion.
The end result of this highly parallel system is that different execution stages of multiple Pagelets proceed simultaneously. For example, the browser can be downloading the CSS resources for three Pagelets while already displaying the content of another Pagelet, and at the same time, the server is still generating a new Pagelet. From the user’s perspective, the page is rendered progressively. The initial page content is displayed much faster, which greatly reduces the user’s perceived latency. If you want to see the difference firsthand, you can try these links: Traditional Mode and BigPipe. The first link displays the page in traditional single-flush mode. The second link is the page in BigPipe pipeline mode. If your browser version is older, the network speed is slow, and the browser cache is poor, the difference in loading time between the two pages will be even more pronounced.
Performance Test Results
The chart below compares the performance data between the traditional mode and BigPipe, showing the perceived latency for the most important content on the page (for example, the News Feed is considered the most important content on the Facebook homepage) for 75% of users. The data was collected by loading the Facebook homepage 50 times with the browser cache disabled. The chart shows that BigPipe reduces the latency perceived by users in most browsers by half.
<