亚马逊AWS官方博客

适用于 AWS Lambda 的 .NET 8 运行时简介

本文由 Beau Gosse(Senior Software Engineer)和 Paras Jain(Senior Technical Account Manager)联合撰写。

AWS Lambda 现在支持 .NET 8 作为托管运行时和容器基础映像。在此版本中,Lambda 开发人员可以受益于 .NET 8 提供的多种功能,包括 API 增强、改进的原生提前(原生 AOT,Ahead of Time)支持,以及更好的性能。.NET 8 支持 C# 12F# 8PowerShell 7.4。您可以使用 AWS Toolkit for Visual Studio适用于 .NET CLI 的 AWS 扩展AWS Serverless Application Model(AWS SAM)AWS CDK 以及其它基础设施即代码工具,在 .NET 8 中开发 Lambda 函数。

在控制台中创建 .NET 8 函数

在控制台中创建 .NET 8 函数

新增功能

升级后的操作系统

.NET 8 运行时建立在 Amazon Linux 2023(AL2023)最小容器镜像之上。与早期基于 Amazon Linux 2023(AL2)的运行时以及 glibc 2.34 和 OpenSSL 3 等常见库的更新版本相比,这可以实现更少的部署空间占用。

新镜像还使用 microdnf 作为包管理器,通过符号链接用作 dnf。这取代了早期基于 AL2 的镜像中使用的 yum 包管理器。如果您将 Lambda 函数部署为容器镜像,则在升级到 .NET 8 基础映像时,您必须更新 Dockerfile 以使用 dnf 而不是 yum。有关更多信息,请参阅 Introducing the Amazon Linux 2023 runtime for AWS Lambda(适用于 AWS Lambda 的 Amazon Linux 2023 运行时简介)。

性能

.NET 8 中提供了多种语言的性能改进。初始化时间会影响性能,因为 Lambda 需要创建新的执行环境来自动扩展函数。要想优化基于 Lambda 的 .NET 工作负载的性能,您可以使用多种方法,包括在 System.Text.Json 中使用源生成器或使用原生 AOT

在蓝图和模板中,Lambda 将默认内存大小从 256 MB 增加到 512 MB,以提高 .NET 8 的性能。在 .NET 8 应用程序上执行您自己的函数和性能测试。您可以使用 AWS Compute OptimizerAWS Lambda Power Tuning 进行性能分析。

在启动时,新 Lambda 运行时收到的使用量,会低于现有已投入使用的运行时的使用量。由于内部 Lambda 子系统中的缓存驻留减少,这可能会导致更长的冷启动时间。随着使用量的增加,冷启动时间通常会在启动后的几周内得到改善。因此,AWS 建议在性能稳定之前,不要总结与其它 Lambda 运行时的性能比较。

原生 AOT

Lambda 于 2022 年 11 月推出了 .NET 原生 AOT 支持基准测试表明,通过消除 JIT 编译,冷启动时间最多可缩短 86%。使用托管 dotnet8 运行时部署 .NET 8 原生 AOT 函数,而不是使用仅限 OS 的 provided.al2023 运行时,可以向函数提供对 .NET 系统库的访问。例如,默认情况下,provided.al2023 运行时中不包括在全球广为使用的 libicu,但 dotnet8 运行时包括。

虽然原生 AOT 并非适用于所有 .NET 函数,但 .NET 8 提供了改进的修剪支持。这让您可以更轻松地运行 ASP.NET API。改进的修剪支持有助于消除构建时的修剪警告,这些警告会突出显示可能的运行时错误。这样您可以放心,您的原生 AOT 函数具有与 JIT 编译的函数相似的行为。修剪支持已添加到 Lambda 运行时库AWS .NET SDK.NET Lambda Annotations.NET 8 本身中。

将 .NET 8 与 Lambda 结合使用

要将 .NET 8 与 Lambda 一起使用,您必须更新工具。

  1. 安装或更新 .NET 8 SDK
  2. 如果您使用的是 AWS SAM,请安装更新到最新版本。
  3. 如果您使用的是 Visual Studio,请安装或更新 AWS Toolkit for Visual Studio
  4. 如果您使用 .NET Lambda Global Tools 扩展(Amazon.Lambda.Tools),请安装 CLI 扩展和模板。您可以使用 dotnet tool update -g Amazon.Lambda.Tools 更新现有工具,使用 dotnet new install Amazon.Lambda.Templates 更新现有模板。

