View a markdown version of this page

使用 Lambda 以无服务器方式处理文件 - FSx for ONTAP

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用 Lambda 以无服务器方式处理文件

文件处理工作流程通常从到达 NFS 或 SMB 文件共享的文件开始,这些文件包括来自分支机构的扫描文档、现场团队上传的图像、从联络中心捕获的音频或合作伙伴提供的数据文件。

通过连接到 FSx for ONTAP 卷的 Amazon S3 接入点, AWS Lambda 函数可以直接使用 Amazon S3 API 读取和写入文件。 File-level 可以针对您的用户和应用程序通过 NFS 和 SMB 访问的相同数据进行无服务器处理操作。

本教程显示了三种常见的文件处理模式。每个示例都通过接入点从卷中读取文件,使用 AWS 服务或库对其进行处理,然后将结果写回卷。

示例 Input Processing Output
示例 1:生成图像缩略图 JPEG 图片 枕头(图片库) 调整了缩略图大小
示例 2:从文档中提取文本 PDF 文档 Amazon Textract 提取的文本 (JSON)
示例 3:转录音频文件 MP3 音频 Amazon Transcribe 笔录 (JSON)
注意

完成本教程大约需要 40 到 60 分钟。 AWS 服务 使用者会对您创建的资源产生费用。如果您及时完成所有步骤,包括清理部分,则美国东部(弗吉尼亚北部)的预期费用将低于 1美元 AWS 区域。该估算值不包括 FSx 对 ONTAP 容量本身的持续费用。

先决条件

在开始之前,请确保您具有以下各项:

  • 连接了 Amazon S3 接入点的 ONTAP 卷的 FSx。有关创建接入点的说明,请参阅创建接入点

  • 您的接入点的接入点别名。你可以在 Amazon FSx 控制台中找到它,也可以通过运行来找到。aws fsx describe-s3-access-point-attachments

  • AWS CLI 已安装并配置版本 1 或版本 2。本教程中的aws lambda invoke命令包括--cli-binary-format raw-in-base64-out选项,该选项在 AWS CLI 版本 2 中是必需的,这样原始 JSON 负载就不会被解释为 base64。如果您使用 AWS CLI 版本 1,请省略该选项。

  • 调用者(运行本教程的用户或角色)的 IAM 权限,用于调用 Lambda 函数 (lambda:CreateFunction,lambda:InvokeFunction)、访问 Amazon S3 接入点 (s3:GetObject,s3:PutObject) 和传递 Lambda 执行角色 ()。iam:PassRole

注意

本教程使用默认 Lambda 配置,其中函数在您的 VPC 之外的托管网络中运行。在这种情况下,接入点必须具有互联网网络来源,以便功能可以访问它。如果您将 Lambda 函数附加到 VPC,则可以在接入点上使用 VPC 网络来源;VPC 必须具有 Amazon S3 网关或接口终端节点。有关更多信息,请参阅 为 Amazon S3 接入点配置网络访问权限

步骤 1:上传示例文件

下载以下示例文件并通过接入点将其上传到您的 FSx for ONTAP 卷。在本教程中my-ap-alias-ext-s3alias,请使用您的接入点别名替换。

通过接入点将示例文件上传到您的 FSx for ONTAP 卷。

$ aws s3 cp sample-image.jpg s3://my-ap-alias-ext-s3alias/samples/images/sample-image.jpg aws s3 cp sample-audio.mp3 s3://my-ap-alias-ext-s3alias/samples/audio/sample-audio.mp3
注意

样本图像是美国宇航局的蓝色大理石照片(公共领域,2.4 MB)。示例音频来自 Amazon Transcribe 入门教程 (410 KB)。样本 PDF 是在中生成的示例 2:从文档中提取文本

步骤 2:创建 Lambda 执行角色

Lambda 函数扮演执行角色与其他函数进行交互。 AWS 服务在本教程中,请附上 CloudWatch 日志记录的 AWS托管AWSLambdaBasicExecutionRole策略,然后添加一个内联策略,授予对 Amazon S3 接入点以及示例使用的 Textract 和 Transcribe API 的访问权限。

