Documentation Performance behind a CDN (like Cloudflare)

Comparing performance with an without a CDN is complicated, people usually expect better performance with a CDN because they have more points of presence, reducing the latency for connection and TLS hanshake to the nearest PoP, but unfortunately most of the time this can be the result (example):

Direct connection without CDN:

screenshot of an updown status page showing normal performance

Through CDN (e.g. Cloudflare):

screenshot of an updown status page showing very short connection time but long response time

What we see here is that even though the connection and TLS handhake are drastically reduced from most locations because the packets no longer have to travel as far, the response time on the other hand takes much longer and eats away all the gains from lowered latency. Let's see why.

First thing to note here is that by adding a CDN you're adding a network hop, closer to the end-user yes but if the CDN needs to connect to your origin server every time, then the gain is negative. This is the case here and we can see from the timing chart that in the CDN setup, the response time metric (green) is roughly equivalent to the total time metric for the direct check. This means that the CDN has to connect to your origin server every time and so it's even slower than without the CDN.

In order to really gain speed you need to leverage two things: Caching and Keep-Alive.

Caching

When leveraging HTTP caching, the CDN setup will be much faster because it won't need to connect to your origin and will server the page directly from its edge server. If the page your are monitoring can benefit from HTTP caching (if it doesn't change too quickly) make sure you are sending the caching headers to allow public caching (private cache is only for the browser). Here is an example curl request:

$ curl -I https://example.com
HTTP/2 200
date: Mon, 10 Apr 2023 15:45:59 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
cf-cache-status: DYNAMIC
server: cloudflare
cf-ray: 7b5c1eb74f1c33eb-YUL

The important this to note here is the cf-cache-status: DYNAMIC which confirms that this resource is NOT cached by cloudflare. This might be because your origin server responds with no Cache-Control header, or a header explicitly preventing any caching, example:

$ curl -I https://origin.com
HTTP/2 200
date: Mon, 10 Apr 2023 15:49:18 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
pragma: no-cache
expires: -1
cache-control: no-store, no-cache, must-revalidate, max-age=0

So if caching is possible for your site/pages, make sure to return proper caching headers to make the most out of your CDN. Even if you can only cache pages for a couple seconds, and this wouldn't help with updown metrics, it would still make a huge difference to your backend in case of swarm of requests.

Keep-Alive

Even for pages which explicitly refuse caching, it is still possible to get better performance with a CDN but for that you need to make sure the connection between the CDN and your origin server can stay open. For that your origin server needs to support Keep-Alive and respond with the Connection: Keep-Alive header. This way you save the TCP connect and TLS handshake duration, every time the CDN needs to contact your origin. Usually this is supported by default in most HTTP servers but can easily be broken by unaware configuration changes or proxies. We can check that if we issue the same requests multiple times, at some point the response time should decreases, example:

$ time curl -I https://example.com
# ...
real 0m0.435s
user 0m0.069s
sys 0m0.005s

# ..more requests..

$ time curl -I https://example.com
# ...
real 0m0.189s
user 0m0.067s
sys 0m0.005s

This is because this last time the CDN edge node hit by my requests already had an open connection to the origin server and thus skipped the connection + TLS handshake round trips, leading to a much quicker total time. This thing does not last long though (usually between 30 seconds and 2 minutes), so when you have constant traffic it's a great help, but when you only have a couple requests per hour it's not.

Even then...

Finally, even if you manage to get the total time with a CDN to be better than without, it might still not be better for your end-users, because the DNS resolution time, TCP connection time and TLS handshake time (which get the biggest improvement when using a CDN) can most of the time be skipped for subsequent requests in the browser (thanks to Keep-Alive or HTTP/2). So even if the CDN makes these faster, it'll help for the initial connection only but won't help for any subsequent requests while users navigate your site. That's why we believe the response time (green bar in updown status pages) is much more important (this one is not skippable) and so using a CDN which will make the response time longer while reducing the connection time is not always a good idea performance-wise.

Unless of course you can leverage caching a lot or have other specific problems to address. There are plenty of good reasons to use a CDN like DDoS attacks protection, TLS coverage for an HTTP only server, Individual requests reconnecting every time like IoT, hidding origin IPs, etc... But don't just assume it's gonna be faster simply because you added a CDN, most of the time it won't.


Adrien Rey-Jarthon
Created on October 20, 2023 · Last update on November 05, 2023