您还可以将 .NET 8 与适用于 AWS Lambda(.NET)的 Powertools 一起使用,这是一个开发人员工具包,用于实施无服务器最佳实践,例如可观测性、批处理、检索参数、幂等性和特征标志。

构建新 .NET 8 函数

使用 AWS SAM

  1. 运行 sam init
  2. 选择 1- AWS Quick Start Templates(1 – AWS 快速起动模板)。
  3. 选择一个可用的模板,例如 Hello World Example
  4. 在显示使用最流行的运行时和包类型?时,选择 N
  5. 选择 dotnet8 作为运行时。dotnet8 Hello World Example 同样包括原生 AOT 模板选项。
  6. 按照其余提示创建 .NET 8 函数。

AWS SAM .NET 8 初始化选项

AWS SAM .NET 8 初始化选项

您可以修改生成的函数代码,并使用 sam deploy --guided 来部署函数。

使用 AWS Toolkit for Visual Studio

  1. 创建新项目向导,筛选模板以使用 Lambda无服务器项目类型,然后选择模板。要部署单个函数,请使用 Lambda。要使用 AWS CloudFormation 部署函数集合,请使用无服务器
  2. 继续执行步骤以完成项目的创建。
  3. 您可以修改生成的函数代码。
  4. 要进行部署,请在解决方案资源管理器中右键单击项目,然后选择发布到 AWS Lambda

将 AWS 扩展用于 .NET CLI

  1. 运行 dotnet new list --tag Lambda 以获取可用的 Lambda 模板列表。
  2. 选择模板并运行 dotnet new <模板名称>。要使用原生 AOT 构建函数,在使用 .NET Lambda Annotations Framework 时,请使用 dotnet new lambda.NativeAOTdotnet new serverless.NativeAOT
  3. src 下包含 .csproj 文件的目录中,找到生成的 Lambda 函数。您可以修改生成的函数代码。
  4. 要进行部署,请运行 dotnet lambda deploy-function 并按照提示操作。
  5. 您可以使用 dotnet lambda invoke-function 在云服务中测试函数,或者使用 Lambda 控制台中的测试功能

您可以使用容器镜像构建和部署.NET Lambda 函数。请按照文档中的说明操作。

从 .NET 6 迁移到 .NET 8 而不使用原生 AOT

使用 AWS SAM

  1. 打开 template.yaml 文件。
  2. Runtime 更新为 dotnet8
  3. 打开终端窗口并使用 sam build 重新构建代码。
  4. 运行 sam deploy 来部署更改。

使用 AWS Toolkit for Visual Studio

  1. 打开 .csproj 项目文件并将 TargetFramework 更新为 net8.0。将 Lambda 函数的 NuGet 包更新到最新版本,以引入 .NET 8 更新。
  2. 验证您使用的构建命令是否针对 .NET 8 运行时。
  3. 根据您使用的构建/部署工具,可能需要完成其它步骤。您可能只需更新函数运行时。

AWS Toolkit for Visual Studio 中的 .NET 函数

将 AWS 扩展用于 .NET CLI 或 AWS Toolkit for Visual Studio

  1. 打开 aws-lambda-tools-defaults.json 文件(如果存在)。
    1. 将 framework 字段设置为 net8.0。如果未指定,则从项目文件中推断出该值。
    2. function-runtime 字段设置为 dotnet8
  2. 打开 serverless.template 文件(如果存在)。对于任何 AWS::Lambda::FunctionAWS::Servereless::Function 资源,请将 Runtime 属性设置为 dotnet8
  3. 打开 .csproj 项目文件(如果存在)并将 TargetFramework 更新为 net8.0。将 Lambda 函数的 NuGet 包更新到最新版本,以引入 .NET 8 更新。

从 .NET 6 迁移到 .NET 8 原生 AOT

以下示例将 .NET 6 类库函数迁移到 .NET 8 原生 AOT 可执行函数。这会使用可选的 Lambda Annotations Framework,该框架提供了惯用的 .NET 编码模式。

更新您的项目文件

  1. 打开项目文件。
  2. TargetFramework 设置为 net8.0
  3. OutputType 设置为 exe
  4. 删除 PublishReadyToRun(如果存在)。
  5. 添加 PublishAot 并将其设置为 true
  6. 添加或更新 NuGet 包引用,使其为 Amazon.Lambda.AnnotationsAmazon.Lambda.RuntimeSupport。您可以使用 IDE 中的 NuGet UI 进行更新,手动进行更新,也可以从项目目录运行 dotnet add package Amazon.Lambda.RuntimeSupport 和 dotnet add package Amazon.Lambda.Annotations 进行更新。

