摘要
本文将介绍如何使用 Amazon Lambda@edge 和 Amazon CloudFront 构建多区域就近访问的应用,从而提高用户体验。与传统的多区域部署方案不同的是,该方案通过 Lambda@edge 在 Origin Request 阶段修改请求的特性,动态地修改源站的域名,从而实现就近访问的目的。
方案场景介绍
某个 Web 应用会部署在美西和新加坡,静态资源利用 S3 部署。美西和新加坡的用户通过 S3 读取图片/文本等静态信息。目前 S3 部署在新加坡,虽然 CF 可以缓存静态资源,但资源的首次加载或缓存过期、仍旧会增加美西用户的访问耗时。希望提供方案解决多个 Region 用户的访问体验。
解决方案
可以在美西和新加坡 2 个区域均部署 S3 存储桶,当客户端请求访问 CloudFront 时未命中时后访问 Origin 源站时,利用 Lambda@edge 在 Origin Request 阶段可以对 Request 请求进行 Domain 和 Host 的修改的特性,动态去修改源站的域名从而达到就近访问的目的,提高用户体验。
架构方案
工作流程
前置工作
1. 在 CloudFront 的 Behavior 上设置 Original Request 关联 Lambda@edge,当请求经过 Original Request 时,通过 Lambda@edge 进行修改。
2. 在美西和新加坡上创建 S3 存储桶,并在 CloudFront 上以 S3 为目标创建源。
注意(可选):为了安全访问 S3 存储桶(不打开公开访问),可以通过 Cloudfront 的 OAC/OAI 身份验证方式来访问 S3,建议使用 OAC(Origin Access Control),因为它支持:
▪ Amazon Website Service 区域中的所有 Amazon S3 存储桶,包括 2022 年 12 月之后推出的选择加入区域。
▪ Amazon S3 使用 Amazon KMS 的服务器端加密(SSE-KMS)。
▪ 对 Amazon S3 的动态请求( PUT 和 DELETE )。
以下为 OAC 的配置(可选)
在 S3 的 Policy 上配置只允许 OAC 访问
{
"Version": "2012-10-17",
"Statement": {
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront:::distribution/"
}
}
}
}
左滑查看更多
在 CloudFront 的 Origin 上开启 OAC
选择“签署请求”后,CloudFront 将使用 SigV4 签署每个发送到 S3 的 Request。它将包含身份验证信息、日期、动作、和参数等。以 Authorization head 的形式发送给 S3,S3 接受到信息后,通过密钥对信息进行签名然后进行比对。通过后处理请求。
最后,创建 Origin group,并将 CloudFront 的 behavior 上的源配置改为 Origin Group。
具体流程
1. 客户端发送请求至 CloudFront。
2. 请求未命中缓存时,在 Edge Location 上,CloudFront 在 Origin Request 调用 Lambda@edge。
3. Lambda@edge 读取当前 Region 的 Code,识别出是 us-west2 或者是 ap-southeast-1,并根据代码里预设的 map。找到该 region 对应的 S3 的地址(注意:也可以基于 route53 的延迟策略来找到最合适的 S3 存储桶位置,参考资料里会有此种方法的链接)。
4. Lambda@edge 修改 Request 的域名地址,Request 请求会路由到对应 S3 存储桶。
5. 返回从存储桶获取的对象到客户端。
Lambda@edge 代码具体如下:
import json
us_bucket = "amazon-cloudfront-secure-static-site-s3bucketroot-21aorhazvsj1.s3.amazonaws.com"
ap_bucket = "amazon-cloudfront-sin-s3root.s3.ap-southeast-1.amazonaws.com"
default_bucket = "amazon-cloudfront-secure-static-site-s3bucketroot-21aorhazvsj1.s3.amazonaws.com"
s3Mapping = {
"us-east-1": us_bucket,
"us-east-2": us_bucket,
"eu-central-1": us_bucket,
"eu-west-2": us_bucket,
"ap-southeast-1": ap_bucket
}
def lambda_handler(event, context):
request = event['Records'][0]['cf']['request']
defaultRequest = event['Records'][0]['cf']['request']
print(request['origin'])
print('req='+json.dumps(request))
try:
originKey = list(request['origin'].keys())[0]
if originKey != 's3'
return request
currentRegion = context.invoked_function_arn.split(':')[3]
print("aaa="+currentRegion)
domainName = s3Mapping.get(currentRegion, default_bucket)
request['origin']['s3']['domainName'] = domainName
request['headers']['host'] = [{'key': 'host', 'value': domainName}]
return request
except TypeError:
print('modify s3 domain failure')
return defaultRequest
左滑查看更多
总结
本文介绍了如何利用 Lambda@edge 构建多区域就近访问应用,从而减少回源延迟,提升性能。通过在 CloudFront 中配置多个区域的源站,并利用 Lambda@edge 在 Origin Request 阶段修改请求的特性,动态地修改源站的域名,可以实现就近访问的目的。此外,这个方案还具有以下几个优势:
高可用性:通过在多个区域部署源站和 CloudFront,可以实现高可用性,确保即使某个区域出现问题,应用仍然可以正常访问。
高性能:通过将静态资源分发到多个区域,并在边缘节点上缓存最新的资源,并在下一次请求时直接从缓存中获取,可以减少回源的次数和延迟,从而提高性能。
通用性:除了对 S3 源站进行加速,在 API Gateway 等服务中也可以应用类似的方案,实现跨区域访问降低延迟的目的。
通过利用 Lambda@edge 和 CloudFront 构建多区域就近访问应用,可以提高用户体验,减少回源延迟,提升性能,同时还具有高可用性和通用性,是一个非常值得尝试的解决方案。
参考资料
OAC: Amazon CloudFront introduces Origin Access Control (OAC) | Networking
https://aws.amazon.com/cn/blogs/networking-and-content-delivery/amazon-cloudfront-introduces-origin-access-control-oac/
SignV4:
https://docs.aws.amazon.com/IAM/latest/UserGuide/signing-elements.html
基于 Route53 的延迟策略动态修改 API gateway:
https://aws.amazon.com/cn/blogs/china/build-nft-offering-systems-with-cloud-native-components/
本篇作者
杨俊
亚马逊云科技资深解决方案架构师。加入亚马逊云科技之前,主要从事电商和零售相关的系统开发工作,具备丰富的零售行业经验和企业上云实践经验。
夏宁
亚马逊云科技解决方案架构师,曾就职惠普软件和声网,超过 10 年前端后端开发经验,主导过各类软件项目设计。熟悉移动互联网,音视频,云计算相关领域。
听说,点完下面4个按钮
就不会碰到bug了!