AWS Lambda에서의 .NET 워크로드

모듈 3

모듈 3: AWS Lambda의 .NET 워크로드

 학습 모듈

여기에 제시된 예시를 따라할 수도 있지만 반드시 그럴 필요는 없습니다.

AWS Lambda는 x86_64 및 Arm64 (Graviton2) 아키텍처 모두에서 여러 .NET 버전을 지원하므로 원하는 아키텍처를 자유롭게 선택할 수 있습니다. 코드 및 배포 프로세스는 변경되지 않습니다.

Lambda는 서버리스 서비스이므로 사용한 만큼만 비용을 지불하면 됩니다. Lambda 함수를 하루에 몇 번 실행해야 하는 경우, 그것만 지불하면 됩니다. 필요에 따라 규모를 조정할 수 있고 동시에 1,000개의 인스턴스를 시작할 수도 있습니다.

 소요 시간

60분 

요금

앞서 말씀드린 것처럼 사용한 만큼만 비용을 지불하면 됩니다. 지불하는 금액은 Lambda 함수가 실행된 시간(가장 가까운 밀리초로 반올림)과 함수에 할당한 메모리 양을 기준으로 계산됩니다.

단 요금 계산에 호출 중에 사용된 양이 아니라 할당된 메모리 양이 사용된다는 점에 유의하시기 바랍니다. 따라서 함수를 테스트하여 호출 중에 사용하는 최대 메모리 양을 평가하는 것이 좋습니다. 할당된 메모리를 필요한 최소한으로 유지하면 Lambda 함수 사용 비용을 줄일 수 있습니다. 자세한 내용은 이 AWS Lambda 요금 페이지를 참조하세요.

참고로 Lambda 함수가 S3, Kinesis 등의 다른 서비스를 사용하는 경우, 해당 서비스에도 요금이 부과될 수 있습니다.

.NET의 지원되는 버전

Lambda 플랫폼에서 .NET 바이너리를 실행하는 방법은 다양합니다. 가장 일반적이고 가장 먼저 고려해야 할 사항은 AWS에서 제공하는 관리형 런타임을 사용하는 것입니다. 가장 간단하고 편리한 시작 방법이며 최고의 성능을 제공합니다. 관리형 런타임을 사용하고 싶지 않거나 사용할 수 없는 경우, 사용자 지정 런타임 또는 컨테이너 이미지라는 두 가지 다른 방법을 선택할 수 있습니다. 두 옵션 모두 장점과 단점이 있으며 아래에 자세한 설명이 나와 있습니다.

관리형 런타임

AWS Lambda 서비스는 코드를 실행할 수 있는 다양한 인기 런타임을 제공합니다. .NET 런타임의 경우, AWS는 런타임을 최신 상태로 유지하고 필요에 따라 Microsoft에서 제공하는 최신 버전으로 패치를 적용합니다. 개발자는 친숙한 .csproj 파일에서 사용할 버전을 지정하는 것 외에는 코드에서 사용할 런타임을 관리하는 작업은 아무것도 할 필요가 없습니다.

현재 AWS는 장기 지원(LTS) 버전의 .NET 런타임, 즉 이 글을 쓰는 시점에서 .NET 3.1 및 .NET 6에 대해서만 관리형 런타임을 제공합니다. .NET 관리형 런타임은 x86_64 및 arm64 아키텍처 모두에서 사용할 수 있으며 Amazon Linux 2에서 실행됩니다. AWS에서 제공하는 버전이 아닌 .NET 버전을 사용하려는 경우, 자체 사용자 지정 런타임을 구축하거나 필요에 맞는 컨테이너 이미지를 만들 수 있습니다.

.NET이 아닌 Lambda 서비스가 다른 언어 (Node.js, Python, Ruby, Java 및 Go)에 대한 관리형 런타임도 제공한다는 사실을 알아두는 것이 좋습니다. 관리되는 런타임 목록과 지원되는 언어 버전에 대한 자세한 내용은 이 페이지에서 사용 가능한 런타임을 참조하세요.

사용자 지정 런타임

사용자 지정 런타임은 직접 빌드하고 번들로 묶는 런타임입니다. 이렇게 하는 데는 몇 가지 이유가 있습니다. 가장 일반적인 이유는 Lambda 서비스에서 관리형 런타임으로 제공하지 않는 .NET 버전을 사용하려는 경우입니다. 그밖에는 런타임 부 버전과 패치 버전을 정밀하게 제어하려는 경우가 있습니다.

사용자 지정 런타임을 만드는 작업은 간단합니다. 다음을 빌드 명령어에 전달하기만 하면 됩니다.

--self-contained true

이 작업은 dotnet 빌드로 직접 수행할 수 있습니다. 다음 파라미터를 사용하여 aws-lambda-tools-defaults.json 파일을 통해서도 이 작업을 수행할 수 있습니다.

"msbuild-parameters": "--self-contained true"

.NET Lambda 함수를 번들링할 때 사용하는 간단한 컴파일러 플래그로 충분합니다. 이제 배포할 패키지에는 코드와 선택한 .NET 런타임의 필수 파일이 포함됩니다.

필요에 따라 런타임을 패치하고 업데이트하는 것은 사용자의 몫입니다. 런타임을 업데이트하려면 함수 코드와 런타임이 함께 패키징되므로 함수를 재배포해야 합니다.

배포되는 패키지에는 필요한 런타임 파일이 모두 포함되어 있기 때문에 관리되는 런타임에 비해 훨씬 더 큽니다. 이는 콜드 스타트 시간에 부정적인 영향을 미칩니다. (자세한 내용은 나중에 설명드리겠습니다.) 이 크기를 줄이려면 .NET 컴파일 기능인 TrimmingReadyToRun을 사용하는 것이 좋습니다. 하지만 그렇게 하기 전에 기능에 대한 설명서를 읽어 보시기 바랍니다.

Linux에서 실행되는 모든 버전의.NET을 사용하여 사용자 지정 런타임을 만들 수 있습니다. 일반적인 사용 사례는 '현재' 버전이나 미리 보기 버전으로 .NET의 함수를 배포하는 것입니다.

사용자 지정 런타임을 사용하면 커뮤니티에서 제공하는 매우 다양한 언어를 사용할 수 있습니다. 또는, Erlang 및 COBOL과 같은 언어를 실행할 때처럼 자체적인 사용자 지정 런타임을 빌드할 수도 있습니다.

컨테이너 이미지

AWS Lambda 서비스는 관리형 런타임 및 사용자 지정 런타임과 함께 컨테이너 이미지에 코드를 패키징하고, 이 이미지를 Lambda 서비스에 배포할 수 있는 기능도 제공합니다. 이 옵션은 코드를 빌드하고 컨테이너에 배포하는 데 시간을 투자한 팀이나, 코드가 실행되는 운영 체제 및 환경을 더욱 잘 제어해야 하는 팀에 적합합니다. 최대 10GB 크기의 이미지가 지원됩니다.

AWS는 .NET 및 .NET Core에 대한 다양한 기본 이미지를 제공합니다. https://gallery.ecr.aws/lambda/dotnet을 통해 매우 빠르게 시작할 수 있습니다.

