What are the practical differences between when CloudFront expires objects at an origin via the CloudFront TTL setting versus when one calls invalidate?
The general idea is that you use TTLs to set the policy that CloudFront uses to determine the maximum amount of time each individual object can potentially be served from the CloudFront cache with no further interaction with the origin.
Default TTL: the maximum time an object can persist in a CloudFront cache without being considered stale, when no relevant Cache-Control directive is supplied by the origin. No Cache-Control header is added to the response by CloudFront.
Minimum TTL: If the origin supplies a Cache-Control: s-maxage value (or, if not present, then a Cache-Control: max-age value) smaller than this, CloudFront ignores it and assumes it can retain the object in the cache for not longer than this. For example, if Minimum TTL is set to 900, but the response contains Cache-Control: max-age=300, CloudFront ignores the 300 and may cache the object for up to 900 seconds. The Cache-Control header is not modified, and is returned to the viewer as received.
Maximum TTL: If the origin supplies a Cache-Control directive indicating that the object can be cached longer than this, CloudFront ignores the directive and assumes that the object must not continue to be served from cache for longer than Maximum TTL.
See Specifying How Long Objects Stay in a CloudFront Edge Cache (Expiration) in the Amazon CloudFront Developer Guide.
So, these three values control what CloudFront uses to determine whether a cached response is still "fresh enough" to be returned to subsequent viewers. It does not mean CloudFront purges the cached object after the TTL expires. Instead, CloudFront may retain the object, but will not serve it beyond the expiration without first sending request to the origin to see if the object has changed.
CloudFront does not proactively check the origin for new versions of objects that have expired -- it only checks if they are requested again, while still in the cache, and then determined to have been expired. When it does this, it usually sends a conditional request, using directives like If-Modfied-Since. This gives the origin the option of responding 304 Not Modified, which tells CloudFront that the cached object is still usable.
A misunderstanding that sometimes surfaces is that the TTL directs CloudFront how long to cache the objects. That is not what it does. It tells CloudFront how long it is allowed to cache the response with no revalidation against the origin. Cache storage inside CloudFront has no associated charge, and caches by definition are ephemeral, so, objects that are rarely requested may be purged from the cache before their TTL expires.
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.
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html
On the next request, CloudFront will request the object from the origin again.
Another misunderstanding is that CloudFront's cache is monolithic. It isn't. Each of the global edges has its own independent cache, caching objects in edges through which they are being requested. Each global edge also has an upstream regional cache (in the nearest EC2 region; there may be more than one per region, but this isn't documented) where the object will also be stored, allowing other nearby global edges to find the object in the nearest regional cache, but CloudFront does not search any further, internally, for cached objects. For performance, it just goes to the origin on a cache miss.
See How CloudFront Works with Regional Edge Caches.
Invalidation is entirely different, and is intended to be used sparingly -- only the first 1000 invalidation paths submitted each month by an AWS account are free. (A path can match many files, and the path /* matches all files in the distribution).
An invalidation request has a timestamp of when the invalidation was created, and sends a message to all regions, directing them to do something along these lines (the exact algorithm isn't documented, but this accurately descibes the net effect):
Delete any files matching ${path} from your cache, if they were cached prior to ${timestamp} and
Meanwhile, since that could take some time, if you get any requests for files matching ${path} that were cached prior to ${timestamp}, don't use the cached files because they are no longer usable.
The invalidation request is considered complete as soon as the entire network has received the message. Invalidations are essentially an idempotent action, in the sense that it is not an error to invalidate files that don't actually exist, because an invalidation is telling the edges to invalidate such files if they exist.
From this, it should be apparent that the correct course of action is not to choose one or the other, but to use both as appropriate. Set your TTLs (or select "use origin cache headers" and configure your origin server always to return them with appropriate values) and then use invalidations only as necessary to purge your cache of selected or all content, as might be necessary if you've made an error, or made significant changes to the site.
The best practice, however, is not to count on invalidations but instead to use cache-busting techniques when an object changes. Cache busting means changing the actual object being requested. In the simplest implementstion, for example, this might mean you change /pics/cat1.png to /pics/cat2.png in your HTML rather than saving a new image as /pics/cat1.png when you want a new image. The problem with replacing one file with another at the same URL is that the browser also has a cache, and may continue displaying the old image.
See also Invalidating Objects.
Note also that the main TTLs are not used for error responses. By default, responses like 404 Not Found are cached for 5 minutes. This is the Error Caching Minimum TTL, designed to relieve your origin server from receiving requests that are likely to continue to fail, but only for a few minutes.
If we are looking at practical differences:
CloudFront TTL: You can control how long your objects stay in a CloudFront cache before CloudFront forwards another request to your origin.
Invalidate: Invalidate the object from edge caches. The next time a viewer requests the object, CloudFront returns to the origin to fetch the latest version of the object.
So the main difference is speed. If you deploy a new version of your application you might want to invalidate immediately.
Related
We have a static site hosted in S3 and delivered with CloudFront. The site works but rolling out updates takes quite long -- hours or longer. Specifically, changing the Origin Path is not reflected on edge locations nearly as quickly as desired.
Here is what we are trying to achieve...
Our S3 bucket is configured to host a website. It stores multiple versions of the same site. There is a sub-directory per git tag. For example:
/git-v1
/git-v2
/git-v3
..
The goal is to tell CF to start serving a new version of the site per Origin Path setting. We don't want to invalidate old objects, just keep advancing the version by creating a new directory and pointing CF at it. The status under CloudFront Distributions shows "Deployed" for a long time, yet the edge locations continue to ignore the new Origin Path.
Any idea for how to make CF start serving the new sub-directory quicker would be greatly appreciated.
The Origin Path setting is applied to the request after the cache is checked... not before. When the object requested in the URI is not in the cache, the object is requested from the Origin server. At that point, Origin Path is prepended to the incoming request path, then sent to the origin. Caching is based on the incoming request path.¹
The setting itself takes effect quickly, often in seconds, but doesn't purge the cache.
If this is just for versioning the root page, you can leave the origin path blank, change the Default Root Object to the new root object, and then just invalidate /. Or, you can keep doing what you are doing, and invalidate /* after making the change. Free invalidations are limited to 1000 per month, but invalidating /* (or any wildcard) only counts as 1 invalidation, no matter how many objects the wildcard matches.
¹ incoming request path also refers to the path as it stands after a Lambda#Edge Viewer Request trigger modifies it, if applicable.
If I have a custom object caching TTL setting for Cloudfront (connecting to an S3 bucket) where:
Min TTL: 0
Max TTL: 1 year
Default TTL: 1 week
My question is this:
If I update an object in S3, will Cloudfront immediately serve up the new object (assuming it had been previously stored in cache), or will it continue to serve up the cached item for up to 1 week as per the default TTL?
I assume with a 0 min ttl, that it would recognize it had been updated, but I can't find any documentation that makes this clear.
Second question:
Since this is a custom TTL, and the min is 0, does that mean that the object actually never gets cached? (Are we just ignoring the default and max in this case?)
Minimum TTL is different than you suppose.
If an object fetched from the origin has a Cache-Control: max-age=n header where n < minimum-ttl, then CloudFront will ignore the max-age=n and instead cache the object for up to minimum-ttl. A minimum-ttl set to 0 is essentially eqivalent to making minimum-ttl never applicable (until time travel is invented), since no object could have a declared max-age less than 0.
Maximum TTL is the same, on the other side, if n > maximum-ttl, then CloudFront will cache the object for not longer than maximum-ttl.
If no Cache-Control: max-age=n is not present, CloudFront will cache the object for not longer than default-ttl.
In any event, CloudFront will not check the origin again for a new version of an already-cached object until its TTL expires. It gets no notification of changed objects from S3. You can tell how long an object had been in a specific edge cache by inspecting the Age: response header.
If you need to evict an object early, use a cache invalidation. An invalidation matches any object that matches the specified pattern (e.g. /images/* evicts any object matching that path) and an invalidation simply tells all the CloudFront edge caches that "if" they have any matching objects cached before the time of the eviction, those must be treated as invalid and no longer used to serve requests. An invalidation succeeds regardless of whether any cached objects were found that matched the pattern. It doesn't tell you what it evicted because -- presumably -- it doesn't literally purge them immediately, it just sets markers that prevents old matching cache entries from being used (forcing a re-fetch on the next request) and actually finds and purges them later, in the background. You get 1,000 invalidation requests for free each month, where 1 invalidation request can include wildcards and evict millions of objects, but that still only counts as 1 invalidation.
From Amazon cloud front
Amazon CloudFront is a web service that speeds up distribution of your
static and dynamic web content, such as .html, .css, .php, and image
files, to your users. CloudFront delivers your content through a
worldwide network of data centers called edge locations.
Per mine undserstanding, CloudFront must be caching the content with URL as key. URL can serve both static and dynamic content. Say i have 100 weburl's , out of which 30 serves the static content and 70 serves dynamic content(user specific data). I have one question each on static and dynamic content
Dynamic content :-
Say user_A access his data through url_A from US. That data has been cached . He updates the first name. Now same user will access the data from same location in US or from
another location in UK. We he see data prior to updation. If yes how will edge location come to know data needs to fetched from server not from cache ?
Does edge location continue to display the data from cache for configurable amount of time and if time is passed then fetch it from server ?
Does cloudfront allows to configure specific URL's that needs to fetched from server instead of cache always ?
Static content :-
There are chances that even static data may change will with each release. How cloud front will know that cached static content is stale and needs to be fetched from server ?
Amazon CloudFront uses an expiration period (or Time To Live - TTL) that you specify.
For static content, you can set the default TTL for the distribution or you can specify the TTL as part of the headers. When the TTL has expired, the CloudFront edge location will check to see whether the Last Modified timestamp on the object has changed. If it has changed, it will fetch the updated copy. If it is not changed, it will continue serving the existing copy for the new time period.
If static content has changed, your application must send an Invalidation Request to tell CloudFront to reload the object even when the TTL has not expired.
For dynamic content, your application will normally specify zero as the TTL. Thus, that URL will always be fetched from the origin, allowing the server to modify the content for the user.
A half-and-half method is to use parameters (eg xx.cloudfront.net/info.html?user=foo). When configuring the CloudFront distribution, you can specify whether a different parameter (eg user=fred) should be treated as a separate object or whether it should be ignored.
Also, please note that each CloudFront edge location has its own cache. So, if somebody accessed a page from the USA, that would not cause it to be cached in the UK.
See the documentation: Specifying How Long Objects Stay in a CloudFront Edge Cache (Expiration)
I am experimenting with AWS S3 and CloudFront for a web application that I am developing.
In the app I'm letting users upload files to the S3 bucket (using the AWS SDK) and make it available via CloudFront CDN, but the issue is even when the files are uploaded and ready in the S3 bucket it takes about a minute or 2 to be available in the CloudFront CDN url, is this normal?
CloudFront attempts to fetch uncached content from the origin server in real time. There is no "replication delay" or similar issue because CloudFront is a pull-through CDN. Each CloudFront edge location knows only about your site's existence and configuration; it doesn't know about your content until it receives requests for it. When that happens, the CloudFront edge fetches the requested content from the origin server, and caches it as appropriate, for serving subsequent requests.
The issue that's occurring here is related to a concept sometimes called "negative caching" -- caching the fact that a request won't work -- which is typically done to avoid hammering the origin of whatever's being cached with requests that are likely to fail anyway.
By default, when your origin returns an HTTP 4xx or 5xx status code, CloudFront caches these error responses for five minutes and then submits the next request for the object to your origin to see whether the problem that caused the error has been resolved and the requested object is now available.
— http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/custom-error-pages.html
If the browser, or anything else, tries to download the file from that particular CloudFront edge before the upload into S3 is complete, S3 will return an error, and CloudFront -- at that edge location -- will cache that error and remember, for the next 5 minutes, not to bother trying again.
Not to worry, though -- this timer is configurable, so if the browser is doing this under the hood and outside your control, you should still be able to fix it.
You can specify the error-caching duration—the Error Caching Minimum TTL—for each 4xx and 5xx status code that CloudFront caches. For a procedure, see Configuring Error Response Behavior.
— http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/custom-error-pages.html
To configure this in the console:
When viewing the distribution configuration, click the Error Pages tab.
For each error where you want to customize the timing, begin by clicking Create Custom Error Response.
Choose the error code you want to modify from the drop-down list, such as 403 (Forbidden) or 404 (Not Found) -- your bucket configuration determines which code S3 returns for missing objects, so if you aren't sure, change 403 then repeat the process and change 404.
Set Error Caching Minimum TTL (seconds) to 0
Leave Customize Error Response set to No (If set to Yes, this option enables custom response content on errors, which is not what you want. Activating this option is outside the scope of this question.)
Click Create. This takes you back to the previous view, where you'll see Error Caching Minimum TTL for the code you just defined.
Repeat these steps for each HTTP response code you want to change from the default behavior (which is the 300 second hold time, discussed above).
When you've made all the changes you want, return to the main CloudFront console screen where the distributions are listed. Wait for the distribution state to change from In Progress to Deployed (formerly, this took quite some time but now requires typically about 5 minutes for the changes to be pushed out to all the edges) and test.
Are these new files being written to S3 for the first time, or are they updates to existing files? S3 provides read-after-write consistency for new objects, and given CloudFront's pull model you should not be having this issue with new files written to S3. If you are, then I would open a ticket with AWS.
If these are updates to existing files, then you have both S3 eventual consistency and CloudFront cache expiration to deal with. Both of which could cause this sort of behavior.
As observed in your comment, it seems that google chrome is messing up with your upload/preview strategy:
Chrome is requesting the URL that currently doesn't have the
content.
the request is cached by cloudfront with invalid response
you upload the file to S3
when preview the uploaded file the cloudfront answers with the cached response (step 2).
after the cloudfront cache expires, cloudfront hits origin and the problem can no longer be reproducible.
I would like to know if there is a cost incurred for "refetching" an expired CloudFront object from an S3 bucket if the resource object has not changed. ie. is the object is retransferred in its entirety to each edge location, or are things like MD5-Content headers or modified times checked first before retransferring?
I'm trying to calculate the costs incurred and can't find any information on this via google or through amazons documentation.
I would like to set the Cache-Control headers to be as short a time as possible (say a few hours) so that objects can be removed/replaced reasonably quickly in places where filename versioning is not possible, without using Invalidation Requests.
If the objects are indeed retransferred in full, then obviously with hundreds of objects this solution would be too expensive to be acceptable.
On the other hand, there may be a better solution without needing to set a low value in the Cache-Control header. If so please share.
Thanks!
Once an object is "expired", it is removed from the cloudfront edge location. There's therefore no way to do an MD5 or modify time check as there is no file to compare it against.
If the file has not expired, it will not check against the origin server.
ie -
1. File is on the edge location - origin server not checked
2. File expires - therefore not on the edge location - origin server fetches it.
A short expiration time will lead to those files being removed from the origin, therefore requiring a complete refetch.