亚马逊AWS官方博客

Amazon CloudFront 部署小指南(二)- 进阶部署

内容简介

在这篇博客文章中,您将进一步了解 Amazon CloudFront 的功能,这些功能可以帮助您根据需求定义内容交付方式,提高服务性能及可用性。

以下我们将从配置和经典需求中,带您了解如何更好的使用 CloudFront 进行加速设置。

一. 构建测试动态源站

二. 源站设置

三. 路径匹配及缓存策略

四. 回源请求及响应头策略

五. 错误响应设置

六. 缓存失效

通过本指南,您将学会如何利用 CloudFront 进行更多的配置构建,以符合实际业务的需求。

在小指南一中的 S3 静态源站基础上,我们将构建了一个动静兼具的最小源站架构。

架构图:

构建测试动态源站及展示页面

在小指南一中,我们已经基于 S3 构建了一个最小架构的静态源站,为了更好的配合以下设置,接下来我们需要构建一个响应动态内容的源站,为了方便演示,此处以一个 echo-server 的 Docker 镜像,创建一个 httpecho 的容器让它能够把我们通过 http 访问服务器的请求头都提取出来作为 http 响应给我们的浏览器。

首先启用一个 t2.micro 的 EC2,使用 Amazon Linux2 AMI 启动。

在此 EC2 上安装 Docker,参考 https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/docker-basics.html

具体 Linux 命令如下:

  1. 安装 docker
sudo yum update -y
sudo amazon-linux-extras install docker
  1. 赋予 ec2-user 用户 docker 启动的 linux 权限
sudo usermod -a -G docker ec2-user
  1. 退出当前 ssh session 以使权限生效
logout
  1. 使用 ec2-user 再次 login 检查 docker 信息
sudo service docker start
docker info | grep Ver

输出如下即为 docker 安装成功:

Server Version: 20.10.7
Cgroup Version: 1
Kernel Version: 4.14.47-64.38.amzn2.x86_64
  1. 运行 echo-server docker image,监听 TCP 1028 端口
docker run -d --name httpecho  -p 1028:8080 jmalloc/echo-server httpecho
  1. curl 检查本地服务
curl 127.0.0.1:1028

输出如下即表示服务正常。该输出表示 echo-server 服务器收到 curl 送来的 http 请求,内容非常简单:

Request served by 16e51706efbe

HTTP/1.1 GET /

Host: 127.0.0.1:1028
User-Agent: curl/7.79.1
Accept: /

接下来,为了更便于展示效果,我们将使用一个简单的 HTML 页面,将静态元素和动态元素进行结合,您可以先将以下 html 代码保存为 index.html 的并上传至 S3 当中:

<!DOCTYPE html>
<html lang="en">
<body>
<table border="1" width="600px" height="800px">
<thead>
<tr><td height="50px"><h1>CloudFront Lab</h1></td></tr>
</thead>
<tfoot>
<tr><td height="50px">AWS Edge Services - Demo</td></tr>
</tfoot>
<tbody>
<tr><td height="50px">Response sent by API</td></tr>
</tbody>
<tbody>
<tr><td height="300px"> <img src='../infra.png' style="width:100%; height:100%;"></img></td></tr>
</tbody>
<tbody>
<tr><td height="650px"> <iframe src='../api' style="width:100%; height:100%;"></iframe></td></tr>
</tbody>
</table>
</body>
</html>

路径匹配及缓存策略

配置缓存策略之前,我们需要先了解下 CloudFront 如何根据行为(Behavior)中的路径识别,来找到对应的策略,配置路径匹配(Path Pattern)时,我们需要遵循以下的规则:

  • 按序执行,规则序号越小,优先级越高
  • * 匹配 0 个或多个字符
  • 大小写敏感
  • 匹配 1 个字符
  • 不支持正则表达式

同时,为了让缓存结果符合预期,我们也需要了解缓存策略(Cache Policy)中的 TTL 设置以及缓存键值(Cache Key)设置的工作方式:

关于 TTL 设置,此处以下图的设置进行举例说明:

CloudFront 将根据源服务器响应的 cache-control 或 expire,结合缓存策略中的 TTL 设置决定缓存多长时间,此处举三个例子来说明最终的效果:

  • 源站响应了 Cache-Control: max-age=3600,由于 3600 落在了 TTL 最大值和最小值 1 – 86400 的区间,则 CloudFront 将缓存 3600 秒
  • 源站响应了 Cache-Control: max-age=99999,由于 99999 超出了 TTL 最大值 86400,则 CloudFront 将缓存 86400 秒
  • 源站未响应 cache-control或expire,由于默认 TTL(Default TTL)设置为 60 秒,则 CloudFront 将缓存 60 秒