함수에 맞게 사용자 지정 이미지를 만드는 옵션도 있습니다. 이 옵션은 고급 사용 사례이며 필요에 맞게 Dockerfile을 편집해야 합니다. 이 강좌에서 이러한 접근 방식을 다루지는 않겠지만, 이 방법을 사용하고 싶다면 이 리포지토리의 Dockerfiles(https://github.com/aws/aws-lambda-dotnet/tree/master/LambdaRuntimeDockerfiles/Images)를 살펴보시기 바랍니다.

컨테이너의 경우, 업로드 크기 때문에 Lambda 함수를 업데이트하는 속도가 가장 느리다는 점에 유의하세요. 컨테이너는 세 가지 옵션 중에서 콜드 스타트가 가장 좋지 않습니다. 그 내용에 대해서는 모듈의 후반부에서 자세히 설명하겠습니다.

적절한 런타임 선택하기

최상의 시작 성능과 간편한 배포와 시작을 원하고 LTS 버전의 .NET을 계속 사용하고 싶다면, 관리형.NET 런타임을 선택하세요.

컨테이너 이미지는 다양한 .NET 버전에 맞춰 AWS가 생성한 이미지를 사용할 수 있는 훌륭한 옵션입니다. 또는, 자체적인 컨테이너 이미지를 선택하고 코드가 실행되는 운영 체제와 환경을 조정할 수 있습니다. 컨테이너 이미지는 이미 컨테이너를 광범위하게 사용하고 있는 조직에도 적합합니다.

.NET 버전과 해당 런타임 라이브러리에 대한 매우 구체적인 요구 사항이 있고 이러한 요구 사항을 직접 제어하려는 경우, 사용자 지정 런타임을 사용하는 것이 좋습니다. 하지만 런타임을 유지관리하고 패치하는 것은 사용자의 몫입니다. Microsoft에서 보안 업데이트를 릴리스하는 경우, 보안 업데이트를 숙지하고 사용자 지정 런타임을 적절하게 업데이트해야 합니다. 사용자 지정 런타임은 성능 관점에서 세 가지 중 시작 속도가 가장 느립니다.

Lambda 함수가 시작되면 관리형 런타임, 컨테이너 이미지 및 사용자 지정 런타임의 성능이 매우 비슷해질 것입니다.

AWS SDK for .NET

AWS 서비스를 사용하는 .NET 애플리케이션을 개발하고 있다면 AWS SDK for .NET을 사용해 본 적이 있을 것입니다. SDK를 사용하면 .NET 개발자가 일관되고 친숙한 방식으로 AWS 서비스를 쉽게 호출할 수 있습니다. SDK는 서비스가 출시되거나 업데이트될 때 최신 상태로 유지됩니다. SDK는 NuGet에서 다운로드할 수 있습니다.

AWS와 관련된 다른 여러 가지와 마찬가지로 SDK도 작은 패키지로 나뉘어 각각 단일 서비스를 처리합니다.

예를 들어 .NET 애플리케이션에서 S3 버킷에 액세스하려는 경우, AWSSDK.S3 NuGet 패키지를 사용할 수 있습니다. 또는 .NET 애플리케이션에서 DynamoDB에 액세스하려는 경우, AWSSDK.DynamoDBv2 NuGet 패키지를 사용할 수 있습니다.

하지만 필요한 NuGet 패키지만 추가하면 됩니다. SDK를 작은 패키지로 나누면 자체적인 배포 패키지를 더 작게 유지할 수 있습니다.

Lambda 함수 핸들러가 다른 AWS 서비스로부터 이벤트를 수신해야 하는 경우, 특정 이벤트 관련 NuGet 패키지를 찾아보세요. 여기에는 이벤트를 처리하기 위한 관련 유형이 포함됩니다. 패키지는 AWSSDK.Lambda.[SERVICE]Events의 이름 지정 패턴을 따릅니다.

예를 들어 Lambda 함수가 다음에 의해 트리거되는 경우에는 다음과 같이 처리합니다.

S3 이벤트를 수신하는 경우, AWSSDK.Lambda.S3Events 패키지 사용

Kinesis 이벤트를 수신하는 경우, AWSSDK.Lambda.KinesisEvents 패키지 사용

SNS 알림을 수신하는 경우, AWSSDK.Lambda.SNSEvents 패키지 사용

SQS 메시지를 수신하는 경우, AWSSDK.Lambda.SQSEvents 패키지 사용

SDK를 사용하여 AWS 서비스와 상호 작용하는 방법은 매우 쉽습니다. 프로젝트에 NuGet 패키지에 대한 참조를 추가한 다음, 사용할 수 있는 다른.NET 라이브러리와 마찬가지로 서비스를 호출합니다.

Lambda 함수의 SDK를 사용하더라도 사용 방식에는 영향을 미치지 않습니다.

반드시 프로젝트에 AWS SDK NuGet 패키지를 추가할 필요는 없다는 점을 기억하세요. 예를 들어 Lambda 함수가 AWS RDS SQL Server를 호출하는 경우, 간단히 Entity Framework를 사용하여 데이터베이스에 액세스할 수 있습니다. 추가적인 AWS 전용 라이브러리는 필요하지 않습니다. 하지만 Secrets Manager에서 데이터베이스의 사용자 이름/암호를 검색하려면 AWSSDK.SecretsManager NuGet 패키지를 추가해야 합니다.

권한에 대한 참고 사항

일반적으로 태스크를 수행하는 데 필요한 가장 낮은 수준의 권한을 사용해야 합니다. 이 과정을 통해 여러분은 용기를 얻고 이를 수행하는 방법을 알게 될 것입니다.

하지만 이 과정을 간단하게 학습할 수 있도록 AdministratorAccess 정책이 연결된 AWS 사용자를 사용하는 것이 좋습니다. 이 정책을 통해 Lambda 함수를 배포할 때 필요한 역할을 생성할 수 있습니다. 수업을 수강하지 않을 때는 AWS 사용자에게서 이 정책을 제거해야 합니다.

Hello World 스타일 .NET Lambda 함수

이전 모듈에서 살펴보았듯이 .NET Lambda 함수를 생성, 배포 및 호출하는 방법은 매우 쉽습니다. 이 섹션에서는 동일한 작업을 수행하지만 더 천천히 진행하면서 각 단계에서 어떤 일이 일어나고 있는지 설명하겠습니다. 생성된 코드 및 구성 파일에 대해 설명합니다.

함수 생성

이 작업을 수행하려면 필요한 도구를 설치해야 합니다. 이 작업을 수행하는 방법에 대한 자세한 내용은 모듈 3을 참조하세요.

지금 확인하고 싶지 않은 분을 위해 간단히 설명을 드리겠습니다.

.NET Lambda 함수 템플릿을 설치합니다.

dotnet new -i Amazon.Lambda.Templates

Lambda 함수를 배포하고 관리하기 위한 .NET 도구를 설치합니다.

dotnet tool install -g Amazon.Lambda.Tools

이제 템플릿이 설치되었으므로 새 함수를 만들 수 있습니다.

명령줄에서 다음을 실행합니다.

dotnet new lambda.EmptyFunction -n HelloEmptyFunction

HelloEmptyFunction이라고 하는 새 디렉터리가 생성됩니다. 그 안에는 src와 test 디렉터리가 두 개 더 있습니다. 이름에서 알 수 있듯이, src 디렉터리에는 함수 코드가 포함되고 테스트 디렉터리에는 함수의 유닛 테스트가 포함됩니다. 이러한 디렉터리를 살펴보면 각각 다른 디렉터리가 포함되어 있음을 알 수 있을 것입니다.. 하위 디렉터리 내에는 함수의 코드 파일과 유닛 테스트 파일이 있습니다.

HelloEmptyFunction
    ├───src
    │   └───HelloEmptyFunction
    │           aws-lambda-tools-defaults.json // The default configuration file
    │           Function.cs // The code for the function
    │           HelloEmptyFunction.csproj // Standard C# project file
    │           Readme.md // A readme file
    │
    └───test
        └───HelloEmptyFunction.Tests
                FunctionTest.cs // The unit tests for the function
                HelloEmptyFunction.Tests.csproj // Standard C# project file

먼저 Function.cs 파일을 살펴보겠습니다.

using Amazon.Lambda.Core;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace HelloEmptyFunction;

public class Function
{
    
    /// <summary>
    /// A simple function that takes a string and does a ToUpper
    /// </summary>
    /// <param name="input"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public string FunctionHandler(string input, ILambdaContext context)
    {
        return input.ToUpper();
    }
}

약간의 설명이 필요한 행에 대한 몇 가지 참고 사항은 다음과 같습니다.

4행은 JSON 입력을 .NET 클래스로 변환합니다.

17행은 함수에 대한 JSON 입력을 문자열로 변환합니다.

17행은 ILambdaContext 객체가 매개 변수로 전달됩니다. 이 객체는 로깅, 함수 이름, 함수 실행 기간 및 기타 정보를 결정하는 데 사용할 수 있습니다.

보시다시피 코드는 매우 간단하며 C#을 사용해 본 사람이라면 누구나 익숙할 것입니다.

여기에 나오는 FunctionHandler 메서드는 동기식이지만, Lambda 함수는 다른 .NET 메서드처럼 비동기식일 수 있습니다. FunctionHandler를 다음과 같이 변경하기만 하면 됩니다.

public async Task<string> FunctionHandler(..)

이제 aws-lambda-tools-defaults.json 파일을 살펴보겠습니다.

{
  "Information": [
    "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
    "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
    "dotnet lambda help",
    "All the command line options for the Lambda command can be specified in this file."
  ],
  "profile": "",
  "region": "",
  "configuration": "Release",
  "function-runtime": "dotnet6",
  "function-memory-size": 256,
  "function-timeout": 30,
  "function-handler": "HelloEmptyFunction::HelloEmptyFunction.Function::FunctionHandler"
}

10행은 릴리스 구성에서 빌드되어야 할 함수를 지정합니다.

11행은 Lambda 서비스에 사용할 런타임을 지정합니다.

12행은 함수에 할당할 메모리 용량(이 경우, 256MB)을 지정합니다.

13행은 함수의 제한 시간을 지정합니다(이 경우, 30초). 최대 허용 제한 시간은 15분입니다.

14행은 함수 핸들러를 지정합니다. 이는 이 함수가 호출될 때 Lambda 서비스에서 호출할 메서드입니다.

함수 핸들러는 세 부분으로 구성됩니다.

"AssemblyName::Namespace.ClassName::MethodName"

조금 후에 이 파일의 구성을 사용하여 이 함수를 빌드하고 AWS Lambda 서비스에 배포해 보겠습니다.

하지만 먼저 테스트 프로젝트를 살펴보겠습니다. 이 파일은 HelloEmptyFunction.tests.cs 파일입니다.

using Xunit;
using Amazon.Lambda.Core;
using Amazon.Lambda.TestUtilities;

namespace HelloEmptyFunction.Tests;

public class FunctionTest
{
    [Fact]
    public void TestToUpperFunction()
    {

        // Invoke the lambda function and confirm the string was upper cased.
        var function = new Function();
        var context = new TestLambdaContext();
        var upperCase = function.FunctionHandler("hello world", context);

        Assert.Equal("HELLO WORLD", upperCase);
    }
}

이 코드는 비교적 간단하며 xUnit 테스트 프레임워크를 사용합니다. 다른 방법을 테스트하듯이 Lambda 함수도 테스트할 수 있습니다.

14행은 Function 클래스의 새 인스턴스를 만듭니다.

15행은 TestLambdaContext 클래스의 새 인스턴스를 생성합니다. 이 인스턴스는 다음 행에서 Lambda 함수로 전달됩니다.

16행은 함수에서 FunctionHandler 메서드를 호출하여 'hello world'라는 문자열과 컨텍스트를 전달합니다. 응답을 대문자 변수에 저장합니다.

18행은 대문자 변수가 'HELLO WORLD'와 같다고 어설션합니다.

명령줄이나 자주 사용하는 IDE에서 이 테스트를 실행할 수 있습니다. Lambda 함수에서 수행할 수 있는 다른 종류의 테스트도 있습니다. 이에 대해 자세히 알아보려면 Lambda 함수를 테스트하고 디버깅하는 다양한 방법에 대해 배울 수 있는 이후의 모듈을 참조하세요.

함수 배포

Lambda 함수가 생성되었고 이미 유닛 테스트를 실행했을 수도 있습니다. 이제 Lambda 함수를 AWS Lambda 서비스에 배포할 차례입니다.

명령줄에서 HelloEmptyFunction.csproj 파일이 들어 있는 디렉터리로 이동하여 다음 명령을 실행합니다.

dotnet lambda deploy-function HelloEmptyFunction  

다음 내용이 포함된 출력이 표시됩니다. (명확히 볼 수 있도록 내용을 잘랐습니다.)

... dotnet publish --output "C:\dev\Lambda_Course_Samples\HelloEmptyFunction\src\HelloEmptyFunction\bin\Release\net6.0\publish" --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false
Zipping publish folder C:\dev\Lambda_Course_Samples\HelloEmptyFunction\src\HelloEmptyFunction\bin\Release\net6.0\publish to C:\dev\Lambda_Course_Samples\HelloEmptyFunction\src\HelloEmptyFunction\bin\Release\net6.0\HelloEmptyFunction.zip
... zipping: Amazon.Lambda.Core.dll
... zipping: Amazon.Lambda.Serialization.SystemTextJson.dll
... zipping: HelloEmptyFunction.deps.json
... zipping: HelloEmptyFunction.dll
... zipping: HelloEmptyFunction.pdb
... zipping: HelloEmptyFunction.runtimeconfig.json
Created publish archive (C:\dev\Lambda_Course_Samples\HelloEmptyFunction\src\HelloEmptyFunction\bin\Release\net6.0\HelloEmptyFunction.zip).

1행은 프로젝트를 컴파일하고 게시합니다. 참고로 런타임은 linux-x64이고 자체 포함 플래그는 false입니다. 즉, 함수가 사용자 지정 런타임이 아닌 Lambda 서비스의 관리형.NET 런타임을 사용한다는 의미입니다.

2행은 게시된 프로젝트를 zip 파일로 압축합니다.

3~8행은 압축되고 있는 파일을 보여줍니다.

9행은 zip 파일이 생성되었음을 확인합니다.

그러면 '코드에 AWS 보안 인증을 제공할 IAM 역할 선택:'이라는 메시지가 표시되어 이전에 생성한 역할 목록이 표시됩니다. 목록 하단에 ‘*** 새 IAM 역할 생성***’ 옵션이 표시되며 해당 옵션 옆에 번호를 입력합니다.

'새 IAM 역할 이름 입력:'을 묻는 메시지가 표시됩니다. 'HelloEmptyFunctionRole'을 입력합니다.

그러면 '새 역할에 연결하고 권한을 부여할 IAM 정책을 선택하세요'라는 메시지가 표시되고 정책 목록이 나옵니다. 아래 목록에서 확인할 수 있으며, 실제로는 더 길어질 수 있습니다.

1) AWSLambdaReplicator (Grants Lambda Replicator necessary permissions to replicate functions ...)
2) AWSLambdaDynamoDBExecutionRole (Provides list and read access to DynamoDB streams and writ ...)
3) AWSLambdaExecute (Provides Put, Get access to S3 and full access to CloudWatch Logs.)
4) AWSLambdaSQSQueueExecutionRole (Provides receive message, delete message, and read attribu ...)
5) AWSLambdaKinesisExecutionRole (Provides list and read access to Kinesis streams and write  ...)
6) AWSLambdaBasicExecutionRole (Provides write permissions to CloudWatch Logs.)
7) AWSLambdaInvocation-DynamoDB (Provides read access to DynamoDB Streams.)
8) AWSLambdaVPCAccessExecutionRole (Provides minimum permissions for a Lambda function to exe ...)
9) AWSLambdaRole (Default policy for AWS Lambda service role.)
10) AWSLambdaENIManagementAccess (Provides minimum permissions for a Lambda function to manage ...)
11) AWSLambdaMSKExecutionRole (Provides permissions required to access MSK Cluster within a VP ...)
12) AWSLambda_ReadOnlyAccess (Grants read-only access to AWS Lambda service, AWS Lambda consol ...)
13) AWSLambda_FullAccess (Grants full access to AWS Lambda service, AWS Lambda console feature ...) 

