我非常高兴地宣布,AWS Lambda功能现在可以挂载Amazon Elastic File System(EFS),这是一种高度可扩展的弹性NFS文件系统,可在多个可用区(AZ)内和跨多个可用区(AZ)存储数据,以实现高可用性和耐用性。通过这种方式,您可以使用熟悉的文件系统接口在具有一个或多个Lambda函数的所有并发执行环境中存储和共享数据。EFS支持完整的文件系统访问语义,例如强一致性和文件锁定。
要将EFS文件系统与lambda函数连接,您可以使用EFS访问点,这是进入EFS文件系统的特定于应用程序的入口点,它包括访问文件系统时要使用的操作系统用户和组、文件系统权限,并且可以限制对文件系统中特定路径的访问。这有助于保持文件系统配置与应用程序代码的分离。
您可以使用相同或不同的访问点从多个功能访问相同的EFS文件系统。例如,使用不同的EFS访问点,每个Lambda函数可以访问文件系统中的不同路径,或者使用不同的文件系统权限。
您可以与Amazon Elastic Compute Cloud(EC2)实例、使用Amazon ECS和AWS Fargate的集装化应用程序以及内部部署服务器共享相同的EFS文件系统。按照这种方法,您可以使用不同的计算体系结构(函数、容器、虚拟服务器)来处理相同的文件。例如,响应事件的Lambda函数可以更新容器上运行的应用程序读取的配置文件。或者,您可以使用Lambda函数来处理由运行在EC2上的Web应用程序上传的文件。
通过这种方式,使用Lambda函数实现一些用例要容易得多。例如:
使用原子操作在文件系统内移动目录及其所有内容。
创建EFS文件系统要挂载EFS文件系统,您的Lambda函数必须连接到可以访问EFS挂载目标的Amazon Virtual Private Cloud。但是为简单起见,我在这里使用的是在每个AWS区域中自动创建的默认VPC地址。
请注意,将Lambda功能连接到vPC时,网络的工作方式不同。如果您的Lambda功能使用Amazon Simple Storage Service(S3)或Amazon DynamoDB,则应为这些服务创建网关vPC端点。如果您的Lambda函数需要访问公网,例如调用外部API,则需要配置NAT网关。我通常不会更改默认私有网络的配置。如果我有特定要求,我可以使用AWS云开发工具包或使用这些AWS CloudFortification示例模板之一创建具有私有子网和公有子网的新vPC。这样,我就可以将网络作为代码来管理。
在EFS控制台中,我选择了创建文件系统,并确保选择了默认私有网络及其子网。对于所有子网,我都使用默认安全组,该默认安全组通过相同的安全组授予对私有网络中其他资源的网络访问权限。
在下一步中,我为文件系统提供了一个name标记,并将所有其他选项保留为默认值。
然后,我选择Add Access Point(添加接入点)。我使用1001作为用户和组ID,并限制对/message路径的访问。在“所有者”部分(用于在第一次连接到接入点时自动创建文件夹)中,我使用与以前相同的用户和组ID,并使用750作为权限。拥有此权限后,所有者可以读取、写入和执行文件。同一组中的用户只能读取。其他用户没有访问权限。
将EFS与Lambda函数结合使用从一个简单的用例开始,让我们构建一个Lambda函数,实现MessageWALL API来添加、读取或删除文本消息。消息存储在EFS上的一个文件中,这样Lambda函数的所有并发执行环境都可以看到相同的内容。
在Lambda控制台中,我创建了一个新的MessageWall函数,并选择Python3.8运行时。在权限部分,我保留默认值。这将创建一个具有基本权限的新AWS Identity and Access Management(IAM)角色。
创建函数后,在Permission选项卡中,单击IAM角色名称以在IAM控制台中打开该角色。在这里,我选择Attach Policies以添加AWSLambdaVPCAccessExecutionRole和AmazonElasticFileSystemClientReadWriteAccess的AWS托管策略。在生产环境中,您可以限制对特定VPC和EFS接入点的访问。
回到Lambda控制台,我编辑vPC配置,使用与EFS挂载点相同的默认安全组,将MessageWall函数连接到默认vPC中的所有子网。
现在,我在函数配置的新文件系统部分选择添加文件系统。在这里,我选择前面创建的EFS文件系统和访问点。对于本地挂载点,我使用/mnt/msg和Save。这是将挂载访问点的路径,与我的EFS文件系统中的/message文件夹相对应。
在Lambda控制台的函数代码编辑器中,粘贴以下代码并保存。
import os import fcntl msg_file_path=';/mnt/msg/content';def get_message():try:with open(msg_file_path,';r';)as msg_file:fcntl.flock(msg_file,fcntl.LOCK_SH)message=msg_file.read()fcntl.flock(msg_file,fccntl.flock。返回消息def add_message(New_Message):with open(msg_file_path,';a';)as msg_file:fcntl.flock(msg_file,fcntl.LOCK_ex)msg_file.write(new_message+";\n";)fcntl.flock(msg_file,fcntl.LOCK_UN)定义DELETE_MESSAGES():Try:os.remove(MSG_FILE_PATH),除了:pass def lambda_Handler(Event,Context):Method=event[';requestContext';][';http';][';method';]if Method==';Get';:Messages=Get_Messages()Elif Method==';POST';用法:NEW_MESSAGE=EVENT[';BODY';]add_message(NEW_MESSAGE)MESSAGES=GET_MESSAGES()ELIF METHOD=';DELETE';参数:DELETE_MESSAGES()MESSAGES=';已删除的消息。';ELSE:Messages=';方法不受支持。';返回消息。
我选择Add Trigger,然后在配置中选择Amazon API Gateway。我创建了一个新的HTTP API。为简单起见,我让我的API端点保持开放。
选择API Gateway触发器后,我复制刚刚创建的新API的端点。
$cURL https://1a2b3c4d5e.execute-api.us-east-1.amazonaws.com/default/MessageWall尚无消息。$CURL-X POST-H&34;内容类型:TEXT/PLAN";-d';来自EFS的https://1a2b3c4d5e.execute-api.us-east-1.amazonaws.com/default/MessageWall问候!$CURL-X POST-H&34;内容类型:TEXT/PLAN";-d';再次问候:)';https://1a2b3c4d5e.execute-api.us-east-1.amazonaws.com/default/MessageWall从应急服务中心发来的您好!再次问候:)$cURL https://1a2b3c4d5e.execute-api.us-east-1.amazonaws.com/default/MessageWall来自efs的问候!再次问候:)$CURL-X删除已删除的https://1a2b3c4d5e.execute-api.us-east-1.amazonaws.com/default/MessageWall消息。$cURL https://1a2b3c4d5e.execute-api.us-east-1.amazonaws.com/default/MessageWall尚无消息。
为不同的用户添加唯一的文件名(或特定的子目录)相对容易,并将这个简单的示例扩展为更完整的消息传递应用程序。作为一名开发人员,我欣赏在代码中使用熟悉的文件系统接口的简单性。但是,根据您的要求,必须考虑EFS吞吐量配置。有关更多信息,请参阅帖子后面的了解EFS性能一节。
现在,让我们使用AWS Lambda中新的EFS文件系统支持来构建更有趣的东西。例如,让我们使用EFS提供的额外空间来构建处理图像的机器学习推理API。
构建无服务器机器学习推理API要创建实现机器学习推理的Lambda函数,我需要能够在我的代码中导入必要的库并加载机器学习模型。这样做时,这些依赖项的总体大小通常会超过部署包大小中当前的AWS Lambda限制。解决这一问题的一种方法是,准确地最小化随函数代码一起提供的库,然后从S3存储桶直接将模型下载到内存(最高3 GB,包括处理新模型所需的内存)或下载到/tmp(最高512 MB)。这种模型的自定义最小化和下载从来都不容易实现。现在,我可以使用EFS文件系统了。
我这次正在构建的Lambda函数需要访问公共互联网,以下载预先训练好的模型和要运行推断的图像。所以我新建了一个包含公网和内网的私有网络,并配置了NAT网关和内网使用的路由表来访问公网。使用AWS云开发工具包,只需几行代码。
我在新的私有网络中创建了一个新的EFS文件系统和一个访问点,使用的配置与前面类似。这一次,我对接入点路径使用了1/ml*。
然后,我创建了一个新的MLInference Lambda函数,权限设置与之前相同,并将该函数连接到新VPC的内网。机器学习推理是相当繁重的工作负载,所以我选择3 GB作为内存,5分钟作为超时。在文件系统配置中,我添加了新的访问点,并将其挂载到/mnt/inference下。
我为这个函数使用的机器学习框架是PyTorch,我需要将运行推理所需的库放在EFS文件系统中。我在新VPC的公有子网中启动了一个Amazon Linux:EC2实例。在实例详细信息中,我选择其中一个具有EFS挂载点的可用区,然后添加文件系统以自动挂载用于该函数的同一个EFS文件系统。对于EC2实例的安全组,我选择了缺省安全组(以便能够挂载EFS文件系统)和一个授予SSH入站访问权限(以便能够连接到实例)的安全组。
我使用SSH连接到该实例,并创建包含所需依赖项的requirements.txt文件:
EFS文件系统由EC2自动挂载在/mnt/efs/fs1下。在那里,我创建了/ml目录,并将路径所有者更改为我现在正在使用的用户和组(ec2-user)。
我安装了Python3并使用pip在/mnt/efs/fs1/ml/lib路径中安装依赖项:
最后,我将整个/ml路径的所有权授予用于EFS接入点的用户和组:
总体而言,我的EFS文件系统中的依赖项使用了大约1.5 GB的存储。
我回到MLInference Lambda函数配置。根据您使用的运行时,您需要找到一种方法来告诉您在哪里查找依赖项(如果依赖项没有包含在部署包中或层中)。在使用Python的情况下,我将PYTHONPATH环境变量设置为/mnt/inference/lib。
我要用PyTorch Hub下载这个预先训练好的机器学习模型,来识别图片中的鸟的种类。我在本例中使用的模型相对较小,大约为200MB。要在EFS文件系统上缓存模型,我将TORCH_HOME环境变量设置为/mnt/inference/model。
所有依赖项现在都在函数挂载的文件系统中,我可以直接在函数代码编辑器中键入代码。我粘贴以下代码以拥有一个机器学习推理API:
导入urllib import json import os导入PIL中的手电筒导入图像从Torchvision导入Transform_TEST=Transforms.Compose([Transforms.Resize((600600),Image.BILINEAR),Transforms.CenterCrop((448,448)),Transforms.To张量器(),Transforms.Normalize((0.485,0.456,0.406),(0.229,0.224,0.225),])Model=torch.hub.load(';nicolalandro/ntsnet-cub200';,';ntsnet';,预训=真,**{';topN';:6,';设备';:';cpu';,';num_class';:200})model.eval()def lambda_Handler(Event,Context):url=event[';queryStringParameters';][';url';]img=Image.open(urllib.request.urlopen(Url))scale_img=Transform_test(Img)torch_images=scale_img.unsquze(0)with torch.no_grad():top_n_cocoels,contat_out,raw_logits,contat_logits,part_logits,top_n_index,top_n_prob=model(Torch_Images)_,recast=torch.max。1)pred_id=recrect.item()bird_class=model.bird_classs[pred_id]print(';BIRD_CLASS:';,BIRD_CLASS)返回json.dump({";BIRD_CLASS";:BIRD_CLASS,})。
我添加了API Gateway作为触发器,类似于我之前对MessageWALL函数所做的操作。现在,我可以使用我刚刚创建的无服务器API来分析鸟类图片。我并不是这个领域的专家,所以我在维基百科上找了几张有趣的图片:
它起作用了!。查看Lambda函数的Amazon CloudWatch日志,我发现第一次调用(当该函数加载并准备在CPU上进行推理的预先训练的模型时)大约需要30秒。为了避免来自API Gateway的响应缓慢或超时,我使用预配置的并发性来保持函数就绪。下一次调用大约需要1.8秒。
当将EFS与lambda函数一起使用时,了解EFS性能对于了解EFS性能如何工作非常重要。对于吞吐量,可以将每个文件系统配置为使用突发或非资源调配模式。
使用突发模式时,所有EFS文件系统(无论大小)都可以突发至少100 MiB/s的吞吐量。标准存储类中超过1 TiB的数据可以突发到每TiB存储在文件系统中的数据100 MiB/s。EFS使用信用系统来确定文件系统何时可以突发。每个文件系统随时间以基准速率赚取积分,该基准速率由存储在标准存储类中的文件系统的大小确定。无论何时读取或写入数据,文件系统都会使用配额。基准速率为每GiB存储50 KiB/s。
您可以在CloudWatch中监视配额的使用情况,每个EFS文件系统都有一个BurstCreditBalance指标。如果您看到您正在消耗所有配额,并且BurstCreditBalance指标将变为零,则应为文件系统启用调配的吞吐量模式,范围从1 MiB/s到1024 MiB/s。使用调配的吞吐量时,根据您在基准速率之上添加的吞吐量,会产生额外成本。
为了避免信用耗尽,您应该将吞吐量视为一天中所需的平均吞吐量。例如,如果您有一个10 GB的文件系统,则基准速率为500 KiB/s,并且每天可以读/写500 KiB/s*3600秒*24小时=43.2 GiB。
如果函数在初始化期间需要加载的库和所有内容约为2 GiB,并且您仅在函数初始化期间访问EFS文件系统,就像上面的MLInference Lambda函数一样,这意味着您每天可以初始化函数约20次(例如,由于更新或扩展活动)。这不是很多,而且您可能需要为EFS文件系统配置预置的吞吐量。
如果您有10 MiB/s的调配吞吐量,则每天有10 MiB/s*3600秒*24小时=864 GiB可读或写。如果您仅在函数初始化时使用EFS文件系统读取大约2 GB的依赖项,这意味着您每天可以进行400次初始化。对于您的用例来说,这可能就足够了。
在Lambda函数配置中,还可以使用预留并发控制来限制函数使用的最大执行环境数。
如果错误地将BurstCreditBalance设置降为零,并且文件系统相对较小(例如,几个Gib),则有可能您的函数被卡住,在到达超时之前不能足够快地执行。在这种情况下,您应该启用(或增加)EFS文件系统的配置吞吐量,或者通过将保留的并发性设置为零来限制您的功能,以避免所有调用,直到EFS文件系统有足够的配额为止。
了解安全控制将EFS文件系统与AWS Lambda配合使用时,您将拥有多个级别的安全控制。我在这里快速回顾一下,因为在您的无服务器应用程序的总体设计和实现过程中,它们都应该被考虑在内。你可以在这篇文章中找到更多关于使用IAM授权和带有EFS的接入点的信息。
Lambda函数访问私有网络和挂载(只读或读/写)EFS文件系统的IAM权限。
您可以在IAM策略条件中指定Lambda函数可以使用的EFS接入点。
EFS访问点可以限制对文件系统中特定路径的访问。
文件系统安全性(用户ID、组ID、权限)可以限制对Lambda函数装载的每个文件或目录的读、写或可执行访问。
Lambda函数执行环境和EFS挂载点使用行业标准传输层安全(TLS)1.2来加密传输中的数据。您可以配置Amazon EFS来加密静态数据。静态加密的数据在写入时透明加密,在读取时透明解密,因此您不必修改应用程序。加密密钥由AWS密钥管理服务(KMS)管理,无需构建和维护安全的密钥管理基础设施。
现已提供此新功能在所有提供AWS Lambda和Amazon EFS的地区都提供,但中国地区除外,我们正在努力尽快使此集成可用。有关可用性的更多信息,请参阅AWS区域表。要了解更多信息,请参阅文档。
用于Lambda的EFS可以使用控制台、AWS命令行界面(CLI)、AWS SDK和无服务器应用程序模型进行配置。“此功能允许您构建需要处理大文件的数据密集型应用程序。例如,您现在可以在几行代码中解压1.5 GB的文件,或者处理10 GB的JSON文档。您还可以加载库或包,这些库或包的大小超过AWS Lambda的250 MB包部署大小限制,从而实现新的机器学习、数据建模、财务分析和ETL作业场景。
AWS合作伙伴网络解决方案(包括Epsagon、Lumigo、Datadog、HashiCorp Terraform和Pulumi)在发布时支持Amazon EFS for Lambda。
从Lambda函数使用EFS不收取额外费用。您需要为AWS Lambda和Amazon EFS支付标准价格。Lambda执行环境始终连接到AZ中的正确装载目标,而不是跨AZ。您可以通过跨账号私有网络连接到同一AZ内的EFS,但可能会产生数据传输费用。我们不支持EFS和Lambda之间的跨区域或跨AZ连接。