Lambda 托管实例的 .NET 运行时
对于 .NET 运行时,Lambda 托管实例在每个执行环境中使用单个 .NET 进程。使用 .NET 任务处理多个并发请求。
并发配置
Lambda 向每个执行环境发送的最大并发请求数由函数配置中的 PerExecutionEnvironmentMaxConcurrency 设置控制。这是一项可选设置,其默认值因运行时而异。对于 .NET 运行时而言,其默认设置为每个 vCPU 32 个并发请求,或者您也可以自行配置其他数值。Lambda 会根据每个执行环境吸收这些请求的容量,自动调整并发请求的数量,最高到配置的最大值。
为多并发构建函数
在使用 Lambda 托管实例时,您应像在任何其他多并发环境中一样,采用相同的并发安全措施。由于处理程序对象在所有任务中是共享的,因此任何可变状态都必须是线程安全的。这包括集合、数据库连接以及在请求处理过程中被修改的任何静态对象。
Amazon 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 托管实例。使用 Amazon 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 Amazon Lambda (.NET)
适用于 Amazon Lambda (.NET) 的 Powertools和 适用于 OpenTelemetry 的 Amazon Distro - 适用于 .Net 的检测工具