'AWSLambdaBasicExecutionRole'을 선택합니다. 제 목록의 6번입니다.

잠시 후 다음을 확인할 수 있습니다.

Waiting for new IAM Role to propagate to AWS regions
...............  Done
New Lambda function created

이제 함수를 호출할 수 있습니다.

함수 호출

명령줄

dotnet lambda 도구를 사용하여 원하는 쉘에서 함수를 호출할 수 있습니다.

dotnet lambda invoke-function HelloEmptyFunction --payload "Invoking a Lambda function"

위와 같은 간단한 Lambda 함수는 이스케이프할 JSON이 없지만, 역직렬화해야 하는 JSON을 전달하려는 경우에는 페이로드 이스케이프는 사용 중인 쉘에 따라 달라집니다.

다음과 같은 출력이 표시됩니다.

Amazon Lambda Tools for .NET Core applications (5.4.1)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet

Payload:
"INVOKING A LAMBDA FUNCTION"

Log Tail:
START RequestId: 3d43c8be-8eca-48a1-9e51-96d9c84947b2 Version: $LATEST
END RequestId: 3d43c8be-8eca-48a1-9e51-96d9c84947b2
REPORT RequestId: 3d43c8be-8eca-48a1-9e51-96d9c84947b2  Duration: 244.83 ms      Billed Duration: 245 ms                                                                                                                  
Memory Size: 256 MB      Max Memory Used: 68 MB      Init Duration: 314.32 ms

