Compilare il codice della funzione.NET Lambda in un formato di runtime nativo - AWS Lambda

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Compilare il codice della funzione.NET Lambda in un formato di runtime nativo

.NET 8 supporta la compilazione nativa ahead-of-time (AOT). Con AOT nativa, puoi compilare il codice della funzione Lambda in un formato di runtime nativo, che elimina la necessità di compilare il codice .NET in fase di runtime. La compilazione AOT nativa può ridurre il tempo di avvio a freddo delle funzioni Lambda scritte in .NET. Per ulteriori informazioni, vedi Introduzione al runtime di .NET 8 nel blog AWS Lambda di AWS Compute.

Runtime Lambda

Per distribuire una build di funzione Lambda con compilazione AOT nativa, usa il runtime gestito.NET 8 Lambda. Questo runtime supporta l'uso di entrambe le architetture x86_64 e arm64.

Quando si distribuisce una funzione.NET Lambda senza utilizzare AOT, l'applicazione viene prima compilata nel codice Intermediate Language (IL). In fase di esecuzione, il compilatore just-in-time (JIT) nel runtime Lambda prende il codice IL e lo compila in codice macchina secondo necessità. Con una funzione Lambda compilata in anticipo con AOT nativo, compili il codice in codice macchina quando distribuisci la funzione, in modo da non dipendere dal runtime .NET o dall'SDK nel runtime Lambda per compilare il codice prima che venga eseguito.

Una limitazione di AOT è che il codice dell'applicazione deve essere compilato in un ambiente con lo stesso sistema operativo Amazon Linux 2023 (AL2023) utilizzato dal runtime .NET 8. La CLI.NET Lambda offre funzionalità per compilare l'applicazione in un contenitore Docker utilizzando un'immagine AL2023.

Per evitare potenziali problemi di compatibilità tra architetture diverse, consigliamo vivamente di compilare il codice in un ambiente con la stessa architettura di processore configurata per la funzione. Per ulteriori informazioni sui limiti della compilazione tra architetture diverse, vedere Compilazione incrociata nella documentazione di Microsoft.NET.

Prerequisiti

Docker

Per utilizzare l'AOT nativo, il codice della funzione deve essere compilato in un ambiente con lo stesso sistema operativo AL2023 del runtime DI.NET 8. I comandi CLI.NET nelle seguenti sezioni utilizzano Docker per sviluppare e creare funzioni Lambda in un ambiente AL2023.

.NET 8 SDK

La compilazione AOT nativa è una funzionalità di.NET 8. È necessario installare il.NET 8 SDK sulla macchina di compilazione, non solo sul runtime.

Amazon.Lambda.Tools

Per creare le funzioni Lambda, usa l'estensione degli strumenti globali .NET Amazon.Lambda.Tools. Per installare Amazon.Lambda.Tools, esegui il comando riportato:

dotnet tool install -g Amazon.Lambda.Tools

Per ulteriori informazioni sull'Amazon.Lambda.Toolsestensione.NET CLI, consulta l'archivio AWS Extensions for .NET CLI su. GitHub

Amazon.Lambda.Templates

Per generare il codice della funzione Lambda, usa il Amazon.Lambda.Templates NuGet pacchetto. Per installare questo pacchetto del modello, esegui il comando riportato:

dotnet new install Amazon.Lambda.Templates

Nozioni di base

Sia il.NET Global CLI che AWS Serverless Application Model (AWS SAM) forniscono modelli introduttivi per la creazione di applicazioni utilizzando AOT nativo. Per creare la tua prima funzione Lambda AOT nativa, completa le operazioni riportate nelle seguenti istruzioni.