关于缓存键值的设置,CloudFront 可识别以下三种请求元素,进而将指定元素作为缓存键值进行缓存,分别为:请求头 / 参数 / Cookie

除了用户携带的请求头可作为缓存键值以外,CloudFront 还内置了诸多供用户使用的请求头,用于识别用户的 设备类型 / 地理位置 等,具体可参考 – 添加 CloudFront 请求标头,您可根据具体业务需求,结合该头部信息进行缓存内容的区分。

另外,当服务中启用了压缩支持(compression support)时,CloudFront 还将根据不同的压缩格式分开进行缓存,并根据请求端发送的 accept-encoding 头部进行相应的内容返回:

关于缓存键值的设置,为了保证实际使用 CloudFront 时维持一个良好且健康的缓存命中率,我们需要遵循“非必要不添加缓存键值”的原则,以下为一个常用的缓存键值场景举例:

页面中的某个静态元素,需要根据用户所携带的 v 参数,来作为缓存版本号识别,进行缓存区分,针对这种需求,我们可以这么设置缓存键值:

结合上述的原理以及我们准备好的源站环境,以下两个例子将解释网站中常用的两种场景——

场景 1:  网站中以 webp 结尾的路径需要缓存,且需要根据参数v进行缓存版本区分,缓存时间强制设置为 86400

根据场景需求我们可以进行以下设置:

路径匹配:

缓存 TTL 以及缓存键值设置,我们可以在 Policies – Cache 中,或是 Edit Behavior 页面中自定义构建缓存方式:

缓存 TTL 及缓存键值设置,设置完毕后保存:

选中刚才创建的 Cache Policy 并保存:

场景 2:网站中的/api 路径,回源 EC2,且不缓存

在小指南一的基础上,我们的设置已经有了 S3 的源站,我们先创建 EC2 源,选中刚才创建的 EC2:


注:在此实验中,EC2 echoserver 监听的端口为 1028,您在创建 EC2 源时需注意指定端口,启用 HTTP/HTTPS,HTTPS 443 端口保持不变,为接下来的实验做准备。

我们可以设置以下的路径匹配,缓存策略则可以使用 CloudFront 托管的缓存策略 – Managed-CachingDisabled,具体设置如下:

同理,我们也将 index.html 按照 S3 为源站 / CachingDisable 的方式进行设置。

效果测试:

在测试实际效果中,我们可以利用到 CloudFront 原生的 X-Cache 响应头,来浏览器中观察缓存状态是否符合预期。

