Lambda Managed Instances용 .NET 런타임

Lambda Managed Instances용 .NET 런타임 (.NET runtime for Lambda Managed Instances)

.NET 런타임의 경우 Lambda Managed Instances는 실행 환경당 단일 .NET 프로세스를 사용합니다. 여러 동시 요청은 .NET Task를 사용해 처리됩니다.

출처: AWS Lambda 개발자 안내서

본문

동시성 구성

Lambda가 각 실행 환경으로 보내는 최대 동시 요청 수는 함수 구성의 PerExecutionEnvironmentMaxConcurrency 설정으로 제어됩니다. 이는 선택적 설정이며 기본값은 런타임에 따라 다릅니다. .NET 런타임의 경우 기본값은 vCPU당 32개의 동시 요청이며, 직접 값을 구성할 수도 있습니다. Lambda는 각 실행 환경이 해당 요청을 흡수할 수 있는 용량을 기반으로 구성된 최대값까지 동시 요청 수를 자동으로 조정합니다.

다중 동시성을 위한 함수 구축

Lambda Managed Instances를 사용할 때는 다른 다중 동시 환경에서와 동일한 동시성 안전 관행을 적용해야 합니다. 핸들러 객체는 모든 Task에서 공유되므로 변경 가능한 상태는 스레드 안전(thread-safe)해야 합니다. 여기에는 컬렉션, 데이터베이스 연결, 요청 처리 중 수정되는 정적 객체가 포함됩니다.

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 items = new List();
    private static Dictionary cache = new Dictionary();

    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 items = new ConcurrentBag();
    private static ConcurrentDictionary cache = new ConcurrentDictionary();

    public string FunctionHandler(object input, ILambdaContext context)
    {
        items.Add(context.AwsRequestId);
        cache["key"] = input;

        return "Success";
    }
}

공유 /tmp 디렉터리

/tmp 디렉터리는 실행 환경의 모든 동시 요청 간에 공유됩니다. 같은 파일에 대한 동시 쓰기는 데이터 손상을 일으킬 수 있습니다. 예를 들어 다른 요청이 파일을 덮어쓸 수 있습니다. 이를 해결하려면 공유 파일에 대해 파일 잠금을 구현하거나 요청별로 고유한 파일 이름을 사용해 충돌을 피하세요. 사용하지 않는 파일을 정리해 사용 가능한 공간이 고갈되지 않도록 하세요.

로깅

로그 인터리빙(서로 다른 요청의 로그 항목이 로그에서 섞이는 것)은 다중 동시 시스템에서 정상입니다. Lambda Managed Instances를 사용하는 함수는 고급 로깅 제어로 도입된 구조화된 JSON 로그 형식을 항상 사용합니다. 이 형식은 requestId를 포함하므로 로그 항목을 단일 요청에 연관시킬 수 있습니다. context.Logger 객체를 사용해 로그를 생성하면 각 로그 항목에 requestId가 자동으로 포함됩니다. 자세한 내용은 .NET에서 Lambda 고급 로깅 제어 사용을 참조하세요.

요청 컨텍스트

context.AwsRequestId 속성을 사용해 현재 요청의 요청 ID에 액세스하세요.

context.TraceId 속성을 사용해 X-Ray 추적 ID에 액세스하세요. 이는 현재 요청의 추적 ID에 대한 동시성 안전한 액세스를 제공합니다. Lambda는 Lambda Managed Instances에서 _X_AMZN_TRACE_ID 환경 변수를 지원하지 않습니다. AWS SDK를 사용하면 X-Ray 추적 ID가 자동으로 전파됩니다.

ILambdaContext.RemainingTime을 사용해 타임아웃을 감지하세요. 자세한 내용은 오류 처리 및 복구를 참조하세요.

예시: 타임아웃 처리

각 작업 단위 전에 남은 시간을 확인하고 타임아웃이 발생하기 전에 처리를 중지하세요. 다음 작업 청크의 예상 소요 시간에 따라 버퍼를 구성하세요.

private static readonly TimeSpan Buffer = TimeSpan.FromMilliseconds(2000);

public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
{
    var items = JsonSerializer.Deserialize>(request.Body);
    foreach (var item in items)
    {
        if (context.RemainingTime < Buffer)
        {
            return new APIGatewayProxyResponse()
            {
                StatusCode = 503,
                Body = "Not enough time to complete"
            };
        }
        // Process the item
    }
    return new APIGatewayProxyResponse() { StatusCode = 200 };
}

예시: 다운스트림 호출에 데드라인 전파

다운스트림 서비스에 호출할 때 남은 시간을 타임아웃으로 전파해 호출보다 오래 지속되는 네트워크 호출에 매달리지 않게 하세요. 호출마다 새 클라이언트를 만드는 대신 공유 클라이언트와 함께 CancellationToken을 사용하세요:

using Amazon.S3;

private static readonly IAmazonS3 s3 = new AmazonS3Client();

public async Task FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
{
    var timeout = context.RemainingTime - TimeSpan.FromMilliseconds(500);
    if (timeout <= TimeSpan.Zero)
    {
        return;
    }

    using var cts = new CancellationTokenSource(timeout);
    await s3.GetObjectAsync("bucket", "key", cts.Token);
}

실행 환경 수명주기

함수 초기화는 실행 환경당 한 번 발생합니다. 초기화 중에 만들어진 객체는 요청 간에 공유됩니다.

확장 기능이 있는 Lambda 함수의 경우 실행 환경은 종료 중에 SIGTERM 신호를 보냅니다. 이 신호는 확장 기능이 버퍼 플러시 같은 정리 작업을 트리거하는 데 사용됩니다. SIGTERM 이벤트를 구독해 데이터베이스 연결 닫기 같은 함수 정리 작업을 트리거할 수 있습니다. 실행 환경 수명주기에 대해 자세히 알아보려면 Lambda 실행 환경 수명주기 이해를 참조하세요.

종속성 버전

Lambda Managed Instances에는 다음 최소 패키지 버전이 필요합니다:

  • 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)

Powertools for AWS Lambda (.NET)와 AWS Distro for OpenTelemetry - Instrumentation for DotNet는 현재 Lambda Managed Instances를 지원하지 않습니다.

다음 단계

  • Lambda Managed Instances용 Java 런타임 검토
  • Lambda Managed Instances용 Node.js 런타임 검토
  • Lambda Managed Instances용 Python 런타임 검토
  • Lambda Managed Instances 확장에 대해 알아보기

더 알아보기 (Learn more)

  • Lambda Managed Instances 개요
  • .NET 다중 동시성 안전
  • Lambda 고급 로깅 제어