출력 'Payload:'는 Lambda 함수의 응답입니다.

로그 테일에 Lambda 함수 호출에 대한 유용한 정보(예: 실행 시간, 메모리 사용량)가 어떻게 포함되어 있는지 확인하세요. 이와 같은 간단한 함수의 경우, 244.83ms가 느린 것처럼 보일 수 있습니다. 하지만 처음 호출된 함수라서 더 많은 작업을 수행해야 하므로 후속 호출은 더 빨라지게 됩니다. 자세한 내용은 콜드 스타트 섹션을 참조하세요.

코드를 약간 변경하여 자체 로그 명령문을 추가해보겠습니다.

FunctionHandler 메서드의 반환 명령문 위에 다음을 추가합니다.

context.Logger.LogInformation("Input: " + input);

다음을 사용하여 다시 배포하세요.

dotnet lambda deploy-function HelloEmptyFunction

이번에는 역할이나 권한에 대한 질문이 없습니다.

함수를 배포한 후 다시 호출할 수 있습니다.

dotnet lambda invoke-function HelloEmptyFunction --payload "Invoking a Lambda function" 

이번에는 출력에 추가 로그 명령문이 포함됩니다.

Payload:
"INVOKING A LAMBDA FUNCTION"

Log Tail:
START RequestId: 7f77a371-c183-494f-bb44-883fe0c57471 Version: $LATEST
2022-06-03T15:36:20.238Z        7f77a371-c183-494f-bb44-883fe0c57471    info    Input: Invoking a Lambda function
END RequestId: 7f77a371-c183-494f-bb44-883fe0c57471
REPORT RequestId: 7f77a371-c183-494f-bb44-883fe0c57471  Duration: 457.22 ms     Billed Duration: 458 ms                                                                                                       
Memory Size: 256 MB      Max Memory Used: 62 MB  Init Duration: 262.12 ms

6행에 로그 설명이 있습니다. Lambda 함수 로그도 CloudWatch 로그에 기록됩니다. (단, Lambda 함수에 해당 권한을 부여한 경우에 한합니다.)

AWS Console

함수를 호출하는 또 다른 방법은 AWS Console을 사용하는 것입니다.

AWS Console에 로그인하고 호출하려는 Lambda 함수를 선택합니다.

테스트 탭을 클릭합니다.

이벤트 JSON 섹션으로 스크롤하여 따옴표를 포함해 "Invoking a Lambda function"을 입력합니다.

그런 다음, 테스트 버튼을 클릭합니다.

다음과 유사한 출력 화면이 표시됩니다.

참고: 로그 출력도 볼 수 있습니다.

JSON 페이로드를 받는 .NET Lambda 함수

이전 예시는 문자열을 가져와 문자열을 반환하는 간단한 함수이므로 시작하기에 좋습니다.

하지만 Lambda 함수에 JSON 페이로드를 보내고 싶을 수도 있습니다. 실제로 다른 AWS 서비스가 Lambda 함수를 호출하면 JSON 페이로드를 전송합니다. 이러한 JSON 페이로드는 매우 복잡한 경우가 많지만 NuGet에서 페이로드 모델을 사용할 수 있습니다. 예를 들어 Lambda 함수를 사용하여 Kinesis 이벤트를 처리하는 경우, Amazon.lambda.KinesisEvents 패키지에는 KinesisEvent 모델이 있습니다. S3 이벤트, SQS 이벤트 등도 마찬가지입니다.

지금 당장은 이러한 모델 중 하나를 사용하는 대신, 사람을 나타내는 페이로드를 사용하여 새 Lambda 함수를 호출해보겠습니다.

{
  "FirstName": "Alan",
  "LastName": "Adams"
}

JSON 페이로드를 역직렬화하는 데 적합한 C# 클래스는 다음과 같습니다.

public class Person 
{
    public string FirstName { get; init; }
    public string LastName { get; init; }  
}

함수 생성

이전과 마찬가지로 다음 명령을 사용하여 새 함수를 생성합니다.

dotnet new lambda.EmptyFunction -n HelloPersonFunction

함수 변경

HelloPersonFunction/src/HelloPersonFunction의 Function.cs 파일로 이동합니다.

FunctionHandler 메서드의 코드를 다음과 같이 변경합니다.
public string FunctionHandler(Person input, ILambdaContext context)
{
    return $"Hello, {input.FirstName} {input.LastName}";
}
파일 맨 아래에 새 클래스를 추가합니다.
public class Person 
{
    public string FirstName { get; init; }
    public string LastName { get; init; }  
}

이는 몇 분 전에 사용한 것과 동일한 명령입니다.

이는 몇 분 전에 사용한 것과 동일한 명령입니다.
dotnet lambda deploy-function HelloPersonFunction

함수 호출

명령줄
 

이제 Lambda 함수가 JSON 페이로드를 받을 수 있지만 각 쉘에서 JSON이 이스케이프되는 방식 때문에 사용하는 쉘에 따라 호출 방법이 달라집니다.

PowerShell 또는 bash를 사용하는 경우, 다음을 사용하세요.

