AWS Cloudfront 0 Minimum TTL meaning & cost - amazon-web-services

I read that Cloudfront now supports setting 0 as minimum TTL, I am wondering how it works though and if it affects the cost of Cloudfront/ AWS S3?
How does Cloudfront know when a js or css file has changed? We upload new file during deployments to S3. I have no idea if the modification time is correct or not but I think it is.
Main question is if it's cheaper to set it to 0 or keep 5 minutes as we have now and do an invalidation of js/css in Cloudfront after deployments. Sometimes when we golive with only backend changes we won't need to invalidate. Most of the time we have css/js changes also though.

Minimum TTL rarely needs to be customized.
Minimum TTL does not define the minimum amount of time that CloudFront will cache an object. That's what it sounds like, but that's a common misconception.
To help clarify that point, let me first clarify TTL.
The TTL (time-to-live) is a value CloudFront calculates, internally, for each individual object, for the purpose of determining whether an object should be cached at all, and then whether an object found in the cache is still considered fresh. If an object has been in the cache for less time than its TTL, it is said to be fresh, otherwise it is said to be stale.
A fresh object can be served to a viewer without checking with the origin.
A stale object should not be served to a viewer without verifying with the origin, and should eventually be purged.
CloudFront may retain a stale object in its cache for some period of time. (It can verify with the origin whether the stale object is still good, with a conditional request. It can also continue to use the stale object in limited conditions, including an outage on your origin).
CloudFront may also purge a fresh object from its cache at any time. Why would it do that? Cache space is free, so it wouldn't make sense for everything that CloudFront caches to continue to be stored in the cache if it isn't getting requested. CloudFront can purge an "unpopular" object from cache at any time.
From this, it is hopefully clear that TTL is not "how long will CloudFront cache the object?" but rather "how long will CloudFront consider a cached object fresh?"
If an object has a calculated TTL of 0, CloudFront won't cache the object.
So... how would an object get a calculated 0 TTL? At least one of these headers in the response from the origin:
Cache-Control: private
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: s-maxage=0
Cache-Control: max-age=0 // ignored when s-maxage is present
These are the only cases where Minimum TTL typically has a role to play. (Also, the Expires HTTP header can trigger it, but don't use Expires -- use Cache-Control).
Cache-Control -- as returned by the origin server -- is primarily intended for the browser, but CloudFront observes it as well, when trying to calculate an appropriate TTL for each object.
Minimum TTL establishes a lower boundary on the value CloudFront will extrapolate from the origin's Cache-Control header, from the conditions above, and smaller values are rounded up. If your origin returns (e.g.) Cache-Control: private, no-cache, no-store, that's a TTL that should be 0... but CloudFront sets its internal TTL for that object to the greater of 0 or Minimum TTL.
If the response had (e.g.) Cache-Control: max-age=15 then both browers and CloudFront would calculate a TTL for that object of 15 seconds. If (e.g.) Minimum TTL is set to 300 then CloudFront ignores the 15 seconds specified by the origin and sets its internal TTL for the object to 300 seconds. The browser will still use 15 seconds, because CloudFront does not modify the Cache-Control response header.
tl;dr: Minimum TTL is the minimum internal TTL value that CloudFront will assign to an object, regardless of values in the origin response that should cause it to calculate a lower value. Changing this setting from the default value 0 is an advanced option. It does not set a minimum amount of time that CloudFront is required to cache objects.
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist

Related

Cloudfront caching responses with Cache-Control : no-cache, no-store set from origin on traffic spikes(load testing with k6)

Current cache policy is set to
Minimum TTL : 0
Maximum TTL : 31536000
Default TTL : 0
Origin Response
We have a specific url pattern for which we are setting the Cache-Control: no-cache, no-store response header from origin.
Expected behaviour:
The expected behaviour according to the docs Managing how long content stays in the cache is all the requests should reach origin server.
Test Condition
We have been using k6 for load testing and found that under 10 rps for 10s, we get about 65% cache hit from cloudfront and only 35% cache misses based on the X-Cache header.
We have tried many different combinations of TTL and other possible Cache-Control headers but nothing worked.
Expected Resolution
We want all the requests with that specific pattern to reach our origin servers.

What is Cloudfront Minimum TTL for?

I am trying to understand Minimum TTL, Maximum TTL and Default TTL with this document.
As my understanding, Maximum TTL is used when HTTP cache header appears in respons to limit maximum cache time and Default TTL is used when there is no HTTP cache header to use as default cache time.
However, for Maximum TTL, there is no specific mention.
In addition, It mentions the relation with forwarding head. Does it mean that if I set any HTTP header to forward to an origin and Minimum TTL is not 0, it doesn't cache anything?
Minimum TTL
Specify the minimum amount of time, in seconds, that you want objects to stay in CloudFront caches before CloudFront forwards another request to your origin to determine whether the object has been updated. The default value for Minimum TTL is 0 seconds.
Important
. If you configure CloudFront to forward all headers to your origin for a cache behavior, CloudFront never caches the associated objects. Instead, CloudFront forwards all requests for those objects to the origin. In that configuration, the value of Minimum TTL must be 0.
When deciding whether and for how long to cache an object, CloudFront uses the following logic:
Check for any Cache-Control response header with these values:
no-cache
no-store
private
If any of these is encountered, stop, and set the object's TTL¹ to the configured value of Minimum TTL. A non-zero value means CloudFront will cache objects that it would not otherwise cache.
Otherwise, find the origin's directive for how long the object may be cached. In order, find one of these response headers:
Cache-Control: s-maxage=x
Cache-Control: max-age=x
Expires
Stop on the first value encountered using this ordering, then continue to the next step.
If no value was found, use Default TTL. Stop.
Otherwise, using the value discovered in the previous step:
If smaller than Minimum TTL, then set the object's TTL to Minimum TTL; otherwise,
If larger than Maximum TTL, then set the object's TTL to Maximum TTL; otherwise,
Use the value found in the previous step as the object's TTL.
See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html.
It's important to note that the TTL determines how long CloudFront is allowed to cache the response. It does not dictate how long CloudFront is required to cache the response. CloudFront can evict objects from cache before TTL expires, if the object is rarely accessed.
Whitelisting some (but not all) headers for forwarding to the origin does not change any of the above logic.
What it does change is how objects are evaluated to determine whether a cached response is available.
For example, if you forward the Origin header to the origin, then each unique value for an Origin header creates a different cache entry. Two requests that are identical, except for their Origin header, are then considered different objects... so a cached response for Origin: https://one.example.com would not be used if a later request for the same resource included Origin: https://two.example.com. Both would be sent to the origin, and both would be cached independently, for use in serving future requests with same the matching request header.
CloudFront does this because if you need to forward headers to the origin, then this implies that the origin will potentially react differently to different values for the whitelisted headers... so they are cached separately.
Forwarding headers unnecessarily will thus reduce your cache hit rate unnecessarily.
There is no documented limit to the number of different copies of the same resource that CloudFront can cache, based on varying headers.
But forwarding all headers to the origin reduces to almost zero the chance of any future request being truly identical. This would potentially consume a lot of cache storage, storing objects that would never again be reused, so CloudFront treats this as a special case, and does not allow any caching under this condition. As a result, you are required to set Minimum TTL to 0 for consistency.
¹the object's TTL as used here refers to CloudFront's internal timer for each cached object that tracks how long it is allowed to continue to serve the cached object without checking back with the origin. The object's TTL inside CloudFront is known only to CloudFront, so this value does not impact browser caching.

Objects are getting expired from CloudFront [duplicate]

Cloudfront is configured to cache the images from our app. I found that the images were evicted from the cache really quickly. Since the images are generated dynamically on the fly, this is pretty intense for our server. In order to solve the issue I set up a testcase.
Origin headers
The image is served from our origin server with correct Last-Modified and Expires headers.
Cloudfront cache behaviour
Since the site is HTTPS only I set the Viewer Protocol Policy to HTTPS. Forward Headers is set to None and Object Caching to Use Origin Cache Headers.
The initial image request
I requested an image at 11:25:11. This returned the following status and headers:
Code: 200 (OK)
Cached: No
Expires: Thu, 29 Sep 2016 09:24:31 GMT
Last-Modified: Wed, 30 Sep 2015 09:24:31 GMT
X-Cache: Miss from cloudfront
A subsequent request
A reload a little while later (11:25:43) returned the image with:
Code: 304 (Not Modified)
Cached: Yes
Expires: Thu, 29 Sep 2016 09:24:31 GMT
X-Cache: Hit from cloudfront
A request a few hours later
Nearly three hours later (at 14:16:11) I went to the same page and the image loaded with:
Code: 200 (OK)
Cached: Yes
Expires: Thu, 29 Sep 2016 09:24:31 GMT
Last-Modified: Wed, 30 Sep 2015 09:24:31 GMT
X-Cache: Miss from cloud front
Since the image was still cached by the browser it loaded quickly. But I cannot understand how the Cloudfront could not return the cached image. Therefor the app had to generate the image again.
I read that Cloudfront evicts files from its cache after a few days of being inactive. This is not the case as demonstrated above. How could this be?
I read that Cloudfront evicts files from its cache after a few days of being inactive.
Do you have an official source for that?
Here's the official answer:
If an object in an edge location isn't frequently requested, CloudFront might evict the object—remove the object before its expiration date—to make room for objects that have been requested more recently.
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html
There is no guaranteed retention time for cached objects, and objects with low demand are more likely to be evicted... but that isn't the only factor you may not have considered. Eviction may not be the issue, or the only issue.
Objects cached by CloudFront are like Schrödinger's cat. It's a loose analogy, but I'm running with it: whether an object is "in the cloudfront cache" at any given instant is not a yes-or-no question.
CloudFront has somewhere around 53 edge locations (where your browser connects and the content is physically stored) in 37 cities. Some major cities have 2 or 3. Each request that hits cloudfront is routed (via DNS) to the most theoretically optimal location -- for simplicity, we'll call it the "closest" edge to where you are.
The internal workings of Cloudfront are not public information, but the general consensus based on observations and presumably authoritative sources is that these edge locations are all independent. They don't share caches.
If, for example, your are in Texas (US) and your request routed through and was cached in Dallas/Fort Worth, TX, and if the odds are equal that you any request from you could hit either of the Dallas edge locations, then until you get two misses of the same object, the odds are about 50/50 that your next request will be a miss. If I request that same object from my location, which I know from experience tends to route through South Bend, IN, then the odds of my first request being a miss are 100%, even though it's cached in Dallas.
So an object is not either in, or not in, the cache because there is no "the" (single, global) cache.
It is also possible that CloudFront's determination of the "closest" edge to your browser will change over time.
CloudFront's mechanism for determining the closest edge appears to be dynamic and adaptive. Changes in the topology of the Internet at large can change shift which edge location will tend to receive requests sent from a given IP address, so it is possible that over the course of a few hours, that the edge you are connecting to will change. Maintenance or outages or other issues impacting a particular edge could also cause requests from a given source IP address to be sent to a different edge than the typical one, and this could also give you the impression of objects being evicted, since the new edge's cache would be different from the old.
Looking at the response headers, it isn't possible to determine which edge location handled each request. However, this information is provided in the CloudFront access logs.
I have a fetch-and-resize image service that handles around 750,000 images per day. It's behind CloudFront, and my hit/miss ratio is about 50/50. That is certainly not all CloudFront's fault, since my pool of images exceeds 8 million, the viewers are all over the world, and my max-age directive is shorter than yours. It has been quite some time since I last analyzed the logs to determine which and how "misses" seemed unexpected (though when I did, there definitely were some, but their number was not unreasonable), but that is done easily enough, since the logs tell you whether each response was a hit or a miss, as well as identifying the edge location... so you could analyze that to see if there's really a pattern here.
My service stores all of its output content in S3, and when a new request comes in, it first sends a quick request to the S3 bucket to see if there is work that can be avoided. If a result is returned by S3, then that result is returned to CloudFront instead of doing all the fetching and resizing work, again. Mind you, I did not implement that capability because of the number of CloudFront misses... I designed that in from the beginning, before I ever even tested it behind CloudFront, because -- after all -- CloudFront is a cache, and the contents of a cache are pretty much volatile and ephemeral, by definition.
Update: I stated above that it does not appear possible to identify the edge location forwarding a particular request by examining the request headers from CloudFront... however, it appears that it is possible with some degree of accuracy by examining the source IP address of the incoming request.
For example, a test request sent to one of my origin servers through CloudFront arrives from 54.240.144.13 if I hit my site from home, or 205.251.252.153 when I hit the site from my office -- the locations are only a few miles apart, but on opposite sides of a state boundary and using two different ISPs. A reverse DNS lookup of these addresses shows these hostnames:
server-54-240-144-13.iad12.r.cloudfront.net.
server-205-251-252-153.ind6.r.cloudfront.net.
CloudFront edge locations are named after the nearest major airport, plus an arbitrarily chosen number. For iad12 ... "IAD" is the International Air Transport Association (IATA) code for Washington, DC Dulles airport, so this is likely to be one of the edge locations in Ashburn, VA (which has three, presumably with different numerical codes at the end, but I can't confirm that from just this data). For ind6, "IND" matches the airport at Indianapolis, Indiana, so this strongly suggests that this request comes through the South Bend, IN, edge location. The reliability of this test would depend on the consistency with which CloudFront maintains its reverse DNS entries. It is not documented how many independent caches might be at any given edge location; the assumption is that there's only one, but there might be more than one, having the effect of increasing the miss ratio for very small numbers of requests, but disappearing into the mix for large numbers of requests.

Cloudfront TTL not working

I'm having a problem and tried to follow answers here in forum, but with no success whatsoever.
In order to generate thumbnails, I have set up the following schema:
S3 Account for original images
Ubuntu Server using NGINX and Thumbor
Cloudfront
The user uploads original images to S3, which will be pulled through Ubuntu Server with Cloudfront in front of the request:
http://cloudfront.account/thumbor-server/http://s3.aws...
The big deal is, that we often loose objects in Cloudfront, I want them to stay 360 days in cache.
I get following response through Cloudfront URL:
Cache-Control:max-age=31536000
Connection:keep-alive
Content-Length:4362
Content-Type:image/jpeg
Date:Sun, 26 Oct 2014 09:18:31 GMT
ETag:"cc095261a9340535996fad26a9a882e9fdfc6b47"
Expires:Mon, 26 Oct 2015 09:18:31 GMT
Server:nginx/1.4.6 (Ubuntu)
Via:1.1 5e0a3a528dab62c5edfcdd8b8e4af060.cloudfront.net (CloudFront)
X-Amz-Cf-Id:B43x2w80SzQqvH-pDmLAmCZl2CY1AjBtHLjN4kG0_XmEIPk4AdiIOw==
X-Cache:Miss from cloudfront
After a new refresh, I get:
Age:50
Cache-Control:max-age=31536000
Connection:keep-alive
Date:Sun, 26 Oct 2014 09:19:21 GMT
ETag:"cc095261a9340535996fad26a9a882e9fdfc6b47"
Expires:Mon, 26 Oct 2015 09:18:31 GMT
Server:nginx/1.4.6 (Ubuntu)
Via:1.1 5e0a3a528dab62c5edfcdd8b8e4af060.cloudfront.net (CloudFront)
X-Amz-Cf-Id:slWyJ95Cw2F5LQr7hQFhgonG6oEsu4jdIo1KBkTjM5fitj-4kCtL3w==
X-Cache:Hit from cloudfront
My Nginx responses as following:
Cache-Control:max-age=31536000
Content-Length:4362
Content-Type:image/jpeg
Date:Sun, 26 Oct 2014 09:18:11 GMT
Etag:"cc095261a9340535996fad26a9a882e9fdfc6b47"
Expires:Mon, 26 Oct 2015 09:18:11 GMT
Server:nginx/1.4.6 (Ubuntu)
Why does Cloudfront not store my objects as indicated? Max-Age is set?
Many thanks in advance.
Your second request shows that the object was indeed cached. I assume you see that, but the question doesn't make it clear.
The Cache-Control: max-age only specifies the maximum age of your objects in the Cloudfront Cache at any particular edge location. There is no minimum time interval for which your objects are guaranteed to persist... after all, Cloudfront is a cache, which is volatile by definition.
If an object in an edge location isn't frequently requested, CloudFront might evict the object—remove the object before its expiration date—to make room for objects that are more popular.
— http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html
Additionally, there is no concept of Cloudfront as a whole having a copy of your object. Each edge location's cache appears to operate independently of the others, so it's not uncommon to see multiple requests for relatively popular objects coming from different Cloudfront edge locations.
If you are trying to mediate the load on your back-end server, it might make sense to place some kind of cache that you control, in front of it, like varnish, squid, another nginx or a custom solution, which is how I'm accomplishing this in my systems.
Alternately, you could store every result in S3 after processing, and then configure your existing server to check S3, first, before attempting the work of resizing the object again.
Then why is there a documented "minimum" TTL?
On the same page quoted above, you'll also find this:
For web distributions, if you add Cache-Control or Expires headers to your objects, you can also specify the minimum amount of time that CloudFront keeps an object in the cache before forwarding another request to the origin.
I can see why this, and the tip phrase cited on the comment, below...
The minimum amount of time (in seconds) that an object is in a CloudFront cache before CloudFront forwards another request to your origin to determine whether an updated version is available. 
...would seem to contradict my answer. There is no contradiction, however.
The minimum ttl, in simple terms, establishes a lower boundary for the internal interpretation of Cache-Control: max-age, overriding -- within Cloudfront -- any smaller value sent by the origin server. Server says cache it for 1 day, max, but configured minimum ttl is 2 days? Cloudfront forgets about what it saw in the max-age header and may not check the origin again on subsequent requests for the next 2 days, rather than checking again after 1 day.
The nature of a cache dictates the correct interpretation of all of the apparent ambiguity:
Your configuration limits how long Cloudfront MAY serve up cached copies of an object, and the point after which it SHOULD NOT continue to return the object from its cache. They do not mandate how long Cloudfront MUST maintain the cached copy, because Cloudfront MAY evict an object at any time.
If you set the Cache-Control: header correctly, Cloudfront will consider the larger of max-age or your Minimum TTL as the longest amount of time you want them to serve up the cached copy without consulting the origin server again.
As your site traffic increases, this should become less of an issue, since your objects will be more "popular," but fundamentally there is no way to mandate that Cloudfront maintain a copy of an object.

Akamai charge questions

I am wondering if anyone has an simple answer to this. If you hit an Akamai server for an image, but the response is returned with a 304 code instead of a 200, does Akamai charge for the call since no data is returned with a 304 and image is served from the browser cache?
If by charge you mean count against your monthly bandwidth allotment, then no. Assuming you're using their Origin Pull service, the only exception is if the file is in your cache but not stored on Akamai's edge servers. In that case, Akamai pulls the file from your server which would incur a small bandwidth hit as both incoming and outgoing traffic is counted on Akamai.
Well, it depends on how you are being billed. By bandwidth or by pageviews?
If by bandwidth, then yes, you would be charged and bits would be delivered on your behalf.
There is no discrepancy if your object is in cache. If the object is in cache, then Akamai won't need to go back to origin to fetch the data.
3xx responses still transfer a small number of bytes per request to tell you about the response. This typically consists of HTTP headers / cookies + 3xx response and the URL it wants to redirect you to.
Therefore you will be incurring a small amount of cost between your user and the edge node, and if the request is a cache miss or not cacheable, then also bandwidth cost between your origin server and Akamai.