

# Lambda 托管实例的 .NET 运行时
<a name="lambda-managed-instances-dotnet-runtime"></a>

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

## 并发配置
<a name="lambda-managed-instances-dotnet-concurrency-config"></a>

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

## 为多并发构建函数
<a name="lambda-managed-instances-dotnet-building"></a>

在使用 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 目录
<a name="lambda-managed-instances-dotnet-shared-tmp"></a>

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

## 日志记录
<a name="lambda-managed-instances-dotnet-logging"></a>

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

## 请求上下文
<a name="lambda-managed-instances-dotnet-request-context"></a>

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

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

使用 `ILambdaContext.RemainingTime` 检测超时。请参阅[错误处理和恢复](lambda-managed-instances-execution-environment.md#lambda-managed-instances-error-handling)了解更多信息。

## 初始化和关闭
<a name="lambda-managed-instances-dotnet-init-shutdown"></a>

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

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

## 依赖项版本
<a name="lambda-managed-instances-dotnet-dependencies"></a>

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)
<a name="lambda-managed-instances-dotnet-powertools"></a>

[适用于 AWS Lambda (.NET) 的 Powertools](https://docs.aws.amazon.com/powertools/dotnet/)和 [适用于 OpenTelemetry 的 AWS Distro - 适用于 .Net 的检测工具](https://github.com/aws-observability/aws-otel-dotnet-instrumentation)目前不支持 Lambda 托管实例。

## 后续步骤
<a name="lambda-managed-instances-dotnet-next-steps"></a>
+ 查看 [Lambda 托管实例的 Java 运行时](lambda-managed-instances-java-runtime.md)
+ 查看 [Lambda 托管实例的 Node.js 运行时](lambda-managed-instances-nodejs-runtime.md)
+ 查看 [Lambda 托管实例的 Python 运行时](lambda-managed-instances-python-runtime.md)
+ 了解有关[扩展 Lambda 托管实例](lambda-managed-instances-scaling.md)的信息