dotnet lambda invoke-function HelloPersonFunction --payload '{ \"FirstName\": \"Alan\", \"LastName\": \"Adams\" }'
하지만 Windows 명령 프롬프트를 사용하는 경우, 다음을 사용하세요.
dotnet lambda invoke-function HelloPersonFunction --payload "{ \"FirstName\": \"Alan\", \"LastName\": \"Adams\" }"
이는 간단한 예시일 뿐입니다. 물론 JSON은 원하는 만큼 복잡하게 만들 수 있습니다.
AWS Console
 
함수를 호출하는 또 다른 방법은 AWS Console을 사용하는 것입니다.

AWS Console에 로그인하고 호출하려는 Lambda 함수를 선택합니다.
테스트 탭을 클릭합니다.
이벤트 JSON 섹션으로 스크롤하여 다음을 입력합니다.
{
  "FirstName": "Alan",
  "LastName": "Adams"
}
그런 다음, 테스트 버튼을 클릭합니다.

다음과 유사한 출력 화면이 표시됩니다.
앞서 보여드린 몇 가지 예시는 매우 간단했고 Lambda 함수는 다른 AWS 서비스를 사용하지 않았습니다. 하지만 Lambda 함수를 작성하고 컴파일된 패키지를 배포하고 함수를 호출하여 AWS Lambda 서비스에 익숙해질 수 있는 좋은 방법입니다.

다음 섹션에서는 HTTP 요청에 응답하는 Lambda 함수를 배포하는 방법을 살펴보겠습니다.

웹 API 애플리케이션을 Lambda 함수로 생성 및 실행

앞의 예시에서 Lambda 함수는 모두 명령줄을 사용하거나 AWS Console의 Lambda 서비스 테스트 기능을 사용하여 호출되었습니다.

하지만 HTTP 요청을 통해 Lambda 함수를 호출할 수도 있는데, 이는 매우 흔한 사용 사례입니다.

.NET용 AWS 도구는 웹 API 애플리케이션을 호스팅하는 간단한 Lambda 함수를 생성하는 데 사용할 수 있는 몇 가지 템플릿을 제공합니다.

가장 친숙한 템플릿은 아마도 Serverless.AspNetCoreWebAPI 템플릿일 것입니다. 이 템플릿은 HTTP 요청을 통해 호출할 수 있는 간단한 웹 API 응용 프로그램을 만듭니다. 프로젝트 템플릿에는 HTTP 요청을 Lambda 함수로 전달하는 API Gateway를 생성하는 CloudFormation 구성 템플릿이 포함되어 있습니다.

AWS Lambda에 배포하면 API Gateway는 HTTP 요청을 API Gateway 이벤트로 변환하고, 이 JSON을 Lambda 함수로 보냅니다. Kestrel 서버가 Lambda 서비스에 배포될 때 Lambda 함수에서 실행되지 않는 상태입니다.

그러나 로컬에서 실행하면 Kestrel 웹 서버가 시작되므로 모든 웹 API 응용 프로그램에 익숙하게 코드를 작성하고 테스트하기가 매우 쉽습니다. 라인 디버깅으로 일반 행을 디버깅할 수도 있습니다. 여러분은 양쪽의 장점을 모두 활용할 수 있습니다!

함수 생성

명령줄에서 다음 명령을 실행합니다.
dotnet new serverless.AspNetCoreWebAPI -n HelloAspNetCoreWebAPI
이렇게 하면 HelloAspNetCoreWebAPI라는 새 디렉터리가 생성됩니다. 그 안에는 src와 test 디렉터리가 두 개 더 있습니다. 이름에서 알 수 있듯이, src 디렉터리에는 함수 코드가 포함되고 테스트 디렉터리에는 함수의 유닛 테스트가 포함됩니다. 이러한 디렉터리를 살펴보면 각각 다른 디렉터리가 포함되어 있음을 알 수 있을 것입니다.. 하위 디렉터리 내에는 함수의 코드 파일과 유닛 테스트 파일이 있습니다.
├───src
│   └───AspNetCoreWebAPI
│       │   appsettings.Development.json
│       │   appsettings.json
│       │   AspNetCoreWebAPI.csproj
│       │   aws-lambda-tools-defaults.json // basic Lambda function config, and points to serverless.template file for deployment
│       │   LambdaEntryPoint.cs // Contains the function handler method, this handles the incoming JSON payload
│       │   LocalEntryPoint.cs // Equivalent to Program.cs when running locally, starts Kestrel (only locally)
│       │   Readme.md  
│       │   serverless.template // CloudFormation template for deployment
│       │   Startup.cs // Familiar Startup.cs, can use dependency injection, read config, etc.
│       │
│       └───Controllers
│               ValuesController.cs // Familiar API controller
│
└───test
    └───AspNetCoreWebAPI.Tests
        │   appsettings.json
        │   AspNetCoreWebAPI.Tests.csproj
        │   ValuesControllerTests.cs // Unit test for ValuesController
        │
        └───SampleRequests
                ValuesController-Get.json // JSON representing an APIGatewayProxyRequest, used by the unit test

함수 배포

serverless.* 템플릿을 기반으로 함수를 배포하는 것은 lambda.* 템플릿을 기반으로 함수를 배포하는 것보다 조금 더 복잡합니다.

서버리스 함수를 배포하기 전에 S3 버킷이 필요합니다. 이는 배포 도구에서 CloudFormation 스택을 저장하는 데 사용됩니다.

기존 S3 버킷을 사용할 수 있으며, 버킷이 없는 경우 아래 지침을 따르세요.
S3 버킷 생성
 
us-east-1 리전을 사용하는 경우, 다음 명령어를 사용하여 버킷을 생성할 수 있습니다.
aws s3api create-bucket --bucket your-unique-bucket-name1234 
또는 다른 리전을 사용하는 경우
aws s3api create-bucket --bucket your-unique-bucket-name1234 --create-bucket-configuration LocationConstraint=REGION
저는 us-east-1에 lambda-course-2022라는 버킷을 생성했습니다.
aws s3api create-bucket --bucket lambda-course-2022 
함수 배포로 돌아가기
 
S3가 생성되었으니 배포 명령을 실행할 수 있습니다.
dotnet lambda deploy-serverless
CloudFormation 스택 이름을 입력하라는 메시지가 표시됩니다.
Enter CloudFormation Stack Name: (CloudFormation stack name for an AWS Serverless application)
AspNetCoreWebAPI를 입력합니다.

그러면 S3 버킷 이름을 입력하라는 메시지가 표시됩니다. 앞서 생성한 버킷의 이름이나 이 용도로 사용할 기존 버킷의 이름을 사용하세요.

이름을 입력하고 나면 빌드 및 배포 과정이 시작됩니다.

만들고 연결할 인프라가 더 많기 때문에 lambda.* 프로젝트 템플릿을 사용하는 예시보다 시간이 더 오래 걸립니다.

출력은 두 개의 개별 섹션으로 나뉩니다.

위쪽 섹션은 앞서 함수를 배포할 때 보았던 프로젝트 게시 및 zip 파일과 비슷하지만, 이번에는 아티팩트가 S3에 업로드됩니다.
..snip
... zipping: AspNetCoreWebAPI.runtimeconfig.json
... zipping: aws-lambda-tools-defaults.json
Created publish archive (C:\Users\someuser\AppData\Local\Temp\AspNetCoreFunction-CodeUri-Or-ImageUri-637907144179228995.zip).
Lambda project successfully packaged: C:\Users\ someuser\AppData\Local\Temp\AspNetCoreFunction-CodeUri-Or-ImageUri-637907144179228995.zip
Uploading to S3. (Bucket: lambda-course-2022 Key: AspNetCoreWebAPI/AspNetCoreFunction-CodeUri-Or-ImageUri-637907144179228995-637907144208759417.zip)
... Progress: 100%
그런 다음, CloudFormation 스택이 생성되고 필요한 모든 리소스가 배포됩니다.
Uploading to S3. (Bucket: lambda-course-2022 Key: AspNetCoreWebAPI/AspNetCoreWebAPI-serverless-637907144211067892.template)
... Progress: 100%
Found existing stack: False
CloudFormation change set created
... Waiting for change set to be reviewed
Created CloudFormation stack AspNetCoreWebAPI

