亚马逊AWS官方博客

Amazon S3 Object Lambda介绍——在S3检索期间使用自有代码进行数据处理

原文链接:

https://aws.amazon.com/cn/blogs/aws/introducing-amazon-s3-object-lambda-use-your-code-to-process-data-as-it-is-being-retrieved-from-s3/

 

通过将数据存储在Amazon Simple Storage Service (S3)当中,我们可以轻松在多个应用程序之间实现数据共享与使用。但不同应用对数据往往有着特殊要求,而且可能需要配合不同的数据视图。例如,电子商务应用所创建的数据集可能包含个人身份信息(Personally identifiable information PII),因此在内部分析时应当对敏感部分加以修订;而在市场营销预测场景下,这部分数据往往需要配合客户忠诚度等其他信息加以充实。

要向多种应用程序提供不同数据视图,目前主流的实现方式主要分两种。其一是由您自主创建、存储并维护数据的其他衍生副本,确保每款应用程序都拥有专属的自定义数据集;其二,您也可以在S3之前引入代理基础层,构建并管理基础设施,借此根据请求实现数据拦截与处理。但这两种选项都会带来额外的复杂性与运营成本,因此S3团队决定开发出一套更合理的解决方案。

今天,我们很高兴宣布S3 Object Lambda。这项新功能允许您添加自有代码以处理S3提供的检索数据,再将结果返回至应用程序。S3 Object Lambda能够与您的现有应用程序配合使用,并通过AWS Lambda函数在S3数据检索期间自动处理并转换数据内容。Lambda函数将通过标准S3 GET请求实现内联调用,因此您无需对应用程序代码做出任何修改。

如此一来,您能够轻松根据同一数据集生成多种视图,并随时更新Lambda函数以修改视图内容。

这种方式能够极大简化各类常见用例,例如:

  • 对分析或非生产环境下的个人身份信息进行修订。
  • 跨数据格式转换,例如将XML转换为JSON。
  • 配合来自其他服务或数据库的信息实现数据增强。
  • 在下载文件时,进行压缩或解压。
  • 根据特定呼叫方的具体情况(例如发出对象请求的用户)即时调整图像大小与水印。
  • 通过自定义授权规则管理数据访问。

只需以下几个简单步骤,大家即可轻松使用S3 Object Lambda:

  1. 创建一项Lambda函数,根据用例需求进行数据转换。
  2. 通过S3管理控制台创建一个S3 Object Lambda访问点。
  3. 选用您之前创建的Lambda函数。
  4. 提供一个支持性S3访问点,以供S3 Object Lambda访问原始对象。
  5. 更新您的应用程序配置,使用新的S3对象Lambda访问点检索S3内的数据。

为了更好地理解S3 Object Lambda的工作原理,本文通过以下示例做出说明。

如何为S3 Object Lambda创建一项Lambda函数

要创建此函数,我们首先来看Lambda函数从S3 Object Lambda处接收到的输入事件的具体语法:

{
    "xAmzRequestId": "1a5ed718-5f53-471d-b6fe-5cf62d88d02a",
    "getObjectContext": {
        "inputS3Url": "https://myap-123412341234.s3-accesspoint.us-east-1.amazonaws.com/s3.txt?X-Amz-Security-Token=...",
        "outputRoute": "io-iad-cell001",
        "outputToken": "..."
    },
    "configuration": {
        "accessPointArn": "arn:aws:s3-object-lambda:us-east-1:123412341234:accesspoint/myolap",
        "supportingAccessPointArn": "arn:aws:s3:us-east-1:123412341234:accesspoint/myap",
        "payload": "test"
    },
    "userRequest": {
        "url": "/s3.txt",
        "headers": {
            "Host": "myolap-123412341234.s3-object-lambda.us-east-1.amazonaws.com",
            "Accept-Encoding": "identity",
            "X-Amz-Content-SHA256": "e3b0c44297fc1c149afbf4c8995fb92427ae41e4649b934ca495991b7852b855"
        }
    },
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "...",
        "arn": "arn:aws:iam::123412341234:user/myuser",
        "accountId": "123412341234",
        "accessKeyId": "..."
    },
    "protocolVersion": "1.00"
}

 

其中的getObjectContext属性包含关于Lambda函数的几项重要信息:

  • 其中inputS3Url为预签名URL,供函数用于从支持性访问点处下载原始对象。通过这种方式,此Lambda函数无需S3读取权限即可检索原始对象,且在调用中仅可访问处理后的对象。
  • 其中的outputRouteoutputToken 则为两项参数,负责通过新的WriteGetObjectResponse API发回修改后的对象。