用您的值替换regionaccount-id、和access-point-name

  1. 将以下信任策略另存为trust-policy.json

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole" } ] }
  2. 将以下内联权限策略另存为permissions-policy.json。它授予访问接入点和示例使用的其他服务的访问权限。

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"], "Resource": [ "arn:aws:s3:region:account-id:accesspoint/access-point-name", "arn:aws:s3:region:account-id:accesspoint/access-point-name/object/*" ] }, { "Effect": "Allow", "Action": ["textract:DetectDocumentText"], "Resource": "*" }, { "Effect": "Allow", "Action": [ "transcribe:StartTranscriptionJob", "transcribe:GetTranscriptionJob" ], "Resource": "*" } ] }
  3. 创建角色,附加托管日志策略并附加内联策略。

    $ aws iam create-role \ --role-name fsxn-lambda-file-processor \ --assume-role-policy-document file://trust-policy.json aws iam attach-role-policy \ --role-name fsxn-lambda-file-processor \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole aws iam put-role-policy \ --role-name fsxn-lambda-file-processor \ --policy-name fsxn-access-point-policy \ --policy-document file://permissions-policy.json

集成到您的工作流程中

本教程中的示例使用带有测试事件的手动调用。在生产环境中,您可以使用以下方法自动触发这些函数:

  • 亚马逊 EventBridge 日程安排。定期运行该函数(例如,每小时或每天)以处理新文件。该功能可以通过接入点列出文件并处理任何尚未处理的文件。有关更多信息,请参阅亚马逊 EventBridge用户指南 EventBridge中的使用计划 Lambda 函数

  • 亚马逊 API Gateway。将该函数公开为 HTTP API,以便用户或应用程序可以根据需要请求处理特定文件。有关更多信息,请参阅亚马逊 API Gateway 开发者指南中的使用 Lambda 集成 API Gateway RES T API

  • Step Functions。编排组合多个 Lambda 函数的多步骤文件处理管道。例如,一种从文档中提取文本、对其进行翻译并将结果写回卷的工作流程。有关更多信息,请参阅AWS Step Functions 开发人员指南中的使用 Step Functions 调用 Lambda

示例 1:生成图像缩略图

此示例从 FSx 中读取 ONTAP 音量的 JPEG 图像,使用 Pillow 图像库将其大小调整为 200 像素的缩略图,然后将缩略图写回音量。

Lambda 函数代码

将以下代码另存为lambda_function.py

import boto3 from io import BytesIO from PIL import Image s3 = boto3.client('s3') def lambda_handler(event, context): bucket = event['access_point_alias'] key = event['key'] # Read the image from FSx through the access point response = s3.get_object(Bucket=bucket, Key=key) image_data = response['Body'].read() # Resize to thumbnail img = Image.open(BytesIO(image_data)) img.thumbnail((200, 200)) # Write the thumbnail back to FSx buffer = BytesIO() img.save(buffer, format='JPEG', quality=85) buffer.seek(0) thumbnail_key = key.rsplit('.', 1)[0] + '_thumbnail.jpg' s3.put_object( Bucket=bucket, Key=thumbnail_key, Body=buffer.getvalue(), ContentType='image/jpeg' ) return { 'original_size': len(image_data), 'thumbnail_size': len(buffer.getvalue()), 'thumbnail_key': thumbnail_key }

创建并调用该函数

此功能需要 Pillow 库。创建一个包含专为 Lambda Linux 运行时构建的 Pillow 的部署包。

$ # Create a deployment package with Pillow for Lambda (Linux) mkdir package && pip install Pillow -t package/ \ --platform manylinux2014_x86_64 --only-binary=:all: cd package && zip -r ../thumbnail-function.zip . cd .. && zip thumbnail-function.zip lambda_function.py # Create the function aws lambda create-function \ --function-name fsxn-thumbnail-generator \ --runtime python3.12 \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::account-id:role/fsxn-lambda-file-processor \ --zip-file fileb://thumbnail-function.zip \ --timeout 30 \ --memory-size 256 # Invoke with a test event aws lambda invoke \ --function-name fsxn-thumbnail-generator \ --cli-binary-format raw-in-base64-out \ --payload '{"access_point_alias": "my-ap-alias-ext-s3alias", "key": "samples/images/sample-image.jpg"}' \ response.json cat response.json

验证结果

$ aws s3 ls s3://my-ap-alias-ext-s3alias/samples/images/ 2024-01-23 12:19:32 2566770 sample-image.jpg 2024-01-23 12:25:49 7065 sample-image_thumbnail.jpg

最初的 2.4 MB 图像(5400 × 2700 像素)的大小调整为 7 KB 的缩略图(200 × 100 像素)。

示例 2:从文档中提取文本

此示例从 FSx for ONTAP 卷中读取 PDF 文档,将其发送到 Amazon Textract 以提取文本,然后将提取的文本作为 JSON 文件写回该卷。

创建并上传示例 PDF

在本示例中,你需要在 FSx for ONTAP 卷上有一个 PDF 文档。以下 Python 脚本生成一个简单的发票 PDF 并通过接入点将其上传。在您的本地计算机上运行此脚本(不是 Lambda)。

$ pip install fpdf2 boto3
# create_invoice.py — run locally to generate and upload a sample PDF from fpdf import FPDF import boto3 pdf = FPDF() pdf.add_page() pdf.set_font("Helvetica", "B", 24) pdf.cell(0, 15, "INVOICE", new_x="LMARGIN", new_y="NEXT", align="C") pdf.set_font("Helvetica", "", 12) pdf.cell(0, 8, "Invoice Number: INV-2024-00142", new_x="LMARGIN", new_y="NEXT") pdf.cell(0, 8, "Date: January 15, 2024", new_x="LMARGIN", new_y="NEXT") pdf.cell(0, 8, "Customer: Example Corp", new_x="LMARGIN", new_y="NEXT") pdf.ln(5) pdf.set_font("Helvetica", "B", 12) pdf.cell(80, 8, "Description", border=1) pdf.cell(30, 8, "Qty", border=1, align="C") pdf.cell(40, 8, "Unit Price", border=1, align="R") pdf.cell(40, 8, "Amount", border=1, align="R") pdf.ln() pdf.set_font("Helvetica", "", 12) for desc, qty, price, amt in [ ("Cloud Storage Service", "1", "$2,400.00", "$2,400.00"), ("Data Transfer (TB)", "5", "$90.00", "$450.00"), ("Technical Support", "1", "$500.00", "$500.00"), ]: pdf.cell(80, 8, desc, border=1) pdf.cell(30, 8, qty, border=1, align="C") pdf.cell(40, 8, price, border=1, align="R") pdf.cell(40, 8, amt, border=1, align="R") pdf.ln() s3 = boto3.client('s3') s3.put_object( Bucket='my-ap-alias-ext-s3alias', Key='samples/documents/invoice.pdf', Body=pdf.output(), ContentType='application/pdf' ) print("Uploaded invoice.pdf")
$ python3 create_invoice.py

Lambda 函数代码

将以下代码另存为lambda_function.py

import boto3 import json s3 = boto3.client('s3') textract = boto3.client('textract') def lambda_handler(event, context): bucket = event['access_point_alias'] key = event['key'] # Read the PDF from FSx through the access point response = s3.get_object(Bucket=bucket, Key=key) document_bytes = response['Body'].read() # Extract text with Textract textract_response = textract.detect_document_text( Document={'Bytes': document_bytes} ) lines = [ block['Text'] for block in textract_response['Blocks'] if block['BlockType'] == 'LINE' ] # Write extracted text as JSON back to FSx result = { 'source_file': key, 'total_lines': len(lines), 'extracted_text': lines } output_key = key.rsplit('.', 1)[0] + '_extracted.json' s3.put_object( Bucket=bucket, Key=output_key, Body=json.dumps(result, indent=2), ContentType='application/json' ) return { 'lines_extracted': len(lines), 'output_key': output_key }

创建并调用该函数

$ zip textract-function.zip lambda_function.py aws lambda create-function \ --function-name fsxn-text-extractor \ --runtime python3.12 \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::account-id:role/fsxn-lambda-file-processor \ --zip-file fileb://textract-function.zip \ --timeout 30 \ --memory-size 256 aws lambda invoke \ --function-name fsxn-text-extractor \ --cli-binary-format raw-in-base64-out \ --payload '{"access_point_alias": "my-ap-alias-ext-s3alias", "key": "samples/documents/invoice.pdf"}' \ response.json cat response.json

输出示例:

{"lines_extracted": 22, "output_key": "samples/documents/invoice_extracted.json"}

示例 3:转录音频文件

此示例为存储在 FSx 上的 ONTAP 音量的音频文件启动 Amazon Transcribe 作业。Amazon Transcribe 使用媒体文件 URI 中的接入点别名直接从接入点读取音频文件。作业完成后,该函数会将脚本写回卷中。

Lambda 函数代码

将以下代码另存为lambda_function.py

import boto3 import json import time import urllib.request s3 = boto3.client('s3') transcribe = boto3.client('transcribe') def lambda_handler(event, context): bucket = event['access_point_alias'] key = event['key'] media_format = key.rsplit('.', 1)[-1] # mp3, wav, etc. # Start a Transcribe job pointing to the file on FSx job_name = f"fsxn-{int(time.time())}" transcribe.start_transcription_job( TranscriptionJobName=job_name, Media={'MediaFileUri': f's3://{bucket}/{key}'}, MediaFormat=media_format, LanguageCode='en-US' ) # Wait for the job to complete while True: status = transcribe.get_transcription_job( TranscriptionJobName=job_name ) state = status['TranscriptionJob']['TranscriptionJobStatus'] if state in ('COMPLETED', 'FAILED'): break time.sleep(5) if state == 'FAILED': raise Exception( status['TranscriptionJob'].get('FailureReason', 'Unknown error') ) # Download the transcript transcript_uri = status['TranscriptionJob']['Transcript']['TranscriptFileUri'] with urllib.request.urlopen(transcript_uri) as resp: transcript_data = json.loads(resp.read()) transcript_text = transcript_data['results']['transcripts'][0]['transcript'] # Write the transcript back to FSx result = { 'source_file': key, 'job_name': job_name, 'transcript': transcript_text } output_key = key.rsplit('.', 1)[0] + '_transcript.json' s3.put_object( Bucket=bucket, Key=output_key, Body=json.dumps(result, indent=2), ContentType='application/json' ) return { 'transcript_length': len(transcript_text), 'output_key': output_key }

创建并调用该函数

$ zip transcribe-function.zip lambda_function.py aws lambda create-function \ --function-name fsxn-audio-transcriber \ --runtime python3.12 \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::account-id:role/fsxn-lambda-file-processor \ --zip-file fileb://transcribe-function.zip \ --timeout 120 aws lambda invoke \ --function-name fsxn-audio-transcriber \ --cli-binary-format raw-in-base64-out \ --payload '{"access_point_alias": "my-ap-alias-ext-s3alias", "key": "samples/audio/sample-audio.mp3"}' \ --cli-read-timeout 180 \ response.json cat response.json
注意

Transcribe 作业通常需要 15 到 45 秒才能完成。为此,该函数的超时设置为 120 秒。

注意事项

  • 默认配置需要互联网来源。默认情况下,Lambda 从您的 VPC 之外的托管基础设施访问 Amazon S3,这需要一个源自互联网的接入点。如果您将 Lambda 函数附加到 VPC,则可以改用 VPC-origin 接入点。有关详细信息,请参阅先决条件。

  • 文件大小限制。Lambda 函数的最大内存为 10 GB,最长执行时间为 15 分钟。对于大型文件,可以考虑使用范围读取(GetObjectRange标头)或流式传输响应。

  • Textract 限制。同步 DetectDocumentText API 接受最大 10 MB 和 1 页的文档。对于多页文档,请使用异步 StartDocumentTextDetection API。

  • Transcribe 直接从接入点读取。Amazon Transcribe 接受MediaFileUri参数 () s3://ap-alias/key 中的接入点别名。Lambda 函数不需要下载和重新上传音频文件。

  • 文件系统用户权限。与接入点关联的文件系统用户必须具有输入文件的读取权限和输出目录的写入权限。

清理

为避免持续收费,请删除您在本教程中创建的资源。

$ # Delete Lambda functions aws lambda delete-function --function-name fsxn-thumbnail-generator aws lambda delete-function --function-name fsxn-text-extractor aws lambda delete-function --function-name fsxn-audio-transcriber # Delete the IAM role and policies aws iam delete-role-policy \ --role-name fsxn-lambda-file-processor \ --policy-name fsxn-access-point-policy aws iam detach-role-policy \ --role-name fsxn-lambda-file-processor \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole aws iam delete-role --role-name fsxn-lambda-file-processor # Delete sample files from your FSx volume aws s3 rm s3://my-ap-alias-ext-s3alias/samples/ --recursive