Timestamp            Logical Resource Id                      Status
-------------------- ---------------------------------------- ---------------------------------------- 
6/10/2022 09:53 AM   AspNetCoreWebAPI                         CREATE_IN_PROGRESS
6/10/2022 09:53 AM   AspNetCoreFunctionRole                   CREATE_IN_PROGRESS
6/10/2022 09:53 AM   AspNetCoreFunctionRole                   CREATE_IN_PROGRESS
6/10/2022 09:54 AM   AspNetCoreFunctionRole                   CREATE_COMPLETE
6/10/2022 09:54 AM   AspNetCoreFunction                       CREATE_IN_PROGRESS
6/10/2022 09:54 AM   AspNetCoreFunction                       CREATE_IN_PROGRESS
6/10/2022 09:54 AM   AspNetCoreFunction                       CREATE_COMPLETE
6/10/2022 09:54 AM   ServerlessRestApi                        CREATE_IN_PROGRESS
6/10/2022 09:54 AM   ServerlessRestApi                        CREATE_IN_PROGRESS
6/10/2022 09:54 AM   ServerlessRestApi                        CREATE_COMPLETE
6/10/2022 09:54 AM   ServerlessRestApiDeploymentcfb7a37fc3    CREATE_IN_PROGRESS
6/10/2022 09:54 AM   AspNetCoreFunctionProxyResourcePermissionProd CREATE_IN_PROGRESS
6/10/2022 09:54 AM   AspNetCoreFunctionRootResourcePermissionProd CREATE_IN_PROGRESS
6/10/2022 09:54 AM   AspNetCoreFunctionProxyResourcePermissionProd CREATE_IN_PROGRESS
6/10/2022 09:54 AM   AspNetCoreFunctionRootResourcePermissionProd CREATE_IN_PROGRESS
6/10/2022 09:54 AM   ServerlessRestApiDeploymentcfb7a37fc3    CREATE_IN_PROGRESS
6/10/2022 09:54 AM   ServerlessRestApiDeploymentcfb7a37fc3    CREATE_COMPLETE
6/10/2022 09:54 AM   ServerlessRestApiProdStage               CREATE_IN_PROGRESS
6/10/2022 09:54 AM   ServerlessRestApiProdStage               CREATE_IN_PROGRESS
6/10/2022 09:54 AM   ServerlessRestApiProdStage               CREATE_COMPLETE
6/10/2022 09:54 AM   AspNetCoreFunctionProxyResourcePermissionProd CREATE_COMPLETE
6/10/2022 09:54 AM   AspNetCoreFunctionRootResourcePermissionProd CREATE_COMPLETE
6/10/2022 09:54 AM   AspNetCoreWebAPI                         CREATE_COMPLETE
Stack finished updating with status: CREATE_COMPLETE

Output Name                    Value
------------------------------ --------------------------------------------------
ApiURL                         https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/

오른쪽 하단에는 API를 호출하는 데 사용할 수 있는 공개 URL이 있습니다.

함수 호출

브라우저 또는 Fiddler/Postman 등에서 해당 URL을 열면 'AWS Lambda에서 ASP.NET Core를 실행해 주셔서 감사합니다'와 같은 응답이 표시됩니다.

그런 다음, https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/api/values를 열어 보세요. 일반 웹 API 애플리케이션에서와 마찬가지로 값 컨트롤러 GET 메서드를 호출합니다.

참고로 API Gateway를 사용하는 경우, 게이트웨이는 자체적으로 29초의 제한 시간을 적용합니다. Lambda 함수가 이보다 오래 실행되는 경우 응답을 받지 못합니다.

관심이 있는 경우, 생성된 리소스를 검토하는 데 사용할 수 있는 몇 가지 방법이 있습니다.

생성된 AWS 리소스를 검토하려면 다음을 사용할 수 있습니다.
aws cloudformation describe-stack-resources --stack-name AspNetCoreWebAPI
그러면 스택의 모든 리소스에 대한 세부 정보가 제공됩니다.

보다 간결한 출력을 원한다면 다음을 사용하세요.
aws cloudformation describe-stack-resources --stack-name AspNetCoreWebAPI --query 'StackResources[].[{ResourceType:ResourceType, LogicalResourceId:LogicalResourceId, PhysicalResourceId:PhysicalResourceId}]'
또 다른 방법은 AWS Console을 열고 Lambda 서비스로 이동하는 것입니다. 화면 왼쪽에서 함수 대신 애플리케이션을 선택합니다.


생성한 애플리케이션이 보입니다. 선택한 다음 열리는 페이지 아래쪽으로 스크롤합니다. 여기에서 생성된 모든 리소스를 볼 수 있습니다.
지금까지 Lambda 함수의 세 가지 예를 살펴보았습니다. 첫 번째는 문자열을 사용하는 간단한 Hello World였고, 두 번째 함수도 매우 간단하지만 JSON 객체를 사용했으며, 세 번째는 좀 더 복잡하지만 생성 및 배포가 매우 쉬웠습니다.

이러한 예시를 통해 자체 Lambda 함수를 생성하고 배포할 수 있습니다. .NET Lambda 함수가 호출되는 방식에 대해 조금 알게 되었을 수도 있습니다. 이는 다음 섹션의 주제입니다.

함수 URL – API Gateway의 대안

간단한 HTTP 요청에 응답하는 Lambda 함수만 필요한 경우, Lambda 함수 URL을 사용하는 방법을 고려해야 합니다.

이를 통해 Lambda 함수에 HTTPS 엔드포인트를 할당할 수 있습니다. 그런 다음, HTTPS 엔드포인트에 요청하여 Lambda 함수를 호출합니다. 자세한 내용은 이 블로그 게시물문서를 참조하세요.

생성한 리소스 정리하기

Lambda 함수 실행은 다음과 같은 방법으로 삭제할 수 있습니다.
dotnet lambda delete-function HelloEmptyFunction  
dotnet lambda delete-function HelloPersonFunction

단, 위 명령을 실행해도 생성한 역할은 삭제되지 않습니다.

웹 API 애플리케이션을 호스팅한 Lambda 함수와 모든 관련 리소스를 삭제하려면 다음을 실행합니다.

dotnet lambda delete-serverless AspNetCoreWebAPI

.NET Lambda 함수를 호출하는 방법

위의 예에서 볼 수 있듯이, 간단한 문자열, JSON 객체 및 HTTP 요청을 사용하여 .NET Lambda 함수를 호출할 수 있습니다. Lambda 함수는 S3(파일 변경 시), Kinesis(이벤트 도착 시), DynamoDB(테이블 변경 발생 시), SMS(메시지 도착 시), Step Functions 등과 같은 다른 서비스에서도 호출할 수 있습니다.

Lambda 함수는 이러한 다양한 호출 방법을 어떻게 처리하나요?

내부적으로 이러한 Lambda 함수는 Lambda 서비스가 함수 핸들러를 실행하고 JSON 입력을 전달할 때 호출됩니다. aws-lambda-tools-defaults.json을 보면 "function-handler":가 지정되어 있는 것을 확인할 수 있습니다. .NET Lambda 함수의 경우, 핸들러는 'AssemblyName::Namespace.ClassName::MethodName'으로 구성됩니다.