您的项目文件应类似于以下所示:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AWSProjectType>Lambda</AWSProjectType>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
    <!-- 在发布期间生成原生 aot 镜像以缩短冷启动时间。-->
    <PublishAot>true</PublishAot>
	  <!-- StripSymbols 告知编译器,如果我们使用的是 Linux,则在最终可执行文件中去除调试符号,并将其放入自己的文件中。
		这将大幅减小最终可执行文件的大小。-->
	  <StripSymbols>true</StripSymbols>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.Core" Version="2.2.0" />
    <PackageReference Include="Amazon.Lambda.RuntimeSupport" Version="1.10.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.4.0" />
  </ItemGroup>
</Project>

更新函数代码

  1. 使用 Amazon.Lambda.Annotations 引用注释库;
  2. 添加 [assembly:LambdaGlobalProperties(GenerateMain = true)] 以允许注释框架创建主方法。这是必需的,因为项目现在是可执行文件而不是库。
  3. 添加以下部分类,并为您要序列化的任何类型(包括函数输入和输出)添加 JsonSerializable 属性。此部分类在构建时用于生成无反射代码,专用于序列化所列的类型。以下是示例:
/// <summary>
/// 此类用于将 FunctionHandler 方法的输入事件和返回类型注册到 System.Text.Json 源生成器。
/// 对于用作输入和返回类型的每种类型,必须要有 JsonSerializable 属性,否则会出现运行时错误 
/// 在 JSON 序列化程序中找不到未知类型的序列化信息。
/// </summary>
[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyRequest))]
[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyResponse))]
public partial class MyCustomJsonSerializerContext : JsonSerializerContext
{
    // 使用派生自 JsonSerializerContext 的此部分类,我们可以在编译时生成无反射的 JSON 序列化程序代码
    // 这可以反序列化我们的类和属性。但是,我们必须为这个类赋予属性,以告诉它要为哪些类型生成序列化代码
    // 请参阅 https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation
}
  1. 在使用语句之后,添加以下内容以指定要使用的序列化程序。[assembly: LambdaSerializer(typeof(SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>))]

如果您没有使用上一步中的部分类,请将您的上下文交换为 LambdaFunctionJsonSerializerContext

更新函数配置

使用 aws-lambda-tools-defaults.json 时。

  1. function-runtime 设置为 dotnet8
  2. function-architecture 设置为与您的构建计算机相符:x86_64arm64
  3. 设置(或更新)environment-variables 以包括 ANNOTATIONS_HANDLER=<YourFunctionHandler>。将 <YourFunctionHandler> 替换为函数处理程序的方法名称,这样注释框架就知道从生成的方法调用什么方法。
  4. function-handler 设置为您的 bin 目录中的可执行程序集。默认情况下,这是您的项目名称,这会告知 .NET Lambda 引导脚本运行您的原生库,而不是启动 .NET 运行时。如果您的项目文件有 AssemblyName,则为函数处理程序使用该值。
{
  "function-architecture": "x86_64",
  "function-runtime": "dotnet8",
  "function-handler": "<your-assembly-name>",
  "environment-variables",
  "ANNOTATIONS_HANDLER=<your-function-handler>",
}

部署和测试

  1. 部署您的函数。如果您使用 Amazon.Lambda.Tools,则运行 dotnet lambda deploy-function。在构建和重构期间,检查修剪警告以消除警告。
  2. 测试您的函数,确保对 AL2023 的原生调用正常运行。默认情况下,在开发计算机上运行本地单元测试不会原生运行,仍将使用 JIT 编译器。使用 JIT 编译器运行时,您将无法捕获原生 AOT 特定的运行时错误。

结论

Lambda 推出了新的 .NET 8 托管运行时。本文重点介绍 .NET 8 中的新功能。您可以创建新的 Lambda 函数,也可以将现有函数迁移到 .NET 8 或 .NET 8 原生 AOT。

有关更多信息,请参阅 AWS Lambda for .NET 存储库、文档Serverless Land 上的 .NET

有关更多无服务器学习资源,请访问 Serverless Land