
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Mon, 13 Apr 2026 09:44:05 GMT</lastBuildDate>
        <item>
            <title><![CDATA[New standards for a faster and more private Internet]]></title>
            <link>https://blog.cloudflare.com/new-standards/</link>
            <pubDate>Wed, 25 Sep 2024 13:00:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare's customers can now take advantage of Zstandard (zstd) compression, offering 42% faster compression than Brotli and 11.3% more efficiency than GZIP. We're further optimizing performance for our customers with HTTP/3 prioritization and BBR congestion control, and enhancing privacy through Encrypted Client Hello (ECH). ]]></description>
            <content:encoded><![CDATA[ <p>As the Internet grows, so do the demands for speed and security. At Cloudflare, we’ve spent the last 14 years simplifying the adoption of the latest web technologies, ensuring that our users stay ahead without the complexity. From being the first to offer <a href="https://www.cloudflare.com/application-services/products/ssl/">free SSL certificates</a> through <a href="https://blog.cloudflare.com/introducing-universal-ssl/"><u>Universal SSL</u></a> to quickly supporting innovations like <a href="https://blog.cloudflare.com/introducing-tls-1-3"><u>TLS 1.3</u></a>, <a href="https://blog.cloudflare.com/introducing-cloudflares-automatic-ipv6-gatewa/"><u>IPv6</u></a>, and <a href="https://blog.cloudflare.com/http-3-from-root-to-tip/"><u>HTTP/3</u></a>, we've consistently made it easy for everyone to harness cutting-edge advancements.</p><p>One of the most exciting recent developments in web performance is Zstandard (zstd) — a new compression algorithm that we have found compresses data 42% faster than Brotli while maintaining almost the same compression levels. Not only that, but Zstandard reduces file sizes by 11.3% compared to GZIP, all while maintaining comparable speeds. As compression speed and efficiency directly impact latency, this is a game changer for improving user experiences across the web.</p><p>We’re also re-starting the <a href="https://blog.cloudflare.com/announcing-encrypted-client-hello/"><u>rollout of Encrypted Client Hello (ECH)</u></a>, a <a href="https://datatracker.ietf.org/doc/draft-ietf-tls-esni/"><u>new proposed standard </u></a>that prevents networks from snooping on which websites a user is visiting. <a href="https://blog.cloudflare.com/encrypted-client-hello/"><u>Encrypted Client Hello (ECH) is a successor to ESNI</u></a> and masks the <a href="https://www.cloudflare.com/en-gb/learning/ssl/what-is-sni/"><u>Server Name Indication (SNI)</u></a> that is used to negotiate a TLS handshake. This means that whenever a user visits a website on Cloudflare that has ECH enabled, no one except for the user, Cloudflare, and the website owner will be able to determine which website was visited. Cloudflare is a big proponent of privacy for everyone and is excited about the prospects of bringing this technology to life.</p><p>In this post, we also further explore our work measuring the impact of HTTP/3 prioritization, and the development of Bottleneck Bandwidth and Round-trip propagation time (BBR) congestion control to further optimize network performance.</p>
    <div>
      <h2>Introducing Zstandard compression</h2>
      <a href="#introducing-zstandard-compression">
        
      </a>
    </div>
    <p><a href="https://github.com/facebook/zstd"><u>Zstandard</u></a>, an advanced compression algorithm, was developed by <a href="https://engineering.fb.com/2018/12/19/core-infra/zstandard/"><u>Yann Collet at Facebook</u></a> and open sourced in August 2016 to manage large-scale data processing.  It has gained popularity in recent years due to its impressive compression ratios and speed. The protocol was included in <a href="https://chromestatus.com/feature/6186023867908096"><u>Chromium-based browsers</u></a> and <a href="https://connect.mozilla.org/t5/ideas/add-support-for-zstd-compression/idi-p/52155"><u>Firefox</u></a> in March 2024 as a <a href="https://caniuse.com/zstd"><u>supported</u></a> compression algorithm. </p><p>Today, we are excited to announce that Zstandard compression between Cloudflare and browsers is now available to everyone. </p><p>Our testing shows that Zstandard compresses data up to 42% faster than <a href="https://github.com/google/brotli"><u>Brotli</u></a> while achieving nearly equivalent data compression. Additionally, Zstandard outperforms <a href="https://datatracker.ietf.org/doc/html/rfc1952"><u>GZIP</u></a> by approximately 11.3% in compression efficiency, all while maintaining similar compression speeds. This means Zstandard can compress files to the same size as Brotli but in nearly half the time, speeding up your website without sacrificing performance.

This is exciting because compression speed and file size directly impacts latency. When a browser requests a resource from the origin server, the server needs time to compress the data before it’s sent over the network. A faster compression algorithm, like Zstandard, reduces this initial processing time. By also reducing the size of files transmitted over the Internet, better compression means downloads take less time to complete, websites load quicker, and users ultimately get a better experience.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6HSjbMJGtBI4GJlBp2Jf35/e2f971157f078636c6702f40f2c03a70/image2.png" />
            
            </figure>
    <div>
      <h3>Why is compression so important?</h3>
      <a href="#why-is-compression-so-important">
        
      </a>
    </div>
    <p>Website performance is crucial to the success of online businesses. <a href="https://www2.deloitte.com/content/dam/Deloitte/ie/Documents/Consulting/Milliseconds_Make_Millions_report.pdf"><u>Study</u></a> after <a href="https://www.thinkwithgoogle.com/_qs/documents/4290/c676a_Google_MobileSiteSpeed_Playbook_v2.1_digital_4JWkGQT.pdf"><u>study</u></a> has shown that an increased load time <a href="https://www.cloudflare.com/learning/performance/more/website-performance-conversion-rates/"><u>directly affects sales</u></a>. In highly competitive markets, the performance of a website is crucial for success. Just like a physical shop situated in a remote area faces challenges in attracting customers, a slow website encounters similar difficulties in attracting traffic. 

Think about buying a piece of flat pack furniture such as a bookshelf. Instead of receiving the bookshelf fully assembled, which would be expensive and cumbersome to transport, you receive it in a compact, flat box with all the components neatly organized, ready for assembly. The parts are carefully arranged to take up the least amount of space, making the package much smaller and easier to handle. When you get the item, you simply follow the instructions to assemble it to its proper state. </p><p>This is similar to how data compression works. The data is “disassembled” and packed tightly to reduce its size before being transmitted. Once it reaches its destination, it’s “reassembled” to its original form. This compression process reduces the amount of data that needs to be sent, saving bandwidth, reducing costs, and speeding up the transfer, just like how flat pack furniture reduces shipping costs and simplifies delivery logistics.</p><p>However, with compression, there is a tradeoff: time to compress versus the overall compression ratio. A compression ratio is a measure of how much a file's size is reduced during compression. For example, a 10:1 compression ratio means that the compressed file is one-tenth the size of the original. Just like assembling flat-pack furniture takes time and effort, achieving higher compression ratios often requires more processing time. While a higher compression ratio significantly reduces file size — making data transmission faster and more efficient — it may take longer to compress and decompress the data. Conversely, quicker compression methods might produce larger files, leading to faster processing but at the cost of greater bandwidth usage. Balancing these factors is key to optimizing performance in data transmission.</p><p><a href="https://w3techs.com/technologies/details/ce-compression"><u>W3 Technologies</u></a> reports that as of September 12, 2024, 88.6% of websites rely on compression to optimize speed and reduce bandwidth usage. <a href="https://datatracker.ietf.org/doc/html/rfc1952"><u>GZIP</u></a>, introduced in 1996, remains the default algorithm for many, used by 57.0% of sites due to its reasonable compression ratios and fast compression speeds. <a href="https://datatracker.ietf.org/doc/html/rfc7932"><u>Brotli</u></a>, released by Google in 2016, delivers better <a href="https://blog.cloudflare.com/results-experimenting-brotli/"><u>compression ratios</u></a>, leading to smaller file sizes, especially for static assets like JavaScript and CSS, and is used by 45.5% of websites. However, this also means that 11.4% of websites still operate without any compression, missing out on crucial performance improvements.</p><p>As the Internet and its supporting infrastructure have evolved, so have user demands for faster, more efficient performance. This growing need for higher efficiency without compromising speed is where Zstandard comes into play.</p>
    <div>
      <h3>Enter Zstandard</h3>
      <a href="#enter-zstandard">
        
      </a>
    </div>
    <p>Zstandard offers higher compression ratios comparable to GZIP, but with significantly faster compression and decompression speeds than Brotli. This makes it ideal for real-time applications that require both speed and relatively high compression ratios.</p><p>To understand Zstandard's advantages, it's helpful to know about <a href="https://blog.cloudflare.com/cloudflare-fights-cancer/"><u>Zlib</u></a>. Zlib was developed in the mid-1990s based on the <a href="https://en.wikipedia.org/wiki/DEFLATE"><u>DEFLATE</u></a> compression algorithm, which combines <a href="https://www.cloudflare.com/en-gb/learning/performance/glossary/what-is-image-compression/"><u>LZ77 and Huffman coding</u></a> to reduce file sizes. While Zlib has been a compression standard since the mid-1990s and is used in Cloudflare’s <a href="https://blog.cloudflare.com/cloudflare-fights-cancer/"><u>open-source</u></a> GZIP implementation, its design is limited by a 32 KB sliding window — a constraint from the memory limitations of that era. This makes Zlib less efficient on modern hardware, which can access far more memory.</p><p>Zstandard enhances Zlib by leveraging modern innovations and hardware capabilities. Unlike Zlib’s fixed 32 KB window, Zstandard has no strict memory constraints and can theoretically address terabytes of memory. However,  in practice, it typically uses much less, around 1 MB at lower compression levels. This flexibility allows Zstandard to buffer large amounts of data, enabling it to identify and compress repeating patterns more effectively. Zstandard also employs <a href="https://engineering.fb.com/2016/08/31/core-infra/smaller-and-faster-data-compression-with-zstandard/#:~:text=Repcode%20modeling,within%20zlib/gzip."><u>repcode modeling</u></a> to efficiently compress structured data with repetitive sequences, further reducing file sizes and enhancing its suitability for modern compression needs.</p><p>Zstandard is optimized for modern CPUs, which can execute multiple tasks simultaneously using multiple Arithmetic Logic Units (ALUs) that are used to perform mathematical tasks. Zstandard achieves this by processing data in parallel streams, dividing it into multiple parts that are processed concurrently. <a href="https://chromium.googlesource.com/external/github.com/klauspost/compress/+/refs/heads/master/huff0/"><u>The Huffman decoder, Huff0</u></a>, can decode multiple symbols in parallel on a single CPU core, and when combined with multi-threading, this leads to substantial speed improvements during both compression and decompression.</p><p>Zstandard’s branchless design is a crucial innovation that enhances CPU efficiency, especially in modern processors. To understand its significance, consider how CPUs execute instructions.</p><p>Modern CPUs use pipelining, where different stages of an instruction are processed simultaneously—like a production line—keeping all parts of the processor busy. However, when CPUs encounter a branch, such as an 'if-else' decision, they must make a <a href="https://blog.cloudflare.com/branch-predictor/"><u>branch prediction</u></a> to guess the next step. If the prediction is wrong, the pipeline must be cleared and restarted, causing slowdowns.</p><p>Zstandard avoids this issue by eliminating conditional branching. Without relying on branch predictions, it ensures the CPU can execute instructions continuously, keeping the pipeline full and avoiding performance bottlenecks.</p><p>A key feature of Zstandard is its use of <a href="https://www.rfc-editor.org/rfc/rfc8478.html#section-4.1"><u>Finite State Entropy (FSE)</u></a>, an advanced compression method that encodes data more efficiently based on probability. FSE, built on the <a href="https://en.wikipedia.org/wiki/Asymmetric_numeral_systems"><u>Asymmetric Numeral System (ANS)</u></a>, allows Zstandard to use fractional bits for encoding, unlike traditional Huffman coding, which only uses whole bits. This allows heavily repeated data to be compressed more tightly without sacrificing efficiency.</p>
    <div>
      <h3>Zstandard findings</h3>
      <a href="#zstandard-findings">
        
      </a>
    </div>
    <p>In the third quarter of 2024, we conducted extensive tests on our new Zstandard compression module, focusing on a 24-hour period where we switched the default compression algorithm from Brotli to Zstandard across our Free plan traffic. This experiment spanned billions of requests, covering a wide range of file types and sizes, including HTML, CSS, and JavaScript. The results were very promising, with significant improvements in both compression speed and file size reduction, leading to faster load times and more efficient bandwidth usage.</p>
    <div>
      <h4>Compression ratios</h4>
      <a href="#compression-ratios">
        
      </a>
    </div>
    <p>In terms of compression efficiency, Zstandard delivers impressive results. Below are the average compression ratios we observed during our testing.</p><table><tr><td><p><b>Compression Algorithm</b></p></td><td><p><b>Average Compression Ratio</b></p></td></tr><tr><td><p>GZIP</p></td><td><p>2.56</p></td></tr><tr><td><p>Zstandard</p></td><td><p>2.86</p></td></tr><tr><td><p>Brotli</p></td><td><p>3.08</p></td></tr></table>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2EA8KkP7M3j4KiEArzmXVT/2a93b972f531f02f6b253e231f73ff40/image5.png" />
            
            </figure><p>As the table shows, Zstandard achieves an average compression ratio of <b>2.86:1</b>, which is notably higher than gzip's <b>2.56:1</b> and close to Brotli’s <b>3.08:1</b>. While Brotli slightly edges out Zstandard in terms of pure compression ratio, what is particularly exciting is that we are only using Zstandard’s default compression level of 3 (out of 22) on our traffic. In the fourth quarter of 2024, we plan to experiment with higher compression levels and multithreading capabilities to further enhance Zstandard’s performance and optimize results even more.</p>
    <div>
      <h4>Compression speeds</h4>
      <a href="#compression-speeds">
        
      </a>
    </div>
    <p>What truly sets Zstandard apart is its speed. Below are the average times to compress data from our traffic-based tests measured in milliseconds:</p><table><tr><td><p><b>Compression Algorithm</b></p></td><td><p><b>Average Time to Compress (ms)</b></p></td></tr><tr><td><p>GZIP</p></td><td><p>0.872</p></td></tr><tr><td><p>Zstandard</p></td><td><p>0.848</p></td></tr><tr><td><p>Brotli</p></td><td><p>1.544</p></td></tr></table>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/15AxPyO1PmyV6hDRRjBznu/9cf16cfdc146afddbf9a3332da29629a/image10.png" />
            
            </figure><p>Zstandard not only compresses data efficiently, but it also does so <b>42% faster</b> than Brotli, with an average compression time of <b>0.848 ms</b> compared to Brotli’s <b>1.544 ms</b>. It even outperforms gzip, which compresses at <b>0.872 ms</b> on average.</p><p>From our results, we have found Zstandard strikes an excellent balance between achieving a high compression ratio and maintaining fast compression speed, making it particularly well-suited for dynamic content such as HTML and non-cacheable sensitive data. Zstandard can compress these responses from the origin quickly and efficiently, saving time compared to Brotli while providing better compression ratios than GZIP.</p>
    <div>
      <h3>Implementing Zstandard at Cloudflare</h3>
      <a href="#implementing-zstandard-at-cloudflare">
        
      </a>
    </div>
    <p>To implement Zstandard compression at Cloudflare, we needed to build it into our Nginx-based service which already handles GZIP and Brotli compression. Nginx is modular by design, with each module performing a specific function, such as compressing a response. Our custom Nginx module leverages Nginx's function 'hooks' — specifically, the header filter and body filter — to implement Zstandard compression.</p>
    <div>
      <h4>Header filter</h4>
      <a href="#header-filter">
        
      </a>
    </div>
    <p>The header filter allows us to access and modify response headers. For example, Cloudflare only compresses responses above a certain size (50 bytes for Zstandard), which is enforced with this code:</p>
            <pre><code>if (r-&gt;headers_out.content_length_n != -1 &amp;&amp;
    r-&gt;headers_out.content_length_n &lt; conf-&gt;min_length) {
    return ngx_http_next_header_filter(r);
}</code></pre>
            <p>Here, we check the "Content-Length" header. If the content length is less than our minimum threshold, we skip compression and let Nginx execute the next module.</p><p>We also need to ensure the content is not already compressed by checking the "Content-Encoding" header:</p>
            <pre><code>if (r-&gt;headers_out.content_encoding &amp;&amp;
    r-&gt;headers_out.content_encoding-&gt;value.len) {
    return ngx_http_next_header_filter(r);
}</code></pre>
            <p>If the content is already compressed, the module is bypassed, and Nginx proceeds to the next header filter.</p>
    <div>
      <h4>Body filter</h4>
      <a href="#body-filter">
        
      </a>
    </div>
    <p>The body filter hook is where the actual processing of the response body occurs. In our case, this involves compressing the data with the Zstandard encoder and streaming the compressed data back to the client. Since responses can be very large, it's not feasible to buffer the entire response in memory, so we manage internal memory buffers carefully to avoid running out of memory.</p><p>The Zstandard library is well-suited for streaming compression and provides the <code>ZSTD_compressStream2</code> function:</p>
            <pre><code>ZSTDLIB_API size_t ZSTD_compressStream2(ZSTD_CCtx* cctx,
                                        ZSTD_outBuffer* output,
                                        ZSTD_inBuffer* input,
                                        ZSTD_EndDirective endOp);</code></pre>
            <p>This function can be called repeatedly with chunks of input data to be compressed. It accepts input and output buffers and an "operation" parameter (<code>ZSTD_EndDirective endOp</code>) that controls whether to continue feeding data, flush the data, or finalize the compression process.</p><p>Nginx uses a "flush" flag on memory buffers to indicate when data can be sent. Our module uses this flag to set the appropriate Zstandard operation:</p>
            <pre><code>switch (zstd_operation) {
    case ZSTD_e_continue: {
        if (flush) {
            zstd_operation = ZSTD_e_flush;
        }
    }
}
</code></pre>
            <p>This logic allows us to switch from the "ZSTD_e_continue" operation, which feeds more input data into the encoder, to "ZSTD_e_flush", which extracts compressed data from the encoder.</p>
    <div>
      <h4>Compression cycle</h4>
      <a href="#compression-cycle">
        
      </a>
    </div>
    <p>The compression module operates in the following cycle:</p><ol><li><p>Receive uncompressed data.</p></li><li><p>Locate an internal buffer to store compressed data.</p></li><li><p>Compress the data with Zstandard.</p></li><li><p>Send the compressed data back to the client.</p></li></ol><p>Once a buffer is filled with compressed data, it’s passed to the next Nginx module and eventually sent to the client. When the buffer is no longer in use, it can be recycled, avoiding unnecessary memory allocation. This process is managed as follows:</p>
            <pre><code>if (free) {
    // A free buffer is available, so use it
    buffer = free;
} else if (buffers_used &lt; maximum_buffers) {
    // No free buffers, but we're under the limit, so allocate a new one
    buffer = create_buf();
} else {
    // No free buffers and can't allocate more
    err = no_memory;
}
</code></pre>
            
    <div>
      <h4>Handling backpressure</h4>
      <a href="#handling-backpressure">
        
      </a>
    </div>
    <p>If no buffers are available, it can lead to backpressure — a situation where the Zstandard module generates compressed data faster than the client can receive it. This causes data to become "stuck" inside Nginx, halting further compression due to memory constraints. In such cases, we stop compression and send an empty buffer to the next Nginx module, allowing Nginx to attempt to send the data to the client again. When successful, this frees up memory buffers that our module can reuse, enabling continued streaming of the compressed response without buffering the entire response in memory.</p>
    <div>
      <h3>What's next? Compression dictionaries</h3>
      <a href="#whats-next-compression-dictionaries">
        
      </a>
    </div>
    <p>The future of Internet compression lies in the use of <a href="https://datatracker.ietf.org/doc/draft-ietf-httpbis-compression-dictionary/"><u>compression dictionaries</u></a>. Both Brotli and Zstandard support dictionaries, offering up to <a href="https://developer.chrome.com/blog/shared-dictionary-compression"><u>90% improvement</u></a> on compression levels compared to using static dictionaries. </p><p>Compression dictionaries store common patterns or sequences of data, allowing algorithms to compress information more efficiently by referencing these patterns rather than repeating them. This concept is akin to how an iPhone's predictive text feature works. For example, if you frequently use the phrase "On My Way," you can customize your iPhone’s dictionary to recognize the abbreviation "OMW" and automatically expand it to "On My Way" when you type it, saving the user from typing six extra letters.</p><table><tr><td><p>O</p></td><td><p>M</p></td><td><p>W</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>O</p></td><td><p>n</p></td><td><p>
</p></td><td><p>M</p></td><td><p>y</p></td><td><p>
</p></td><td><p>W</p></td><td><p>a</p></td><td><p>y</p></td></tr></table><p>Traditionally, compression algorithms use a static dictionary defined by its RFC that is shared between clients and origin servers. This static dictionary is designed to be broadly applicable, balancing size and compression effectiveness for general use. However, Zstandard and Brotli support custom dictionaries, tailored specifically to the content being sent to the client. For example, Cloudflare could create a specialized dictionary that focuses on frequently used terms like “Cloudflare”. This custom dictionary would compress these terms more efficiently, and a browser using the same dictionary could decode them accurately, leading to significant improvements in compression and performance.</p><p>In the future, we will enable users to leverage origin-generated dictionaries for Zstandard and Brotli to enhance compression. Another exciting area we're exploring is the use of AI to create these dictionaries dynamically without them needing to be generated at the origin. By analyzing data streams in real-time, Cloudflare could develop context-aware dictionaries tailored to the specific characteristics of the data being processed. This approach would allow users to significantly improve both compression ratios and processing speed for their applications.</p>
    <div>
      <h3>Compression Rules for everyone</h3>
      <a href="#compression-rules-for-everyone">
        
      </a>
    </div>
    <p>Today we’re also excited to announce the introduction of <a href="https://developers.cloudflare.com/rules/compression-rules/"><u>Compression Rules</u></a> for all our customers. By default, Cloudflare will automatically compress certain content types based on their <a href="https://developers.cloudflare.com/speed/optimization/content/brotli/content-compression"><u>Content-Type headers</u></a>. Customers can use compression rules to optimize how and what Cloudflare compresses. This feature was previously exclusive to our Enterprise plans.

Compression Rules is built on the same robust framework as our other rules products, such as Origin Rules, Custom Firewall Rules, and Cache Rules, with additional fields for Media Type and Extension Type. This allows you to easily specify the content you wish to compress, providing granular control over your site’s performance optimization.</p><p>Compression rules are now available on all our pay-as-you-go plans and will be added to free plans in October 2024. This feature was previously exclusive to our Enterprise customers. In the table below, you’ll find the updated limits, including an increase to 125 Compression Rules for Enterprise plans, aligning with our other rule products' quotas.</p><table><tr><td><p><b>Plan Type</b></p></td><td><p><b>Free*</b></p></td><td><p><b>Pro</b></p></td><td><p><b>Business</b></p></td><td><p><b>Enterprise</b></p></td></tr><tr><td><p>Available Compression Rules</p></td><td><p>10</p></td><td><p>25</p></td><td><p>50</p></td><td><p>125</p></td></tr></table>
    <div>
      <h3>Using Compression Rules to enable Zstandard</h3>
      <a href="#using-compression-rules-to-enable-zstandard">
        
      </a>
    </div>
    <p>To integrate our Zstandard module into our platform, we also added support for it within our Compression Rules framework. This means that customers can now specify Zstandard as their preferred compression method, and our systems will automatically enable the Zstandard module in Nginx, disabling other compression modules when necessary.</p><p>The <code>Accept-Encoding</code> header determines which compression algorithms a client supports. If a browser supports Zstandard (<code>zstd</code>), and both Cloudflare and the zone have enabled the feature, then Cloudflare will return a Zstandard compressed response.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/tRIwu8JItGU0zyVmeTp2e/232af3ea43893022e5879e8361ed42b7/image4.png" />
            
            </figure><p>If the client does not support Zstandard, then Cloudflare will automatically fall back to Brotli, GZIP, or serve the content uncompressed where no compression algorithm is supported, ensuring compatibility. 

To enable Zstandard for your entire site or specifically filter on certain file types, all Cloudflare users can deploy a simple compression rule.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2WiodFBfD02mlPASLABkz5/e9a66b552ba46e423f352e502792b398/image3.png" />
            
            </figure><p>Further details and examples of what can be accomplished with Compression Rules can be found in our <a href="https://developers.cloudflare.com/rules/compression-rules/"><u>developer documentation</u></a>.</p><p>Currently, we support Zstandard, Brotli, and GZIP as compression algorithms for traffic sent to clients, and support GZIP and Brotli (since <a href="https://blog.cloudflare.com/this-is-brotli-from-origin/"><u>2023</u></a>) compressed data from the origin. We plan to implement full end-to-end support for Zstandard in 2025, offering customers another effective way to reduce their egress costs.</p><p>Once Zstandard is enabled, you can view your browser’s <a href="https://developer.chrome.com/docs/devtools/network"><u>Network Activity</u></a> log to check the content-encoding headers of the response.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1CujaUsXiEFee79Ny27Zks/1f7ef23910d4bad47c203ad311866951/image11.png" />
            
            </figure><p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5JIvK4tNjlxd7uFlWyEJoc/e426053d2c895c980f4c1370379c7b2e/image1.png" />
            
            </figure>
    <div>
      <h3>Enable Zstandard now!</h3>
      <a href="#enable-zstandard-now">
        
      </a>
    </div>
    <p>Zstandard is now available to all Cloudflare customers through <a href="https://dash.cloudflare.com/?to=/:account/:zone/rules/compression-rules"><u>Compression Rules</u></a> on our Enterprise and pay as you go plans, with free plans gaining access in October 2024. Whether you're optimizing for speed or aiming to reduce bandwidth, <a href="https://dash.cloudflare.com/?to=/:account/:zone/rules/compression-rules"><u>Compression Rules</u></a> give all customers granular control over their site's performance.</p>
    <div>
      <h2>Encrypted Client Hello (ECH)</h2>
      <a href="#encrypted-client-hello-ech">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4BFVDlJK6Mxn0P1yk5UdHK/e348084642480eeaec9861a76e32d5f2/image9.png" />
          </figure><p>While performance is crucial for delivering a fast user experience, ensuring privacy is equally important in today’s Internet landscape. As we optimize for speed with Zstandard, Cloudflare is also working to protect users' sensitive information from being exposed during data transmission. With web traffic growing more complex and interconnected, it's critical to keep both performance and privacy in balance. This is where technologies like Encrypted Client Hello (ECH) come into play, securing connections without sacrificing speed.</p><p>Ten years ago, we embarked on a mission to create a more secure and encrypted web. At the time, much of the Internet remained unencrypted, leaving user data vulnerable to interception. On September 27, 2014, we took a major step forward by enabling HTTPS for free for all Cloudflare customers. Overnight, we doubled the size of the encrypted web. This set the stage for a more secure Internet, ensuring that encryption was not a privilege limited by budget but a right accessible to everyone.</p><p>Since then, both Cloudflare and the broader community have helped encrypt more of the Internet. Projects like <a href="https://letsencrypt.org/"><u>Let's Encrypt</u></a> launched to make certificates free for everyone. Cloudflare invested to encrypt more of the connection, and future-proof that encryption from coming technologies like <a href="https://blog.cloudflare.com/post-quantum-for-all/"><u>quantum computers</u></a>. We've always believed that it was everyone's right, regardless of your budget, to have an encrypted Internet at no cost.</p><p>One of the last major challenges has been securing the SNI (Server Name Identifier), which remains exposed in plaintext during the TLS handshake. This is where Encrypted Client Hello (ECH) comes in, and today, we are proud to announce that we're closing that gap. </p><p>Cloudflare announced support for <a href="https://blog.cloudflare.com/announcing-encrypted-client-hello/"><u>Encrypted Client Hello (ECH)</u></a> in 2023 and has continued to enhance its implementation in collaboration with our Internet browser partners. During a TLS handshake, one of the key pieces of information exchanged is the <a href="https://www.cloudflare.com/learning/ssl/what-is-sni/"><u>Server Name Indication (SNI)</u></a>, which is used to initiate a secure connection. Unfortunately, the SNI is sent in plaintext, meaning anyone can read it. Imagine hand-delivering a letter — anyone following you can see where you're delivering it, even if they don’t know the contents. With ECH, it is like sending the same confidential letter to a P.O. Box. You place your sensitive letter in a sealed inner envelope with the actual address. Then, you put that envelope into a larger, standard envelope addressed to a public P.O. Box, trusted to securely forward your intended recipient. The larger envelope containing the non-sensitive information is visible to everyone, while the inner envelope holds the confidential details, such as the actual address and recipient. Just as the P.O. Box maintains the anonymity of the true recipient’s address, ECH ensures that the SNI remains protected. </p><p>While encrypting the SNI is a primary motivation for ECH, its benefits extend further. ECH encrypts the entire Client Hello, ensuring user privacy and enabling TLS to evolve without exposing sensitive connection data. By securing the full handshake, ECH allows for flexible, future-proof encryption designs that safeguard privacy as the Internet continues to grow.</p>
    <div>
      <h3>How ECH works</h3>
      <a href="#how-ech-works">
        
      </a>
    </div>
    <p>Encrypted Client Hello (ECH) introduces a layer of privacy by dividing the ClientHello message into two distinct parts: a ClientHelloOuter and a ClientHelloInner. </p><ul><li><p><b>ClientHelloOuter</b>: This part remains unencrypted and contains innocuous values for sensitive TLS extensions. It sets the SNI to Cloudflare’s public name, currently set to cloudflare-ech.com. Cloudflare manages this domain and possesses the necessary certificates to handle TLS negotiations for it.</p></li><li><p><b>ClientHelloInner</b>: This part is encrypted with a public key and includes the actual server name the client wants to visit, along with other sensitive TLS extensions. The encryption scheme ensures that this sensitive data can only be decrypted by the client-facing server, which in our case is Cloudflare.</p></li></ul><p>During the TLS handshake, the ClientHelloOuter reveals only the public name (e.g., cloudflare-ech.com), while the encrypted ClientHelloInner carries the real server name. As a result, intermediaries observing the traffic will only see cloudflare-ech.com in plaintext, concealing the actual destination.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5C7EUMmlYp3gmvfvnbeKul/ea62a3c648cd859bbb46bb6fe0761645/image13.png" />
          </figure><p>The design of ECH effectively addresses many challenges in securely deploying handshake encryption, thanks to the collaborative efforts within the <a href="https://datatracker.ietf.org/doc/draft-ietf-tls-esni/"><u>IETF community</u></a>. The key to ECH’s success is its integration with other IETF standards, including the new <a href="https://datatracker.ietf.org/doc/html/rfc9460"><u>HTTPS DNS resource record</u></a>, which enables HTTPS endpoints to advertise different TLS capabilities and simplifies key distribution. By using <a href="https://blog.cloudflare.com/dns-encryption-explained/"><u>Encrypted DNS</u></a> methods, browsers and clients can anonymously query these HTTPS records. These records contain the ECH parameters needed to initiate a secure connection. </p><p>ECH leverages the <a href="https://blog.cloudflare.com/hybrid-public-key-encryption/"><u>Hybrid Public Key Encryption (HPKE)</u></a> standard, which streamlines the handshake encryption process, making it more secure and easier to implement. Before initiating a layer 4 connection, the user’s browser makes a DNS request for an HTTPS record, and zones with ECH enabled will include an ECH configuration in the HTTPS record containing an encryption public key and some associated metadata. For example, looking at the zone cloudflare-ech.com, you can see the following record returned:</p>
            <pre><code>dig cloudflare-ech.com https +short


1 . alpn="h3,h2" ipv4hint=104.18.10.118,104.18.11.118 ech=AEX+DQBB2gAgACD1W1B+GxY3nZ53Rigpsp0xlL6+80qcvZtgwjsIs4YoOwAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA= ipv6hint=2606:4700::6812:a76,2606:4700::6812:b76</code></pre>
            <p>Aside from the public key used by the client to encrypt ClientHelloInner and other <a href="https://www.ietf.org/archive/id/draft-ietf-tls-esni-20.html#name-encrypted-clienthello-confi"><u>parameters</u></a> that specify the ECH configuration, the configured public name is also present.</p>
            <pre><code>Y2xvdWRmbGFyZS1lY2guY29t</code></pre>
            <p>When the string is decoded it reveals:</p>
            <pre><code>cloudflare-ech.com</code></pre>
            <p>This public name is then used by the client in the ClientHelloOuter.</p>
    <div>
      <h3>Practical implications</h3>
      <a href="#practical-implications">
        
      </a>
    </div>
    <p>With ECH, any observer monitoring the traffic between the client and Cloudflare will see only uniform TLS handshakes that appear to be directed towards <code>cloudflare-ech.com</code>, regardless of the actual website being accessed. For instance, if a user visits <code>example.com</code>, intermediaries will not discern this specific destination but will only see <code>cloudflare-ech.com</code> in the visible handshake data. </p>
    <div>
      <h3>The problem with middleboxes</h3>
      <a href="#the-problem-with-middleboxes">
        
      </a>
    </div>
    <p>In a basic HTTPS connection, a browser (client) establishes a TLS connection directly with an origin server to send requests and download content. However, many connections on the Internet do not go directly from a browser to the server but instead pass through some form of proxy or middlebox (often referred to as a "monster-in-the-middle" or MITM). This routing through intermediaries can occur for various reasons, both benign and malicious.</p><p>One common type of HTTPS interceptor is the TLS-terminating forward proxy. This proxy sits between the client and the destination server, transparently forwarding and potentially modifying traffic. To perform this task, the proxy terminates the TLS connection from the client, decrypts the traffic, and then re-encrypts and forwards it to the destination server over a new TLS connection. To avoid browser certificate validation errors, these forward proxies typically require users to install a root certificate on their devices. This root certificate allows the proxy to generate and present a trusted certificate for the destination server, a process often managed by network administrators in corporate environments, as seen with <a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/"><u>Cloudflare WARP</u></a>. These services can help prevent sensitive company data from being transmitted to unauthorized destinations, safeguarding confidentiality.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2xfA7PB61KxnbZ96XRLahh/975153cfcd831f67f47f638ec9578cdb/image8.png" />
          </figure><p>However, TLS-terminating forward proxies may not be equipped to handle Encrypted Client Hello (ECH) correctly, especially if the MITM proxy and the client facing ECH server belong to different entities.  Because the MITM proxy will terminate the TLS connection without being ECH aware, it may provide a valid certificate for the public name (in our case, cloudflare-ech.com) without being able to decrypt the ClientHelloInner or provide a new public key for the client to use. In this case, the client considers ECH to be disabled, which means you lose out on both ECH and pay the cost of an extra round trip. </p><p>We also observed that specific Cloudflare setups, such as <a href="https://developers.cloudflare.com/dns/cname-flattening/"><u>CNAME Flattening</u></a> and <a href="https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/"><u>Orange-to-Orange configurations</u></a>, could cause ECH to break. This issue arose because the end destination for these connections did not support TLS 1.3, preventing ECH from being processed correctly. Fortunately, in close collaboration with our browser partners, we implemented a fallback in our <a href="https://boringssl.googlesource.com/boringssl/+/d274b1bacdca36f3941bf78e43dc38acf676a1a8"><u>BoringSSL</u></a> implementation that handles TLS terminations. This fallback allows browsers to retry connections over TLS 1.2 without ECH, ensuring that a connection can be established and not break.</p><p>As a result of these improvements, we have enabled ECH by default for all Free plans, while all other plan types can manually enable it through their <a href="https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/edge-certificates#ech-card"><u>Cloudflare dashboard</u></a> or via the API. We are excited to support ECH at scale, enhancing the privacy and security of users' browsing activities. ECH plays a crucial role in safeguarding online interactions from potential eavesdroppers and maintaining the confidentiality of web activities.</p>
    <div>
      <h2>HTTP/3 Prioritization and QUIC congestion control</h2>
      <a href="#http-3-prioritization-and-quic-congestion-control">
        
      </a>
    </div>
    <p>Two other areas we are investing in to improve performance for all our customers are <a href="https://blog.cloudflare.com/better-http-3-prioritization-for-a-faster-web/"><u>HTTP/3 Prioritization</u></a> and QUIC congestion control. </p><p>HTTP/3 Prioritization focuses on efficiently managing the order in which web assets are loaded, thereby improving web performance by ensuring critical assets are delivered faster. HTTP/3 Prioritization uses Extensible Priorities to simplify prioritization with two parameters: urgency (ranging from 0-7) and a true/false value indicating whether the resource can be processed progressively. This allows resources like HTML, CSS, and images to be prioritized based on importance.</p><p>On the other hand, QUIC congestion control aims to optimize the flow of data, preventing network bottlenecks and ensuring smooth, reliable transmission even under heavy traffic conditions. </p><p>Both of these improvements significantly impact how Cloudflare’s network serves requests to clients. Before deploying these technologies across our global network, which handles peak traffic volumes of over 80 million requests per second, we first developed a reliable method to measure their impact through rigorous experimentation.</p>
    <div>
      <h3>Measuring impact</h3>
      <a href="#measuring-impact">
        
      </a>
    </div>
    <p>Accurately measuring the impact of features implemented by Cloudflare for our customers is crucial for several reasons. These measurements ensure that optimizations related to performance, security, or reliability deliver the intended benefits without introducing new issues. Precise measurement validates the effectiveness of these changes, allowing Cloudflare to assess improvements in metrics such as load times, user experience, and overall site security. One of the best ways to measure performance changes is through aggregated real-world data.</p><p><a href="https://developers.cloudflare.com/pages/how-to/web-analytics/"><u>Cloudflare Web Analytics</u></a> offers free, privacy-first analytics for your website, helping you understand the performance of your web pages as experienced by your visitors. Real User Metrics (RUM) is a vital tool in web performance optimization, capturing data from real users interacting with a website, providing insights into site performance under real-world conditions. RUM tracks various metrics directly from the user's device, including load times, resource usage, and user interactions. This data is essential for understanding the actual user experience, as it reflects the diverse environments and conditions under which the site is accessed.</p><p>A key performance indicator measured through RUM is <a href="https://web.dev/articles/vitals#core-web-vitals"><u>Core Web Vitals (CWV)</u></a>, a set of metrics defined by Google that quantify crucial aspects of user experience on the web. CWV focuses on three main areas: loading performance, interactivity, and visual stability. The specific metrics include Largest Contentful Paint (LCP), which measures loading performance; First Input Delay (FID), which gauges interactivity; and Cumulative Layout Shift (CLS), which assesses visual stability. By using the CWV measurement in RUM, developers can monitor and optimize their applications to ensure a smoother, faster, and more stable user experience and track the impact of any changes they release.</p><p>Over the last three months we have developed the capability to include valuable information in Server-Timing response headers. When a page that uses Cloudflare Web Analytics is loaded in a browser, the privacy-first client-side script from Web Analytics collects browser metrics and server-timing headers, then sends back this performance data. This data is ingested, aggregated, and made available for querying. The server-timing header includes Layer 4 information, such as Round-Trip Time (RTT) and protocol type (TCP or QUIC). Combined with Core Web Vitals data, this allows us to determine whether an optimization has positively impacted a request compared to a control sample. This capability enables us to release large-scale changes such as HTTP/3 Prioritization or BBR with a clear understanding of their impact across our global network.</p><p>An example of this header contains several key properties that provide valuable information about the network performance as observed by the server:</p>
            <pre><code>server-timing: cfL4;desc="?proto=TCP&amp;rtt=7337&amp;sent=8&amp;recv=8&amp;lost=0&amp;retrans=0&amp;sent_bytes=3419&amp;recv_bytes=832&amp;delivery_rate=548023&amp;cwnd=25&amp;unsent_bytes=0&amp;cid=94dae6b578f91145&amp;ts=225</code></pre>
            <ul><li><p><b>proto</b>: Indicates the transport protocol used</p></li><li><p><b>rtt</b>: Round-Trip Time (RTT), representing the duration of the network round trip as measured by the layer 4 connection using a smoothing algorithm.</p></li><li><p><b>sent</b>: Number of packets sent.</p></li><li><p><b>recv</b>: Number of packets received.</p></li><li><p><b>lost</b>: Number of packets lost.</p></li><li><p><b>retrans</b>: Number of retransmitted packets.</p></li><li><p><b>sent_bytes</b>: Total number of bytes sent.</p></li><li><p><b>recv_bytes</b>: Total number of bytes received.</p></li><li><p><b>delivery_rate</b>: Rate of data delivery, an instantaneous measurement in bytes per second.</p></li><li><p><b>cwnd</b>: Congestion Window, an instantaneous measurement of packet or byte count depending on the protocol.</p></li><li><p><b>unsent_bytes</b>: Number of bytes not yet sent.</p></li><li><p><b>cid</b>: A 16-byte hexadecimal opaque connection ID.</p></li><li><p><b>ts</b>: Timestamp in milliseconds, representing when the data was captured.</p></li></ul><p>This real-time collection of performance data via RUM and Server-Timing headers allows Cloudflare to make data-driven decisions that directly enhance user experience. By continuously analyzing these detailed network and performance insights, we can ensure that future optimizations, such as HTTP/3 Prioritization or BBR deployment, are delivering tangible benefits for our customers.</p>
    <div>
      <h3>Enabling HTTP/3 Prioritization for all plans</h3>
      <a href="#enabling-http-3-prioritization-for-all-plans">
        
      </a>
    </div>
    <p>As part of our focus on improving <a href="https://www.cloudflare.com/learning/performance/what-is-observability/">observability</a> through the integration of the server-timing header, we implemented several minor changes to optimize QUIC handshakes. Notably, we observed positive improvements in our telemetry due to the Layer 4 observability enhancements provided by the server-timing header. These internal findings coincided with third-party measurements, which showed similar improvements in handshake performance.</p><p>In the fourth quarter of 2024, we will apply the same experimental methodology to the HTTP/3 Prioritization support announced during Speed Week 2023. <a href="https://blog.cloudflare.com/better-http-3-prioritization-for-a-faster-web/"><u>HTTP/3 Prioritization</u></a> is designed to enhance the efficiency and speed of loading web pages by intelligently managing the order in which web assets are delivered to users. This is crucial because modern web pages are composed of numerous elements — such as images, scripts, and stylesheets — that vary in importance. Proper prioritization ensures that critical elements, like primary content and layout, load first, delivering a faster and more seamless browsing experience.</p><p>We will use this testing framework to measure performance improvements before enabling the feature across all plan types. This process allows us not only to quantify the benefits but, most importantly, to ensure there are no performance regressions.</p>
    <div>
      <h3>Congestion control</h3>
      <a href="#congestion-control">
        
      </a>
    </div>
    <p>Following the completion of the HTTP/3 Prioritization experiments we will then begin testing different congestion control algorithms, specifically focusing on <a href="https://cloud.google.com/blog/products/networking/tcp-bbr-congestion-control-comes-to-gcp-your-internet-just-got-faster"><u>BBR</u></a> (Bottleneck Bandwidth and Round-trip propagation time) version 3. Congestion control is a crucial mechanism in network communication that aims to optimize data transfer rates while avoiding network congestion. When too much data is sent too quickly over a network, it can lead to congestion, causing packet loss, delays, and reduced overall performance. Think of a busy highway during rush hour. If too many cars (data packets) flood the highway at once, traffic jams occur, slowing everyone down.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1kR4Ekkg2eUPzO4Lj8CrjY/d002875b8f77f782d13bc0ef199ba931/image6.png" />
          </figure><p>Congestion control algorithms act like traffic managers, regulating the flow of data to prevent these “traffic jams,” ensuring that data moves smoothly and efficiently across the network. Each side of a connection runs an algorithm in real time, dynamically adjusting the flow of data based on the current and predicted network conditions.

BBR is an advanced congestion control algorithm, initially developed by Google. BBR seeks to estimate the actual available bandwidth and the minimum round-trip time (RTT) to determine the optimal data flow. This approach allows BBR to maintain high throughput while minimizing latency, leading to more efficient and stable network performance.</p><p><a href="https://github.com/google/bbr/blob/v3/README.md"><u>BBR v3</u></a>, the latest iteration, builds on the strengths of its predecessors BBRv1 and BBRv2 by further refining its bandwidth estimation techniques and enhancing its adaptability to varying network conditions. We found BBR v3 to be faster in several cases compared to our previous implementation of <a href="https://datatracker.ietf.org/doc/html/rfc8312"><u>CUBIC</u></a>. Most importantly, it reduced loss and retransmission rates in our <a href="https://blog.cloudflare.com/introducing-oxy/"><u>Oxy</u></a> proxy implementation.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/61VpPQXJWTHnrnlb7dz2um/f1aecca8fea1bbeced3074d46389c3db/image7.png" />
            
            </figure><p>With these promising results, we are excited to test various congestion control algorithms including BBRv3 for <a href="https://github.com/cloudflare/quiche"><u>quiche</u></a>, our QUIC implementation, across our HTTP/3 traffic. Combining the layer 4 server-timing information with experiments in this area will enable us to explicitly control and measure the impact on real-world metrics.</p>
    <div>
      <h2>The future</h2>
      <a href="#the-future">
        
      </a>
    </div>
    <p>The future of the Internet relies on continuous innovation to meet the growing demands for speed, security, and scalability. Technologies like Zstandard for compression, BBR for congestion control, HTTP/3 prioritization, and Encrypted Client Hello are setting new standards for performance and privacy. By implementing these protocols, web services can achieve faster page load times, more efficient bandwidth usage, and stronger protections for user data.</p><p>These advancements don't just offer incremental improvements, they provide a significant leap forward in optimizing the user experience and safeguarding online interactions. At Cloudflare, we are committed to making these technologies accessible to everyone, empowering businesses to deliver better, faster, and more secure services. </p><p>Stay tuned for more developments as we continue to push the boundaries of what's possible on the web and if you’re passionate about building and implementing the latest Internet innovations, we’re <a href="https://www.cloudflare.com/careers/jobs/"><u>hiring</u></a>!</p> ]]></content:encoded>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[Privacy]]></category>
            <category><![CDATA[Compression]]></category>
            <category><![CDATA[TLS]]></category>
            <guid isPermaLink="false">6YLU1FUKD4lioSrbpOnb5r</guid>
            <dc:creator>Matt Bullock</dc:creator>
            <dc:creator>Maciej Lechowski</dc:creator>
            <dc:creator>Rushil Mehra</dc:creator>
        </item>
        <item>
            <title><![CDATA[Upgrading one of the oldest components in Cloudflare’s software stack]]></title>
            <link>https://blog.cloudflare.com/upgrading-one-of-the-oldest-components-in-cloudflare-software-stack/</link>
            <pubDate>Fri, 31 Mar 2023 13:00:00 GMT</pubDate>
            <description><![CDATA[ Engineers at Cloudflare have improved the release procedure of our largest edge proxy server. The improved process allows us to significantly decrease the amount of memory used during the version upgrade. As a result, we can deploy code faster and more reliably ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Cloudflare serves a huge amount of traffic: 45 million HTTP requests per second on average (as of 2023; 61 million at peak) from more than 285 cities in over 100 countries. What inevitably happens with that kind of scale is that software will be pushed to its limits. As we grew, one of the problems we faced was related to deploying our code. Sometimes, a release would be delayed because of inadequate hardware resources on our servers. Buying more and more hardware is expensive and there are limits to e.g. how much memory we can realistically have on a server. In this article, we explain how we optimised our software and its release process so that no additional resources are needed.</p><p>In order to handle traffic, each of our servers runs a set of specialised proxies. Historically, they were based on NGINX, but increasingly they <a href="/how-we-built-pingora-the-proxy-that-connects-cloudflare-to-the-internet/">include services created in Rust</a>. Out of our proxy applications, FL (Front Line) is the oldest and still has a broad set of responsibilities.</p><p>At its core, it’s one of the last uses of NGINX at Cloudflare. It contains a large amount of business logic that runs many Cloudflare products, using a variety of Lua and Rust libraries. As a result, it consumes a large amount of system resources: up to 50-60 GiB of RAM. As FL grew, it became more and more difficult to release it. The upgrade mechanism requires double the memory (which sometimes is not available) than at runtime. This was causing delays in releases. We have now improved the release procedure of FL, and in effect, removed the need for additional memory during the release process, improving its speed and performance.</p>
    <div>
      <h2>Architecture</h2>
      <a href="#architecture">
        
      </a>
    </div>
    <p>To accomplish all of its work, each FL instance <a href="https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/">runs many workers (individual processes)</a>. By design, individual processes handle requests while the master process controls them and makes sure they stay up. This allows NGINX to handle more traffic by adding more workers. We take advantage of this architecture.</p><p>The number of workers depends on the numbers of total CPU cores present. It’s typically equal to half of the CPU cores available, e.g. on a 128-core CPU we use 64 FL workers.</p>
    <div>
      <h3>So far so good, what's the problem then?</h3>
      <a href="#so-far-so-good-whats-the-problem-then">
        
      </a>
    </div>
    <p>We aim to deploy code in a way that’s transparent to our customers. We want to continue serving requests without interruptions. In practice, this means briefly running both versions of FL at the same time during the upgrade, so that we can flawlessly transition from one version to another. As soon as the new instance is up and running, we begin to shut down the old one, giving it some time to finish its work. In the end, only the new version is left running. NGINX implements this <a href="https://nginx.org/en/docs/control.html">procedure</a> and FL makes use of it.</p><p>After a new version of FL is installed on a server, the upgrade procedure starts. NGINX’s implementation revolves around communicating with the master process using signals. The upgrade process starts by sending the USR2 signal which will start the new master process and its workers.</p><p>At that point, as can be seen below, both versions will be running and processing requests. The unfortunate side effect of this is the memory footprint has been doubled.</p>
            <pre><code>  PID  PPID COMMAND
33126     1 nginx: master process /usr/local/nginx/sbin/nginx
33134 33126 nginx: worker process (nginx)
33135 33126 nginx: worker process (nginx)
33136 33126 nginx: worker process (nginx)
36264 33126 nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nginx: worker process (nginx)
36266 36264 nginx: worker process (nginx)
36267 36264 nginx: worker process (nginx)</code></pre>
            <p>Then, the WINCH signal will be sent to the master process which will then ask its workers to gracefully shut down. Eventually, they will all quit, leaving just the original master process running (which can be shut down with the QUIT signal). The successful outcome of this will leave just the new instance running, which will look similar to this:</p>
            <pre><code>  PID  PPID COMMAND
36264     1 nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nginx: worker process (nginx)
36266 36264 nginx: worker process (nginx)
36267 36264 nginx: worker process (nginx)</code></pre>
            <p>The standard NGINX upgrade mechanism is visualised in this diagram:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2At10yd2Eea3HVDdL0U3N1/23a06f60c88a26071a0dd6e0ccccbb6e/image5-6.png" />
            
            </figure><p>It’s also clearly visible in the memory usage graph below (notice the large bump during the upgrade).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2TZd2iwu6ObkICVMNoRVKV/ef47bb08937c28ac59b66d434091b5d3/image1-60.png" />
            
            </figure><p>The mechanism outlined above has both versions running at the same time for a while. When both sets of workers are running, they are still sharing the same sockets, so all of them accept requests. As the release progresses, ‘old’ workers stop listening and accepting new requests (at that point only the new workers accept new requests). As we release new code multiple times per week, this process is effectively doubling up our memory requirements. At our scale, it’s easy to see how multiplying this event by the number of servers we operate results in an immense waste of memory resources.</p><p>In addition, sometimes servers would take hours to upgrade (a concern especially when we need to release something quickly), as we are waiting to have enough memory available to kick off the reload action.</p>
    <div>
      <h2>New upgrade mechanism</h2>
      <a href="#new-upgrade-mechanism">
        
      </a>
    </div>
    <p>We solved this problem by modifying NGINX's method for upgrading executable. Here's how it works.</p><p>The crux of the problem is that NGINX treats the entire instance (master + workers) as one. When upgrading, we need to start all the workers whilst all the previous ones are still running. Considering the number of workers we use and how heavy they are, this is not sustainable.</p><p>So, instead, we modified NGINX to be able to control individual workers. Rather than starting and stopping them all at once, we can do so by selecting them individually. To accomplish this, the master process and workers understand additional signals compared to the ones NGINX uses. The actual mechanism to accomplish this in NGINX is nearly the same as when handling workers in bulk. However, there’s a crucial difference.</p><p>Typically, NGINX's master process ensures that the right number of workers is actually running (per configuration). If any of them crashes, it will be restarted. This is good, but it doesn't work for our new upgrade mechanism because when we need to shut down a single worker, we don't want the NGINX master process to think that a worker has crashed and needs to be restarted. So we introduced a signal to disable that behaviour in NGINX while we're shutting down a single process.</p>
    <div>
      <h3>Step by step</h3>
      <a href="#step-by-step">
        
      </a>
    </div>
    <p>Our improved mechanism handles each worker individually. Here are the steps:</p><ol><li><p>At the beginning, we have an instance of FL running 64 workers.</p></li><li><p>Disable the feature to automatically restart workers which exit.</p></li><li><p>Shut down a worker from the first (old) instance of FL. We're down to 63 workers.</p></li><li><p>Create a new instance of FL but only with a single worker. We're back to 64 workers but including one from the new version.</p></li><li><p>Re-enable the feature to automatically restart worker processes which exit.</p></li><li><p>We continue this pattern of shutting down a worker from an older instance and creating a new one to replace it. This can be visualised in the diagram below.</p></li></ol>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4ja1ydbwqob5R6Gha1siHf/01e7d09ea1e388a689e267b2d8455dbb/image3-33.png" />
            
            </figure><p>We can observe our new mechanism in action in the graph below. Thanks to our new procedure, our use of memory remains stable during the release.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/P5YwoLGgcP5ckjOrBgq4Q/1cad0069b9e0bd811ee61905a2fe2ffa/image2-28.png" />
            
            </figure><p>But why do we begin by shutting down a worker belonging to an older instance (v1)? This turns out to be important.</p>
    <div>
      <h3>Worker-CPU pinning</h3>
      <a href="#worker-cpu-pinning">
        
      </a>
    </div>
    <p>During this workflow, we also had to take care of CPU pinning. FL workers on our servers are pinned to CPU cores with one process occupying one CPU core to help us distribute resources more efficiently. If we start a new worker first, it will share the CPU core with another one for a brief amount of time. This will make one CPU overloaded compared to other ones running FL, impacting the latency for requests served. That's why we start by freeing up a CPU core which then can be taken over by a new worker rather than starting by creating a new worker.</p><p>For the same reason, pinning of worker processes to cores must be maintained throughout the whole operation. At no point, we can have two different workers sharing a CPU core. We make sure this is the case by executing the whole procedure in the same order every time.</p><p>We start from CPU core 1 (or whichever is the first one used by FL) and do the following:</p><ol><li><p>Shut down a worker that's running there.</p></li><li><p>Create a new worker. NGINX will pin it to the CPU core we have freed up in the previous step.</p></li></ol><p>After doing that for all workers, we end up with a new set of workers which are correctly pinned to their CPU cores.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>At Cloudflare, we need to release new software multiple times per day across our fleet. Standard upgrade mechanism used by NGINX is not suitable at our scale. For this reason, we customised the process to avoid increasing the amount of memory needed to release FL. This enabled us to safely ship code whenever it's needed, everywhere. The custom upgrade mechanism enables us to release a large application such as FL reliably regardless of how much memory we have available on an edge server. We showed that it’s possible to extend NGINX and its built-in upgrade mechanism to accommodate the unique requirements of Cloudflare.</p><p>If you enjoy solving challenging application infrastructure problems and want to help maintain the busiest web server in the world, we’re <a href="https://www.cloudflare.com/careers/jobs/">hiring</a>!</p> ]]></content:encoded>
            <category><![CDATA[NGINX]]></category>
            <guid isPermaLink="false">5Pa64Xa839HvHoQNbzzBM3</guid>
            <dc:creator>Maciej Lechowski</dc:creator>
        </item>
    </channel>
</rss>