Lambda 함수에 스트림을 전달하여 호출할 수도 있지만 이는 일반적인 시나리오가 아닙니다. 자세한 내용은 스트림 처리 페이지를 참조하세요.

각 Lambda 함수에는 단일 함수 핸들러가 있습니다.

Lambda 함수 핸들러는 JSON 입력과 함께 선택적 ILambdaContext 객체를 사용할 수도 있습니다. 이를 통해 현재 호출에 대한 정보(예: 완료까지 남은 시간, 함수 이름 및 버전)에 액세스할 수 있습니다. ILambdaContext 객체를 통해 로그 메시지를 작성할 수도 있습니다.

모든 이벤트는 JSON입니다.

AWS 서비스가 .NET Lambda 함수를 매우 쉽게 호출할 수 있는 이유는 이러한 서비스가 JSON을 생성하고, 위에서 설명한 것처럼 .NET Lambda 함수가 JSON 입력을 받아들이기 때문입니다. 서로 다른 서비스에서 발생하는 이벤트는 모두 다른 형태의 JSON을 생성하지만, AWS Lambda 이벤트 NuGet 패키지에는 JSON을 다시 작업 가능한 객체로 직렬화하는 데 필요한 모든 관련 객체 유형이 포함되어 있습니다.

사용 가능한 Lambda 패키지 목록은 https://www.nuget.org/packages?packagetype=&sortby=relevance&q=Amazon.Lambda&prerel=True을 참조하세요. 해당 결과 내에서 관심 있는 이벤트 유형을 검색해야 합니다.

예를 들어, S3 버킷의 파일 변경에 대한 응답으로 Lambda 함수를 트리거하려면 S3Event 유형의 객체를 받아들이는 Lambda 함수를 생성해야 합니다. 그런 다음, Amazon.Lambda.S3Events 패키지를 프로젝트에 추가합니다. 함수 핸들러 메서드는 다음과 같이 변경합니다.

public async string FunctionHandler(S3Event s3Event, ILambdaContext context)
{
    ...
}

이것만 있으면 S3 이벤트를 처리할 수 있습니다. 이를 통해 이벤트를 프로그래밍 방식으로 검사하고, 파일에서 어떤 작업이 수행되었는지, 어떤 버킷에 있는지 등을 확인할 수 있습니다. Amazon.Lambda.S3Events를 사용하면 S3 자체가 아닌 이벤트 작업을 수행할 수 있습니다. S3 서비스와 상호작용하려면 프로젝트에 AWSSDK.S3 NuGet 패키지도 추가해야 합니다. 이후 모듈에서는 Lambda 함수를 호출하는 AWS 서비스에 대한 주제를 다루겠습니다.

다른 유형의 이벤트에도 동일한 패턴이 적용됩니다. NuGet 패키지를 추가하고 매개 변수를 함수 핸들러로 변경하면 이벤트 객체로 작업할 수 있습니다.

다른 서비스의 이벤트를 처리하는 데 사용할 수 있는 몇 가지 일반적인 패키지는 다음과 같습니다.

https://www.nuget.org/packages/Amazon.Lambda.SNSEvents

https://www.nuget.org/packages/Amazon.Lambda.DynamoDBEvents

https://www.nuget.org/packages/Amazon.Lambda.CloudWatchEvents

https://www.nuget.org/packages/Amazon.Lambda.KinesisEvents

https://www.nuget.org/packages/Amazon.Lambda.APIGatewayEvents

Lambda 함수를 호출할 때 AWS 정의 이벤트 유형을 사용하는 데는 제한이 없습니다. 모든 유형의 이벤트는 직접 생성할 수 있습니다. Lambda 함수는 전송한 모든 JSON을 수신할 수 있다는 점을 기억하세요.

직렬화 방법

Lambda 프로젝트 템플릿에는 크게 두 가지 범주, 즉 'lambda.'로 시작하는 템플릿과 'serverless.'로 시작하는 템플릿이 있습니다.

'lambda.' 템플릿의 경우, Function.cs 파일 상단에 assembly 속성이 있습니다. 이 속성은 들어오는 이벤트를 함수 핸들러의 .NET 유형으로 역직렬화하는 작업을 처리합니다. .csproj 파일에는 Amazon.Lambda.Serialization.SystemTextJson 패키지에 대한 참조가 있습니다.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
그 외의 다른 건 하지 않아도 됩니다.

'serverless.' 템플릿은 조금 다르게 작동합니다.

함수 핸들러는 serverless.template 파일에서 지정됩니다. serverless.AspNetCoreWebAPI 애플리케이션을 배포하는 경우, Resources.AspNetCoreFunction.Properties.Handler에서 값을 확인하세요. 이 유형의 프로젝트 핸들러는 Assembly::Namespace.LambdaEntryPoint::FunctionHandlerAsync 형식으로 종료됩니다.

LambdaEntryPoint 클래스는 프로젝트에 포함되며, FunctionHandlerAsync 메서드가 있는 클래스에서 상속됩니다.

함수 핸들러는 네 가지 이벤트 유형, 즉 API Gateway REST API, API Gateway HTTP API 페이로드 버전 1.0, API Gateway HTTP API 페이로드 버전 2.0 및 Application Load Balancer를 처리하도록 설정할 수 있습니다.

LambdaEntryPoint가 상속하는 클래스를 변경하여 함수 핸들러가 처리하는 JSON 이벤트의 유형을 변경할 수 있습니다.

Lambda 함수가 사용자가 보내는 HTTP 요청에 응답하는 것처럼 보이지만 사용자가 정의한 JSON을 사용하면 실제로는 그렇지 않습니다. 실제로 HTTP 요청은 게이트웨이나 로드 밸런서에서 처리되며, 게이트웨이나 로드 밸런서가 JSON 이벤트를 생성하여 함수 핸들러로 보냅니다. 이 JSON 이벤트에는 원래 HTTP 요청에 포함된 데이터, 소스 IP 주소, 요청 헤더에 이르는 모든 데이터가 포함됩니다.

동시성

Lambda 함수를 사용할 때 고려해야 할 동시성에는 예약 동시성과 프로비저닝된 동시성이라는 두 가지 종류가 있습니다.

AWS 계정에는 동시 Lambda 실행 수에 대한 기본적인 상한이 있습니다. 이 글을 쓰는 시점의 한도는 1,000개입니다.

함수에 대해 예약된 동시성을 지정하면 함수가 지정된 동시 실행 수에 도달할 수 있도록 보장됩니다. 예를 들어 함수의 예약된 동시성이 200개인 경우, 함수가 200개의 동시 실행에 도달할 수 있는지 확인해야 합니다. 참고로 다른 함수의 경우, 800개의 동시 실행(1,000-200=800)이 남습니다.

프로비저닝된 동시성을 지정하면 지정된 수의 Lambda 실행 환경을 초기화하게 됩니다. 이러한 작업이 초기화되면 Lambda 함수는 요청에 즉시 응답하여 '콜드 스타트' 문제를 피할 수 있습니다. 하지만 프로비저닝된 동시성 사용에는 요금이 부과됩니다.

자세한 내용은 Lambda 예약 동시성 관리 및 Lambda 프로비저닝된 동시성 관리를 참조하세요.

콜드 스타트와 웜 스타트