configuration属性中则包含Object Lambda访问点与支持性访问点的Amazon资源名称(ARN)。

userRequest属性则提供关于原始请求的更多详细信息,例如URL中的路径以及HTTP标头等。

最后,userIdentity部分将返回原始请求方的详细信息,并可用于对数据执行自定义访问。

现在,我们已经掌握了事件语法,接下来可以创建Lambda函数了。为简单起见,我们使用由Python编写的函数,目标是将原始对象中的所有文本内容更改为大写形式:

import boto3
import requests

def lambda_handler(event, context):
    print(event)

    object_get_context = event["getObjectContext"]
    request_route = object_get_context["outputRoute"]
    request_token = object_get_context["outputToken"]
    s3_url = object_get_context["inputS3Url"]

    # 从S3处获取对象
    response = requests.get(s3_url)
    original_object = response.content.decode('utf-8')

    # 转换对象
    transformed_object = original_object.upper()

    # 将对象写入回S3 Object Lambda
    s3 = boto3.client('s3')
    s3.write_get_object_response(
        Body=transformed_object,
        RequestRoute=request_route,
        RequestToken=request_token)

    return {'status_code': 200}

 

查看此函数中的代码,可以看到其主要分为三个部分:

  • 首先,我们使用输入事件中的inputS3Url属性以下载原始对象。由于此属性的值为一条预签名URL,因此该函数并不需要S3数据读取权限。
  • 接下来,我们将文本内容全部转换为大写。要针对用例对函数行为进行自定义,我们需要更改相应部分。例如,要检测并修订个人身份信息(PII),我们可以使用Amazon Comprehend配合DetectPiiEntities API定位PII实体,并用星号或其他实体修订类型替换掉相应内容。
  • 最后,这里使用新的WriteGetObjectResponse API将转换结果发送回S3 Object Lambda。转换后的对象可能超出Lambda函数所能返回的响应结果的最大长度。如果对象过大, WriteGetObjectResponse API也支持分块传输编码以实现流数据传输。Lambda函数仅需要返回状态代码(在此用例中为200 OK)、最终错误,也可选择对返回对象元数据进行自定义,具体请参阅S3 GetObject API中的说明。

我们将此函数打包,包括其依赖项,并将成果上传至Lambda。请注意,S3 Object Lambda所使用的Lambda函数最长只能持续60秒,且Lambda函数需要具备Amazon身份与访问管理(IAM)权限方可正常调用WriteGetObjectResponse API。

如何通过控制台创建S3 Ojbect Lambda访问点

在S3控制台内,我们可以在任意S3存储桶之上创建S3访问点:

接下来,使用刚刚创建的支持性访问点创建一个S3 Object Lambda访问点,此Lambda函数将使用支持性访问点以下载原始对象。

在配置S3 Object Lambda访问点时,我们选择之前创建的Lambda函数的最新版本。作为可选项,我们也可以使用字节范围或分片编号实现请求支持。但在本文中,我们直接禁用这些功能。要了解如何在S3 Object Lambda当中使用字节范围与分片编号,请参阅说明文档

在配置S3对象Lambda访问点时,我们可以将字符串设置为payload,并在由该访问点执行的所有调用中将payload传递给Lambda函数,具体请参见之前提到的示例事件中的configuration属性。通过这种方式,我们可以为多个S3 Object Lambda访问点配置同一Lambda函数,并使用payload的值自定义各个Lambda访问点的具体行为。

最后,我们可以设置一项策略,以类似于对普通S3访问点的操作方式通过Object Lambda访问点对对象发起访问。这里,我们将此策略留空。之后,保留其他默认选项以阻断公开访问,同时创建Object Lambda访问点。

现在,S3 Object Lambda访问点已经准备就绪,可以随时供您使用。

如何使用S3 Object Lambda访问点

在S3控制台中,我们选择新创建的Object Lambda访问点。之后在属性部分,复制其ARN以供后续使用。

使用Amazon命令行界面(CLI),我们将包含语句素材的文本文件上传至S3 Object Lambda访问点后的S3存储桶处:

aws cp s3.txt s3://danilop-data/

 

我们可以轻松在现有应用程序当中使用S3 Object Lambda。只需要使用S3 Object Lambda访问点的ARN替换掉S3存储桶,而后更新Amazon SDK以使用S3 Object Lambda ARN能够接受新的语法即可。