使用 HTTP 方法访问您的 index.html 页面(如 http://xxx.xxx.com/index.html),在重复刷新页面后,可以看到 infra.png 此请求的 X-Cache 状态为Hit。

而/api 路径由于缓存策略设置为不缓存,多次刷新后状态仍然为 Miss。

源组设置

尽管有许多不同的方法可以提高网站的可用性,例如如果承载网站的原始服务器在 AWS 云中,则使用弹性负载平衡和多可用区,但 CloudFront 可为您的网站带来了更高的可用性。

网站可用性最常受到网络故障/服务器中断或内容不可用的影响,但有许多因素可能会影响网站的可用性。例如,网站停机可能是由于意外的硬件故障造成的。您可以通过使所有组件完全冗余来减轻这种类型的风险。在 CloudFront 的源设置中,提供了源组(Origin Group)的功能,您可以为源服务器端点提供多个冗余,避免由于一个源站故障或内容不可用而引起业务中断。

注:如果您使用的源站为非 Amazon 资源,如其他云服务计算资源,建议您在设置源站时启用源护盾(Origin Shield)功能,充分利用骨干网络,以保持业务的最佳性能以及可用性。

如以上截图,您在实际配置时,如需设置源组,则需要先设置出至少 2 个及以上的源,方可进行源组的设置,且您可灵活的指定源之间的主备关系,且根据源所响应的状态码,对满足特定状态码的请求进行自动宕切(Failover)。

以下我们举个例子,当访问的对象在 S3 上不存在时,CF 自动 Failover 到备用源站 EC2 去取内容:

创建完 Origin Group 后,在 Behavior 中设置一个测试用的行为,并将上述创建的源组应用到该行为中:

浏览器测试效果:

*由于 EC2 只启用了 HTTP,请使用 HTTP 访问测试,而非 HTTPS。

我们可以看到当访问不存在的内容时,页面显示的不是主源上 S3 的报错信息,而是可以自动由备源 EC2 拿到内容,证明设置成功。

回源请求及响应头策略

在使用 CloudFront 为页面业务进行加速时,您同样可以决定回源时,CloudFront 应携带哪些必要信息回源,以及响应时在 CloudFront 设置相应的响应头策略,和缓存策略类似,您可以在 CloudFront 源请求策略(Origin Request Policy)中指定需要携带回源的请求头 / 参数 / Cookie,同时,您也可以灵活的制定响应头的策略,对指定的响应头进行增删改的操作,为了更好的理解,以下为一个应用案例——

因业务需求,我们需要在 CloudFront 上实现以下三个策略:

  • 源站部署并监听了多个 Hostname,CloudFront 需携带用户请求的 Host 头供源站进行区分;
  • 业务方需要 CloudFront 携带用户的国家信息回源,供业务方进行信息收集并统计;
  • 在响应头中自定义响应头 x-cdn: CloudFront。

根据上述需求,您可以进行以下的相关设置:

  • 设置源请求策略携带 Host 和 CloudFront 内置的地理位置信息头

  • 自定义设置响应头策略

创建完毕后在行为路径“/api”中进行应用并部署:

效果测试:

利用到实验环境中的 echo server 响应内容为用户请求头的特性,我们可以很好的观察到配置的效果。

在部署上述 请求头和响应头逻辑之前,我们可以看到该请求请求头携带回源的 Host 为 EC2 域名,响应头不携带 CORS 信息:

部署完逻辑后进行对比,我们可以看到用户请求的 host 信息已成功被携带回源,并且请求头中已携带了用户地理位置信息,响应头中也具备了我们自定义的响应头信息:

*在上面的测试结果我们可以看到一个有意思的现象,即 UA 为 Amazon CloudFront,这是因为在制定 Origin Policy 时,我们并未指定携带 UA 回源,在实际应用中,源服务往往需要根据请求头获取更多用户的请求特征,您可根据您的需要制定 CloudFront 应该携带哪些请求元素回源。

定制错误响应

在使用 CloudFront 进行内容分发时,我们可能会遇到 文件不存在 / 源服务器维护 / 源服务超时 等情况,导致客户端拿到错误响应或是源服务收到过多的错误请求,为了更好的缓解这种情况,CloudFront 可自定义错误响应码的缓存时间以及响应内容,以缓解源站持续收到触发错误响应码的请求,以及更友好的用户错误页面。

在这我们举例个场景,业务方需要针对源服务响应的 502 响应码进行 10 秒缓存,并且响应自定义的报错页面,我们可进行以下设置,来实现上述需求:

创建一个 custom error response

进行如下设置,指定 502 的 10 秒缓存时间,并且设置 sorry page 的路径,并进行 200 响应。

这边提供了一段简单的 html 文本页面:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to CloudFront!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Sorry, Your content is not available!</h1>
</body>
</html>

我们将该 html 上传至 S3 源站中作为错误页面进行展示:

上述操作完毕后,我们可以开始测试效果,由于部署 EC2 时,我们未开启 443 端口以及部署 HTTPS 证书,此时如果使用 HTTPS 访问 CloudFront,当 CloudFront 尝试用 HTTPS 回源 EC2 时,请求将会超时并产生 502 错误。

利用这个机制我们可以模拟源服务 502 的情况,使用 HTTPS 进行对 index.html 访问,未部署定制化错误响应前,我们可以看到以下效果:

部署定制化错误响应后:

缓存失效

在实际业务中,您可能会遇到某些场景需要进行资源变更同时需要进行缓存失效,在 CloudFront Distribution 配置界面,您可以找到缓存失效的入口并进行缓存失效的动作,在确保源资源变更后,您方可在 CloudFront 上进行缓存失效的动作。

接下来,我们使用构建好的环境来进行缓存刷新的测试,访问/index.html,直至静态内容呈现 Hit 状态,如下图所示:

下一步,在 CloudFront 失效界面,添加需要失效缓存的 URL path:


提交并确认失效完成后,再次访问/index.html 页面,即可看到失效动作完成,再次访问缓存状态为 Miss。

总结

在此篇小指南中,我们了解到了如何进一步使用 CloudFront 实现更多灵活的设置,包括 定制缓存策略 / 设置源服务主备逻辑 / 针对回源请求进行制定 / 修改业务所需的响应头以及如果定制错误响应,根据本篇的指引,您可根据业务需求灵活构建 CloudFront 的行为以及如果响应客户请求。

本篇作者

王骏兴

亚马逊云科技边缘产品架构师,负责亚马逊云科技 Edge 服务领域在中国的技术推广。在 CDN 内容分发以及 WAF 领域拥有多年实战经验,专注于边缘服务设计以及体验优化。

崔俊杰

亚马逊云科技高级产品解决方案架构师,负责亚马逊云科技云边缘安全相关的服务产品。为亚马逊云用户提供 DDoS 防御/网站前端安全防御/域名安全相关的产品咨询。对 Cloudfront,Shield,WAF,Route53,Global Accelerator 等云边缘安全相关产品有深入了解。在计算机安全、数据中心和网络领域有多年的工作经验。