Lambda 함수를 호출하려면 먼저 실행 환경을 초기화해야 합니다. 이 작업은 Lambda 서비스에서 사용자를 대신하여 수행합니다. 소스 코드는 AWS 관리형 S3 버킷(관리형 런타임 및 사용자 지정 런타임을 사용하는 함수의 경우) 또는 Elastic Container Registry(컨테이너 이미지를 사용하는 함수의 경우)에서 다운로드됩니다.

함수를 처음 실행할 때는 코드를 JIT 처리하고 초기화 코드(예: 생성자)를 실행해야 합니다. 이렇게 하면 콜드 스타트 시간이 늘어납니다.

함수를 정기적으로 호출하면 '웜' 상태로 유지됩니다. 즉, 실행 환경이 유지됩니다. 이후에 함수를 호출해도 콜드 스타트 시간이 영향을 받지 않습니다. '웜 스타트'는 '콜드 스타트'보다 훨씬 빠릅니다.

특정 기간(Lambda 서비스에서 정확한 시간을 지정하지 않은 경우) 동안 함수가 호출되지 않으면 실행 환경이 제거됩니다. 다음에 함수를 호출하면 다시 콜드 스타트가 발생합니다.

새 버전의 함수 코드를 업로드하면 다음에 함수를 호출할 때 콜드 스타트가 발생합니다.

Lambda에서 .NET을 실행하기 위한 세 가지 옵션, 즉 관리형 런타임, 사용자 지정 런타임 및 컨테이너 호스팅은 각각 다른 콜드 스타트 프로필을 가지고 있습니다. 가장 느린 것은 컨테이너이고, 그 다음으로 느린 것은 사용자 지정 런타임이며, 가장 빠른 것은 관리형 런타임입니다. .NET Lambda 함수를 실행할 때는 가능하면 항상 관리형 런타임을 선택해야 합니다.

콜드 스타트는 프로덕션 환경보다 테스트 또는 개발 환경에서 더 자주 발생하는 것으로 밝혀졌습니다. AWS 분석에서 콜드 스타트는 호출의 1% 미만에서 발생합니다.

사용 빈도가 낮은 Lambda 함수가 있지만 요청에 빠르게 응답해야 하는 경우, 콜드 스타트를 피하고 싶다면 프로비저닝된 동시성을 사용하거나 함수를 자주 '핑'하여 웜 상태로 유지하는 메커니즘을 사용할 수 있습니다.

Lambda 함수 최적화에 대한 자세한 내용은 AWS Lambda 개발자 안내서에서 콜드 스타트, 웜 스타트 및 프로비저닝된 동시성에 대해 읽거나, James Beswick이 작성한 Operating Lambda: Performance optimization 블로그 시리즈 part 1, part 2, part 3를 참조하세요.

.NET 7 이전 .NET 버전을 위한 트리밍 및 실행 준비

.NET 7 이전 .NET 버전에 대해 Lambda 사용자 지정 런타임을 사용하기로 선택한 경우, 콜드 스타트 시간을 줄이기 위해 사용할 수 있는 .NET 기능이 몇 가지 있습니다.

PublishTrimmed는 패키지에서 불필요한 라이브러리를 제거하여 배포하는 패키지의 전체 크기를 줄입니다.

PublishReadyToRun은 코드 컴파일을 미리 수행하여 필요한 적시 컴파일의 양을 줄입니다. 하지만 이렇게 하면 배포하는 패키지의 크기가 커집니다.

성능을 최적화하려면 이러한 옵션을 사용할 때 함수를 테스트해야 합니다.

.csproj 파일에서 PublishTrimmed 및 PublishReadyToRun을 활성화할 수 있습니다.

<PublishTrimmed>true</PublishTrimmed>
<PublishReadyToRun>true</PublishReadyToRun>

결론

이 모듈에서는 .NET Lambda 함수를 생성, 배포 및 호출하는 방법을 소개했습니다. AWS Lambda에서 .NET을 실행할 수 있는 다양한 방법을 개괄적으로 설명하고, 어떤 방법을 선택할지 몇 가지 이유를 설명했습니다. 또한 '콜드 스타트'와 최적화에 대한 개념도 설명했습니다.


.NET 7을 위한 네이티브 AOT 컴파일

2022년 11월에 출시된 NET 7은 네이티브 AOT(Ahead-Of-Time) 컴파일을 지원합니다. AWS Lambda용 .NET 템플릿 도구를 사용하면 .NET 7 사용자 지정 런타임 함수를 빌드하고 배포할 수 있습니다. 테스트에서 .NET 7 Lambda 함수는 .NET 6 관리형 런타임에 비해 콜드 스타트 속도가 최대 86% 더 빠릅니다.
 
이 새로운 기능을 활용하려면 .NET Lambda 프로젝트 템플릿을 버전 6.7.0 이상으로 업데이트하고 .NET용 AWS 확장 프로그램을 버전 5.6.1 이상으로 업데이트해야 합니다.
 
업데이트를 수행하려면 다음을 실행합니다.
dotnet new -i "Amazon.Lambda.Templates::*"dotnet tool update -g Amazon.Lambda.Tools
이 글을 쓰는 시점에는 Lambda AOT 함수를 위한 템플릿이 두 개 있습니다. 바로 Lambda.NativeAOT와 Serverless.NativeAOT입니다. 또한, Docker를 설치하고 실행해야 합니다.

지식 확인

이제 AWS Lambda를 사용하여 '모듈 2, .NET 개발을 위한 도구'를 완료했습니다. 다음 테스트를 통해 지금까지 배운 내용을 확인할 수 있습니다.

1. Lambda 서비스는 어떤 버전의 .NET 관리형 런타임을 제공하나요?(두 개 선택)

a. .NET Core 5

b. .NET 6

c. .NET 7

d. .NET Core 3.1

e. .NET Framework 4.8

2. 콜드 스타트는 무엇을 의미하나요?(하나 선택)

a. Lambda 실행 환경을 시작하고 함수의 초기화 코드를 시작하는 데 걸리는 시간.

b. AWS S3 Glacier 스토리지를 사용하는 Lambda 함수.

c. Lambda 서비스에 코드를 배포하는 데 걸리는 시간.

d. 함수를 업데이트하는 데 걸리는 시간.

3. .NET Lambda 함수와 AWS .NET SDK를 함께 사용하려면 어떻게 해야 하나요?

a. 프로젝트 파일에 SDK 패키지에 대한 참조를 추가합니다.

b. Lambda 함수 템플릿이 포함되어 있으므로 필요하지 않습니다.

c. IDE용 툴킷에 포함되어 있으므로 필요하지 않습니다.

d. AWS Console을 통해 Lambda 서비스에 SDK를 추가합니다.

4. 새 Lambda.EmptyFunction 프로젝트를 생성할 때 함수의 구성을 지정하는 파일 이름은 무엇인가요?

a. serverless.template

b. lambda.csproj

c. aws-lambda-tools-defaults.json

5. 다음 중 Lambda 함수를 호출하는 방법은 무엇인가요?

a. dotnet lambda 도구를 사용하는 명령줄

b. HTTPS 요청

c. 기타 AWS 서비스에서 호출

d. 위의 모든 항목

정답: 1-bd, 2-a, 3-a, 4-c, 5-d

결론

이 모듈에서는 .NET Lambda 함수를 생성, 배포 및 호출하는 방법을 소개했습니다. AWS Lambda에서 .NET을 실행할 수 있는 다양한 방법을 개괄적으로 설명하고, 어떤 방법을 선택할지 몇 가지 이유를 설명했습니다. 또한 '콜드 스타트'와 최적화에 대한 개념도 설명했습니다.

이 페이지의 내용이 도움이 되었나요?

다른 AWS 서비스와 호환