Lambda 托管实例的 .NET 运行时 - AWS Lambda

Lambda 托管实例的 .NET 运行时

对于 .NET 运行时,Lambda 托管实例在每个执行环境中使用单个 .NET 进程。使用 .NET 任务处理多个并发请求。

并发配置

Lambda 向每个执行环境发送的最大并发请求数由函数配置中的 PerExecutionEnvironmentMaxConcurrency 设置控制。这是一项可选设置,其默认值因运行时而异。对于 .NET 运行时而言,其默认设置为每个 vCPU 32 个并发请求,或者您也可以自行配置其他数值。Lambda 会根据每个执行环境吸收这些请求的容量,自动调整并发请求的数量,最高到配置的最大值。

为多并发构建函数

在使用 Lambda 托管实例时,您应像在任何其他多并发环境中一样,采用相同的并发安全措施。由于处理程序对象在所有任务中是共享的,因此任何可变状态都必须是线程安全的。这包括集合、数据库连接以及在请求处理过程中被修改的任何静态对象。

AWS SDK 客户端是线程安全的,且不需要特殊处理。

示例:数据库连接池

以下代码使用静态的数据库连接对象,该对象在并发请求之间共享。SqlConnection 对象不是线程安全的。

public class DBQueryHandler { // Single connection shared across threads - NOT SAFE private SqlConnection connection; public DBQueryHandler() { connection = new SqlConnection("your-connection-string-here"); connection.Open(); } public string Handle(object input, ILambdaContext context) { using var cmd = connection.CreateCommand(); cmd.CommandText = "SELECT ..."; // your query using var reader = cmd.ExecuteReader(); ... } }

要解决这个问题,请为每个请求使用从连接池中获取的单独连接。打开连接对象时,Microsoft.Data.SqlClient 之类的 ADO.NET 提供程序会自动支持连接池。

public class DBQueryHandler { public DBQueryHandler() { } public string Handle(object input, ILambdaContext context) { using var connection = new SqlConnection("your-connection-string-here"); connection.Open(); using var cmd = connection.CreateCommand(); cmd.CommandText = "SELECT ..."; // your query using var reader = cmd.ExecuteReader(); ... } }

示例:集合

标准的 .NET 集合不是线程安全的:

public class Handler { private static List<string> items = new List<string>(); private static Dictionary<string, object> cache = new Dictionary<string, object>(); public string FunctionHandler(object input, ILambdaContext context) { items.Add(context.AwsRequestId); cache["key"] = input; return "Success"; } }

使用 System.Collections.Concurrent 命名空间中的集合以确保并发安全:

public class Handler { private static ConcurrentBag<string> items = new ConcurrentBag<string>(); private static ConcurrentDictionary<string, object> cache = new ConcurrentDictionary<string, object>(); public string FunctionHandler(object input, ILambdaContext context) { items.Add(context.AwsRequestId); cache["key"] = input; return "Success"; } }

共享的 /tmp 目录

/tmp 目录在执行环境中为所有并发请求共享使用。对同一个文件进行并发写入可能会导致数据损坏,例如,如果另一个请求覆盖了该文件。要解决这个问题,要么为共享文件实施文件锁定机制,要么根据每次请求使用唯一的文件名以避免冲突。记得清理不再需要的文件,以免耗尽可用空间。

日志记录

在多并发系统中,日志交错(即来自不同请求的日志条目在日志中交错排列)是常见现象。使用 Lambda 托管实例的函数始终使用高级日志记录控制引入的结构化 JSON 日志格式。此格式包括 requestId,使得日志条目能够与单个请求相关联。当您使用 context.Logger 对象生成日志时,requestId 会自动包含在每个日志条目中。有关更多信息,请参阅将 Lambda 高级日志记录控制与 .NET 结合使用

请求上下文

使用 context.AwsRequestId 属性访问当前请求的请求 ID。

使用 context.TraceId 属性访问 X-Ray 跟踪 ID。这为当前请求的跟踪 ID 提供了并发安全的访问权限。Lambda 不支持将 _X_AMZN_TRACE_ID 环境变量用于 Lambda 托管实例。使用 AWS SDK 时,X-Ray 跟踪 ID 会自动传播。

初始化和关闭

函数初始化会在每个执行环境中发生一次。初始化期间创建的对象在请求之间共享。

对于带有扩展程序的 Lambda 函数,其执行环境在关闭时会发出一个 SIGTERM 信号。扩展程序使用此信号来触发清理任务,例如刷新缓冲区。您可以订阅 SIGTERM 事件来触发函数清理任务,例如关闭数据库连接。要了解有关执行环境生命周期的更多信息,请参阅了解 Lambda 执行环境生命周期

依赖项版本

Lambda 托管实例需要以下最低程序包版本:

  • Amazon.Lambda.Core:版本 2.7.1 或更高版本

  • Amazon.Lambda.RuntimeSupport:版本 1.14.1 或更高版本

  • OpenTelemetry.Instrumentation.AWSLambda:版本 1.14.0 或更高版本

  • AWSXRayRecorder.Core:版本 2.16.0 或更高版本

  • AWSSDK.Core:版本 4.0.0.32 或更高版本

Powertools for AWS Lambda (.NET)

适用于 AWS Lambda (.NET) 的 Powertools适用于 OpenTelemetry 的 AWS Distro - 适用于 .Net 的检测工具目前不支持 Lambda 托管实例。

后续步骤