AWS CloudFront Best Practices: Optimizing Performance and Cost
Introduction to CloudFront
Amazon CloudFront is a global content delivery network (CDN) that makes it easy to deliver websites, videos, apps, and APIs securely and at high speeds with low latency. You can use the AWS CloudFront service to reduce latency by delivering data through 400+ globally dispersed Points of Presence (PoPs) and improve security with traffic encryption, access controls, and resiliency against DDoS attacks. In addition to performance and security, CloudFront services can be used to cost optimize your AWS infrastructure in various ways. In this post, we’ll cover numerous AWS CloudFront features and best practices that can help optimize costs for some commonly deployed architectures.
Use CloudFront for everything – including dynamic content
Suppose you serve dynamic content via web applications or APIs hosted directly from an Elastic Load Balancer (ELB) Amazon Elastic Compute Cloud (Amazon EC2) instances, or Amazon Elastic Container Service (Amazon ECS)/Amazon Elastic Kubernetes Service (Amazon EKS) container cluster to end users on the Internet. Instead of serving the requested content directly from these resources, you can route this traffic via AWS CloudFront, configured to pass-through the content without caching it at the edge locations. This approach lets you utilize CloudFront’s Free Tier, which offers 1 TB of data transfer out to the internet, and 10 million HTTP or HTTPS requests free each month, thereby reducing your Data Transfer Out (DTO) costs.
If you are using a third-party CDN while hosting your applications on AWS, you should be aware that this can be an anti-pattern from a cost perspective of data transfer. Let’s understand why – assume that you’re running a commonly-deployed web application behind Application Load Balancers (ALB) on AWS and using a different CDN instead of CloudFront. Now assume that your application is serving 10 TB of data to your users per month. If you use AWS CloudFront services as your CDN, then you’ll pay a data-transfer cost for only 9 TB because CloudFront Free Tier will cover the first 1 TB every month. Additionally, there is no data transfer cost for the data that is transferred between your origin servers on AWS, such as ALB, AWS Elastic Beanstalk, Amazon Simple Storage Service (Amazon S3), to the edge locations. However, if you use a different CDN, you’ll pay data transfer costs for 10 TB to them as per their pricing plans, as well as incur an additional data transfer cost to AWS for your data that is transferred out from your origin servers on AWS to the edge locations of the other CDN.
Restrict serving content to unwanted regions using CloudFront geographic restriction
Unwanted and malicious traffic can result in additional load on your resources, consume bandwidth, and increase your AWS costs. Restricting unwanted traffic at the edge before it hits your other resources can help you save on costs. For example, suppose you don’t want traffic from specific countries to hit your applications. In that case, you can use the CloudFront geographic restrictions feature to restrict access to all of the files associated with a CloudFront distribution at the country level. This can reduce the amount of traffic that your origin servers must process. Therefore, you can scale down your origin resources appropriately, resulting in cost savings.
Use CloudFront price classes as a metric for edge location strategy
AWS CloudFront has edge locations all over the world. The cost for each edge location varies, and thus the price varies depending on which edge location serves the requests. Price classes let you reduce your delivery prices by excluding CloudFront’s more expensive edge locations from your CloudFront distribution. Therefore, configuring the AWS CloudFront pricing class basis of application user geographies helps reduce costs without causing any noticeable latency impact.
Implement controls to reduce the cost of CloudFront logging
You may want to monitor your content distribution metrics, which you can get using CloudFront logs. However, note that real-time logs are charged based on the number of generated log lines, which in turn is based on the number of HTTP requests served by your AWS CloudFront distribution. Therefore, as a best practice, we recommend putting some preventive controls in place to limit the amount of traffic served by your CloudFront distribution using security services such as AWS Web Application Firewall (AWS WAF). You can also limit the amount of logs generated in three ways:
- Specify what percentage of requests you want to log
- Choose to log only specific log fields
- Enable real-time logs only for specific CloudFront caching behaviors
You can configure all of this on the CloudFront logs settings as shown in the following image.
Optimize cache hit ratio for non-AWS Origins
CloudFront services are often used as a content distribution layer for applications hosted outside of AWS. In these cases, optimizing the cache hit ratio can help save origin request submission costs. Cache hit ratio is the percentage of total requests that are served from the content cached at the edge locations. Take advantage of CloudFront’s customizable cache policies to improve the cache hit ratio by controlling the cache key. The cache key is the unique identifier for every object in the cache, and it determines whether a viewer request results in a cache hit. A cache hit occurs when a viewer request generates the same cache key as a prior request, and the object for that cache key is in the edge location’s cache and valid. One way to improve your cache hit ratio is to include only the minimum necessary values in the cache key. Optimize your cache hit ratio by understanding the cache key. In addition, CloudFront provides some predefined cache policies, known as managed policies, for common use cases or supports creating a custom cache policy specific to application requirements.
Effectively utilize AWS CloudFront compressed data caching capabilities
AWS CloudFront natively supports requesting and caching objects compressed in the GZIP or Brotli compression formats. CloudFront serves the compressed objects when the viewer’s web browsers or other clients support them and indicate their support for compressed objects with the Accept-Encoding HTTP header. Object compression helps reduce your data transfer costs because you’re transferring less data out from your origin servers to the internet. If certain file types aren’t natively supported for compression at CloudFront, then you can compress these files at your origin and return them as a compressed object to CloudFront. AWS CloudFront detects that the object is compressed based on the presence of a Content-Encoding header and won’t compress the object again.
Optimize CloudFront caching strategy to reduce cache invalidations
If you must remove a file from AWS CloudFront edge caches before it expires, then you can invalidate the file from edge caches. You’re charged for invalidation requests beyond the first 1,000 paths requested for invalidation each month. Therefore, it’s important to know some general best practices to save costs on invalidation.
We recommend that you control caching using the Cache-Control HTTP header that is sent by your origin, where you can define how long an object is cached by setting a time to live (TTL). The AWS CloudFront honors Cache-Control headers. This means that if an object has a Cache-Control header in the response, then CloudFront caches the object at the edge location for the duration of time specified in the Cache-Control max-age directive. If there is no Cache-Control header, then CloudFront caches the object for the duration of the Default TTL specified in the applicable cache behavior. In addition, you can define boundaries on the least and the most amount of time any object is cached by CloudFront by using the Minimum TTL and Maximum TTL fields of the cache behavior to protect against excessively short or long TTLs from being set unintentionally.
If you need to remove a file from CloudFront edge caches before it expires, you can use file versioning to serve a different version of the file with a different name. This allows you to control which file a request returns, even if the user has a version cached locally or behind a corporate caching proxy. If you invalidate the file, the user may continue to see the old version until it expires from those caches. Versioning is a less expensive option, as you only have to pay for CloudFront to transfer new versions of your files to edge locations in the case of non-AWS origins, without having to pay for invalidating files.
Optimize Lambda@Edge execution costs by rightsizing AWS Lambda runtime
The cost of running Lambda@Edge for your workload is determined by three factors: the number of executions, the duration of execution of the AWS Lambda function, and the memory usage (combined as Gb/s). Your choice of Lambda runtime has a direct impact on the cost. Generally, compiled languages run code more quickly than interpreted languages, but they can take longer to initialize. For small functions with simple functionality, often an interpreted language is better suited for the fastest total execution time, and thus the lowest cost for AWS Lambda functions. Functions using compiled languages are often faster in workloads with heavier computational complexity or where you’re using Provisioned Concurrency, so the initialization overhead occurs before the invocation.
This blog explains some best practices that can help you optimize your costs for some commonly deployed architectures on AWS by leveraging Amazon CloudFront services. Use these features in conjunction with other features that can help you improve the performance of web applications using CloudFront.
With CloudKeeper, you can optimize your entire AWS infrastructure, including a wide range of services like AWS CloudFront, EC2, RDS, Elasticsearch and more, and achieve contractually guaranteed savings of up to 25% on your entire AWS bills. Sounds interesting? Talk to our experts to learn more.