亚马逊AWS官方博客

利用 Lambda@edge 构建多区域就近访问应用

摘要

本文将介绍如何使用 Lambda@edge 和 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),因为它支持:

  • AWS 区域中的所有 Amazon S3 存储桶,包括 2022 年 12 月之后推出的选择加入区域。
  • Amazon S3 使用 AWS KMS 的服务器端加密(SSE-KMS)。
  • 对 Amazon S3 的动态请求(PUTDELETE)。

以下为 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:::<S3 bucket name>/*",
        "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::<AWS 账户 ID>:distribution/<CloudFront distribution ID>"
            }
        }
    }
}

在 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

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/

本篇作者

杨俊

亚马逊云科技资深解决方案架构师。加入 AWS 之前,主要从事电商和零售相关的系统开发工作,具备丰富的零售行业经验和企业上云实践经验。

夏宁

亚马逊云科技解决方案架构师,曾就职惠普软件和声网,超过 10 年前端后端开发经验,主导过各类软件项目设计。熟悉移动互联网,音视频,云计算相关领域。