例如,以下Python脚本用于下载我们刚刚上传完成的文本文件:首先是直接从S3存储桶处下载,而后是从S3 Object Lambda访问点处下载。两轮下载间的唯一区别,只有Bucket参数的值。

import boto3

s3 = boto3.client('s3')

print('Original object from the S3 bucket:')
original = s3.get_object(
  Bucket='danilop-data',
  Key='s3.txt')
print(original['Body'].read().decode('utf-8'))

print('Object processed by S3 Object Lambda:')
transformed = s3.get_object(
  Bucket='arn:aws:s3-object-lambda:us-east-1:123412341234:accesspoint/myolap',
  Key='s3.txt')
print(transformed['Body'].read().decode('utf-8'))

这里在我自己的笔记本电脑上启动此脚本:

python3 read_original_and_transformed_object.py

得到的结果如下所示:

Original object on S3:
Amazon Simple Storage Service (Amazon S3) is an object storage service that offers industry-leading scalability, data availability, security, and performance. This means customers of all sizes and industries can use it to store and protect any amount of data for a range of use cases, such as data lakes, websites, mobile applications, backup and restore, archive, enterprise applications, IoT devices, and big data analytics.

Object processed by S3 Object Lambda:
AMAZON SIMPLE STORAGE SERVICE (AMAZON S3) IS AN OBJECT STORAGE SERVICE THAT OFFERS INDUSTRY-LEADING SCALABILITY, DATA AVAILABILITY, SECURITY, AND PERFORMANCE. THIS MEANS CUSTOMERS OF ALL SIZES AND INDUSTRIES CAN USE IT TO STORE AND PROTECT ANY AMOUNT OF DATA FOR A RANGE OF USE CASES, SUCH AS DATA LAKES, WEBSITES, MOBILE APPLICATIONS, BACKUP AND RESTORE, ARCHIVE, ENTERPRISE APPLICATIONS, IOT DEVICES, AND BIG DATA ANALYTICS.

第一条输出直接从源存储桶处下载而来,得到的为原始内容、未加任何修改。而第二次下载时,对象在检索中由Lambda函数接手处理,最终得到的文本内容均为大写!

关于S3 Object Lambda的更多用例

在使用S3 Object Lambda检索对象时, S3存储桶内并不一定要有相同名称的对象存在。Lambda函数也可以使用文件名或者HTTP标头内的信息生成自定义对象。

例如,如果您要求对象名称为sunset_600x400.jpg的图像使用S3 Object Lambda访问点,则Lambda函数可以查找名为sunset.jpg的图像,并调整其大小以适合文件中所描述的最大宽度与高度名称。在这种情况下,由于对象密钥与预签名URL中使用的密钥不同,Lambda函数需要具备访问权限才能读取原始图像。

另一个有趣的用例,是检索基于数据库内容所即时生成的JSON或CSV文档,例如order.json或者items.csv。请求HTTP标头中的元数据可用于传递要使用的orderId。当然,大家也可以自行摸索出更多灵活的使用方式。

以下简短视频,展示了S3 Object Lambda的工作原理与使用方式:

上线情况与费率标准

S3 Object Lambda目前已在除亚太地区(大阪)、Amazon GovCloud(美国东部)、Amazon GovCloud(美国西部)、中国(北京)以及中国(宁夏)区域之外的所有Amazon区域内上线。您可以将S3 Object Lambda与Amazon管理控制台、Amazon命令行界面(CLI)以及Amazon SDK配合使用。目前,Amazon CLI中的高级S3命令(例如aws s3 cp)尚不支持来自S3 Object Lambda访问点的对象,但您可以使用aws s3api get-object等低级S3 API命令达成相同的效果。

要使用S3 Object Lambda,您需要为处理数据所占用的Amazon Lambda计算与请求资源付费,此外S3 Object Lambda返回至应用程序的数据以及Lambda函数所调用的S3请求也同样会产生成本。关于更多费率信息,请参阅Amazon S3费率页面

相信这项新功能,将帮助大家更轻松地跨多个应用程序实现数据共享与转换。

立即体验S3 Object Lambda以简化您的存储架构。

— Danilo

 

本篇作者

Danilo Poccia

Danilo与不同规模的初创公司及大型企业合作,努力提供各类创新支持。在担任Amazon Web Services首席布道师(欧洲、非洲与中东市场)期间,他利用自己的丰富经验帮助客户将创意灵感转化为现实。他主要关注无服务器架构与事件驱动编程,以及机器学习与边缘计算对于技术及业务的重大影响。他的论著《AWS Lambda in Action》由曼宁出版社出版发行。