Inizializzazione e distribuzione di una funzione Lambda compilata in AOT nativa
  1. Inizializza un nuovo progetto utilizzando il modello AOT nativo, quindi naviga nella directory contenente i file .cs e .csproj creati. In questo esempio, diamo un nome alla nostra funzione NativeAotSample.

    dotnet new lambda.NativeAOT -n NativeAotSample cd ./NativeAotSample/src/NativeAotSample

    Il file Function.cs creato dal modello AOT nativo contiene il seguente codice di funzione.

    using Amazon.Lambda.Core; using Amazon.Lambda.RuntimeSupport; using Amazon.Lambda.Serialization.SystemTextJson; using System.Text.Json.Serialization; namespace NativeAotSample; public class Function { /// <summary> /// The main entry point for the Lambda function. The main function is called once during the Lambda init phase. It /// initializes the .NET Lambda runtime client passing in the function handler to invoke for each Lambda event and /// the JSON serializer to use for converting Lambda JSON format to the .NET types. /// </summary> private static async Task Main() { Func<string, ILambdaContext, string> handler = FunctionHandler; await LambdaBootstrapBuilder.Create(handler, new SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>()) .Build() .RunAsync(); } /// <summary> /// A simple function that takes a string and does a ToUpper. /// /// To use this handler to respond to an AWS event, reference the appropriate package from /// https://github.com/aws/aws-lambda-dotnet#events /// and change the string input parameter to the desired event type. When the event type /// is changed, the handler type registered in the main method needs to be updated and the LambdaFunctionJsonSerializerContext /// defined below will need the JsonSerializable updated. If the return type and event type are different then the /// LambdaFunctionJsonSerializerContext must have two JsonSerializable attributes, one for each type. /// // When using Native AOT extra testing with the deployed Lambda functions is required to ensure // the libraries used in the Lambda function work correctly with Native AOT. If a runtime // error occurs about missing types or methods the most likely solution will be to remove references to trim-unsafe // code or configure trimming options. This sample defaults to partial TrimMode because currently the AWS // SDK for .NET does not support trimming. This will result in a larger executable size, and still does not // guarantee runtime trimming errors won't be hit. /// </summary> /// <param name="input"></param> /// <param name="context"></param> /// <returns></returns> public static string FunctionHandler(string input, ILambdaContext context) { return input.ToUpper(); } } /// <summary> /// This class is used to register the input event and return type for the FunctionHandler method with the System.Text.Json source generator. /// There must be a JsonSerializable attribute for each type used as the input and return type or a runtime error will occur /// from the JSON serializer unable to find the serialization information for unknown types. /// </summary> [JsonSerializable(typeof(string))] public partial class LambdaFunctionJsonSerializerContext : JsonSerializerContext { // By using this partial class derived from JsonSerializerContext, we can generate reflection free JSON Serializer code at compile time // which can deserialize our class and properties. However, we must attribute this class to tell it what types to generate serialization code for. // See https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation

    AOT nativo compila l'applicazione in un unico binario nativo. Il punto di ingresso di quel binario è il metodo static Main. All'interno di static Main, viene avviato il runtime Lambda e viene impostato il metodo FunctionHandler. Come parte del bootstrap di runtime, un serializzatore generato dal codice sorgente viene configurato utilizzando new SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>()

  2. Per distribuire l'applicazione in Lambda, assicurati che Docker sia in esecuzione nel tuo ambiente locale ed esegui il comando riportato.

    dotnet lambda deploy-function

    Dietro le quinte, la CLI globale.NET scarica un'immagine Docker AL2023 e compila il codice dell'applicazione all'interno di un container in esecuzione. Il file binario compilato viene restituito al file system locale prima di essere implementato su Lambda.

  3. Verifica la tua funzione eseguendo il comando riportato. Sostituisci <FUNCTION_NAME> con il nome scelto per la funzione nella procedura guidata di implementazione.

    dotnet lambda invoke-function <FUNCTION_NAME> --payload "hello world"

    La risposta della CLI include dettagli sulle prestazioni per l'avvio a freddo (durata di inizializzazione) e il tempo di esecuzione totale per l'invocazione della funzione.

  4. Per eliminare le AWS risorse create seguendo i passaggi precedenti, esegui il comando seguente. Sostituisci <FUNCTION_NAME> con il nome scelto per la funzione nella procedura guidata di implementazione. Eliminando AWS le risorse che non utilizzi più, eviti che ti vengano addebitati addebiti inutili. Account AWS

    dotnet lambda delete-function <FUNCTION_NAME>

Serializzazione

Per implementare le funzioni in Lambda utilizzando AOT nativo, il codice della funzione deve utilizzare la serializzazione generata dal codice sorgente. Invece di utilizzare la riflessione in fase di esecuzione per raccogliere i metadati necessari per accedere alle proprietà degli oggetti per la serializzazione, i generatori di codice sorgente generano file sorgente C# che vengono compilati durante la creazione dell'applicazione. Per configurare correttamente il serializzatore generato dal codice sorgente, assicurati di includere tutti gli oggetti di input e output utilizzati dalla funzione, nonché tutti i tipi personalizzati. Ad esempio, una funzione Lambda che riceve eventi da una REST API di Gateway API e restituisce un tipo Product personalizzato includerebbe un serializzatore definito come segue.

[JsonSerializable(typeof(APIGatewayProxyRequest))] [JsonSerializable(typeof(APIGatewayProxyResponse))] [JsonSerializable(typeof(Product))] public partial class CustomSerializer : JsonSerializerContext { }

Rifinitura

L'AOT nativo rifinisce il codice dell'applicazione come parte della compilazione per garantire che il file binario sia il più piccolo possibile. .NET 8 for Lambda offre un supporto di taglio migliorato rispetto alle versioni precedenti di.NET. È stato aggiunto il supporto alle librerie di runtime Lambda, AWS .NET SDK, .NET Lambda Annotations e .NET 8 stesso.

Questi miglioramenti offrono la possibilità di eliminare gli avvisi di taglio in fase di compilazione, ma .NET non sarà mai completamente sicuro. Ciò significa che parti delle librerie su cui si basa la funzione possono essere eliminate durante la fase di compilazione. Puoi gestirlo definendo TrimmerRootAssemblies come parte del tuo .csproj file, come mostrato nell'esempio seguente.

<ItemGroup> <TrimmerRootAssembly Include="AWSSDK.Core" /> <TrimmerRootAssembly Include="AWSXRayRecorder.Core" /> <TrimmerRootAssembly Include="AWSXRayRecorder.Handlers.AwsSdk" /> <TrimmerRootAssembly Include="Amazon.Lambda.APIGatewayEvents" /> <TrimmerRootAssembly Include="bootstrap" /> <TrimmerRootAssembly Include="Shared" /> </ItemGroup>

Tieni presente che quando ricevi un avviso di taglio, l'aggiunta della classe che genera l'avviso TrimmerRootAssembly potrebbe non risolvere il problema. Un avviso di trim indica che la classe sta tentando di accedere a un'altra classe che non può essere determinata fino al runtime. Per evitare errori di runtime, aggiungete questa seconda classe aTrimmerRootAssembly.

Per ulteriori informazioni sulla gestione degli avvisi di taglio, vedere Introduzione agli avvisi di taglio nella documentazione di Microsoft.NET.

Risoluzione dei problemi

Errore: la compilazione nativa tra sistemi operativi non è supportata.

La tua versione dello strumento globale .NET Core di Amazon.Lambda.Tools non è aggiornata. Esegui l'aggiornamento alla versione più recente e riprova.

Docker: il sistema operativo di immagini "linux" non può essere utilizzato su questa piattaforma.

Docker sul tuo sistema è configurato per utilizzare container Windows. Passa ai container Linux per eseguire l'ambiente della compilazione AOT nativa.

Per ulteriori informazioni sugli errori comuni, consulta il repository AWS NativeAOT for .NET su. GitHub