How to Measure Your CDN’s Cache Hit Ratio and Increase Cache Hits
Even with a CDN implemented, performance degradation and increased latency is always an unfortunate possibility for any web application.
Consider for a moment what’s involved in a single web request from client to the origin: The request is fragmented and encapsulated into datum packets and sent out across the Internet’s backbone network of cables, traversing thousands of switches, routers, and data centers along parallel ISP routes.
You can’t control sharks
With this in mind, one has to accept that the intrinsic nature of such complex systems are inclined to obey Murphy’s Law that states: “If anything can go wrong, it will.” Notable examples of things going wrong include sharks eating fiber optic submarine cables, a Georgian woman scavenging for copper, and cyber-terrorist-scuba-hackers.
You can control cache
Mother nature and human curiosity aside, there are certain variables in your control. One of these is your CDN’s cache. When configured correctly, it can provide your web app with 99.99% resource utilization, maximum speed, and minimum latency.
Take Control: Cache Control
The configuration rules which govern how, when, and why your web assets are stored in a web servers’ cache are collectively referred to as a Cache-Policy.
A well configured Cache-Policy minimizes Cache Misses, maximizes Cache Hits, and maintains a basal level of “cache warmth.” Deciphering the multiple configuration files that govern these policies can be a daunting task even for a seasoned sys admin. However, there are specific things you can do that direct most of the issues you’ll face when trying to optimize your cache hit ratio.
We’ll discuss these things below, but first let’s get a better understanding or how to track your cache hits and misses. Monitoring your cache hit ratio and analyzing metrics play a pivotal role in the process of optimization.
Introducing cache hit ratio
Cache hit ratio measures the percentage of requests your CDN is able to serve from its own internal cache (Cache HIT: Client to Edge) verse requests for assets in which the CDN has to pass along a request to your Origin (Cache MISS: Client to Edge to Origin).
High cache hit ratios result in faster web apps while low cache hit ratios result in slower web apps, increased origin stress, sharp increases in latency, and dropped connections. In fact, requests that miss the cache (via CDN edge nodes) often result in longer response times than requests sent directly to the origin.
Simply put, your cache hit ratio is the single most important metric in representing proper utilization and configuration of your CDN.
Keeping Score of Your Cache Hit Ratio
Your cache hit ratio relationship can be defined by a simple formula:
(Cache Hits / Total Hits) x 100 = Cache Hit Ratio (%)
- Cache Hits = recorded Hits during time t
- Total Hits = all requests recorded during time t
- t = time frame of observation
In the actual formula, time t becomes irrelevant as it’s cancelled out. Also keep in mind that the ratio must be less than or equal to 100 as the total amount of requests must be greater than or equal to Cache Hits.
For any web app, a cache hit ratio of 99% is possible. This depends, however, on the functionalities and design of the web app on the origin server. Web apps with a lot of user-generated content or more frequent updates may have a lower cache hit ratio.
With that said, if your cache hit ratio is below 80% on static files, your CDN is either poorly configured or not performing properly.
Classifying Your Cache Hit Ratio
While cache hit ratios measure the performance of the CDN cache in terms of percentage value, there are other ways to label cache performance. This is often done with the following cache terms.
- Cold Cache: A cold cache is either empty or too stale to be used. Cache hit ratios typically hover below 15% or display sharp negative slope tendencies towards 0%.
- Warm Cache: The most ambiguous of the three cache states, warmth is a relative state: hot cache decreasing in performance (turning cold) or a cold cache increasing in performance (turning hot while priming assets from the origin).
- Hot Cache: What every cache strives to be: efficient, fast and utilized. Pretty straightforward.
Optimizing Your Cache Hit Ratio
Optimization #1: Modify cache control headers
The origin server sets a number of HTTP headers on each object it serves, some of which tell browsers and other web clients how long an object is considered fresh. Properly configured cache control headers on the origin inform the CDN of the age and freshness of each object.
If the origin is unable to set cache control headers on all objects, the CDN can set them. It can also override existing ones set by the origin. The CDN’s ability to do this can give you the leverage you need to serve content faster from the edge.
Reading HTTP headers
A number of HTTP headers control caching. These headers can set the maximum age of an object, an expiration time, or even specify that an object is not to be cached at all.
HTTP response/requests headers can be viewed with a number of different open source tools and libraries. There are browser-based extensions as well as cURL, the definitive library for command line interfaces across OSX, Unix, Linux and Windows.
Common cache control headers
Last-Modified— Reports the last time the object at that URL was modified on the origin
ETag— A unique tag for the object used to find it in a cache
Cache-Control— Various rules for caching the object, such as the maximum time between origin requests
Expires— A fixed expiration time for the object in a cache
Important: Setting the cache lifetime to 365 days (max-age: 31556900) is not always the best option.
Takeaway: Set a time that best fits your content. For instance, if an asset changes approximately every 2 weeks, a cache time of 7 days may be appropriate. However, if the asset is accessed frequently, you may want to use a lifetime of one day or implement a version control query string on your backend. The latter would require you to manage something like a Cache Query String setting on your CDN. (We elaborate on this below.)
Optimization #2: Strip cookies
If a static object (e.g. an image resource) is setting cookies on the client side it’s not acting like a static object. Since the CDN can’t tell what’s going on behind the curtain at the origin server, it needs to assume that objects with cookies are dynamic. Therefore they will be a cache miss every time.
Look for the “Set-Cookie” header in the HTTP Response header to check if your origin is setting cookies. You can do this with one of the open source tools mentioned above.
Notice how the Set-Cookie value changes in the following response headers for the same object. This can force the CDN into revalidating the asset on every request resulting in Cache MISS.
HTTP/1.1 200 OK
Cache-Control: public, max-age=315360000
HTTP/1.1 200 OK
Cache-Control: public, max-age=315360000
If it isn’t possible to change how cookies are set on the origin server, some CDNs can ignore cookie data from the origin server’s response. This improves the CDN’s ability to cache an object.
Takeaway: There are scenarios when cookies should be used: for authentication, session id’s, etc. By nature though, cookies are un-cacheable, which means files containing them are also un-cacheable. This is why it’s important to have cookies ignored in requests for assets you want delivered by your CDN.
Optimization #3: Have CDN ignore query strings
Query strings are used to interact with web applications and APIs, aggregate user metrics, and provide versioning information for objects. When query strings are included in static object URLs they can be mistaken as unique objects and will be requested from the origin server on each request. This results in an unnecessary decrease in cache hit ratio.
If the origin server is unable to remove query strings from static object URLs, most CDNs should have the capability to ignore the query string, getting a cache hit for all objects with query strings.
Note: Sometimes query strings are warranted and represent unique content. This is why content delivery networks like StackPath honor the query string created at the origin as default unless otherwise stated.
You can check if two static objects change with query strings using the cURL and md5sum tools from a Unix or Linux command prompt. If the MD5 checksums are the same, so are the static objects.
$ curl -s www.example.com/images/company-logo.png?ver1212 | md5sum 888310813fffd5aa46f1e51206aea2b5 -
$ curl -s www.example.com/images/company-logo.png?ver9191 | md5sum 888310813fffd5aa46f1e51206aea2b5 -
In this case, the md5sum hash values are identical. Therefore it’s a good indicator that query strings should be ignored. If the hash values were not the same, query strings would represent dynamic content that shouldn’t be cached.
Takeaway: When query strings are used to change content on static URLs for each new user, this means they’re specific to the user and most likely enhance the user experience. Therefore they shouldn’t be cached by the CDN.
Audit Your Ratio for Long-Term Success
Even if the performance of your web app is above average, it’s good practice to continually audit the hits and misses on your cache. As seen above, shaving milliseconds or even seconds off response times can be as easy as ticking or unticking a box in your CDN’s control panel.
Audit your hits and misses weekly—if not daily—and always after editing code that affects entire apps or individual microservices that are connected to your CDN sites/zones.