.NET-Workloads in AWS Lambda

MODUL 3

Modul 3: .NET in AWS Lambda

 LERNMODUL

Bitte beachten Sie, dass Sie den hier vorgestellten Beispielen folgen können, dies aber nicht müssen.

AWS Lambda unterstützt mehrere .NET-Versionen, sowohl auf x86_64- als auch auf Arm64-Architekturen (Graviton2). Sie können die gewünschte Architektur frei wählen. Ihr Code und Ihr Bereitstellungsprozess ändern sich nicht.

Da Lambda ein Serverless-Service ist, zahlen Sie nur für das, was Sie nutzen. Wenn Ihre Lambda-Funktion ein paar Mal am Tag ausgeführt werden muss, ist das alles, wofür Sie bezahlen. Sie kann aber an Ihre Bedürfnisse angepasst werden und auch tausend Instances gleichzeitig starten!

 Veranschlagte Zeit

60 Minuten 

Preise

Wie oben erwähnt, zahlen Sie nur für das, was Sie nutzen. Der Betrag, den Sie zahlen, wird auf der Grundlage der Dauer der Ausführung Ihrer Lambda-Funktion (aufgerundet auf die nächste Millisekunde) und der Speichermenge, die Sie der Funktion zugewiesen haben, berechnet.

Denken Sie daran, dass bei der Preisberechnung die Menge des zugewiesenen Speichers verwendet wird, nicht die Menge, die während eines Aufrufs verwendet wird. Aus diesem Grund lohnt es sich, Ihre Funktionen zu testen, um zu ermitteln, wie viel Speicher sie während eines Aufrufs maximal beanspruchen. Wenn Sie den zugewiesenen Speicher auf die niedrigste erforderliche Menge beschränken, können Sie die Kosten für die Verwendung von Lambda-Funktionen senken. Weitere Informationen finden Sie auf der Seite der AWS-Lambda-Preise.

Wenn Ihre Lambda-Funktion andere Services wie S3 oder Kinesis verwendet, auch für diese Services Gebühren anfallen können.

Unterstützte Versionen von .NET

Es gibt eine Vielzahl von Möglichkeiten, .NET-Binärdateien auf der Lambda-Plattform auszuführen. Die häufigste und die, die zuerst in Betracht gezogen werden sollte, ist die Verwendung einer verwalteten Laufzeit, die von AWS bereitgestellt wird. Das ist der einfachste und bequemste Einstieg, der auch die beste Leistung bietet. Wenn Sie die verwaltete Laufzeit nicht verwenden möchten oder können, haben Sie zwei andere Möglichkeiten: eine benutzerdefinierte Laufzeit oder ein Container-Image. Beide Optionen haben ihre eigenen Vor- und Nachteile und werden im Folgenden näher erörtert.

Verwaltete Laufzeiten

Der AWS-Lambda-Service bietet eine Vielzahl beliebter Laufzeiten, auf denen Sie Ihren Code ausführen können. In Bezug auf die .NET-Laufzeiten hält AWS die Laufzeit auf dem neuesten Stand und aktualisiert sie bei Bedarf mit den neuesten von Microsoft verfügbaren Versionen. Sie als Entwickler müssen in Bezug auf die Verwaltung der Laufzeit, die Ihr Code verwenden wird, nichts weiter tun, als die Version, die Sie verwenden möchten, in Ihrer vertrauten .csproj-Datei anzugeben.

Derzeit bietet AWS nur verwaltete Laufzeiten für Long Term Support (LTS)-Versionen der NET-Laufzeit an, d. h. .NET 3.1 und.NET 6. Die verwalteten.NET-Laufzeiten sind sowohl für x86_64- als auch für arm64-Architekturen verfügbar und werden in Amazon Linux 2 ausgeführt. Wenn Sie eine andere Version von .NET als die von AWS angebotenen verwenden möchten, können Sie Ihre eigene benutzerdefinierte Laufzeit erstellen oder ein Container-Image erstellen, das Ihren Anforderungen entspricht.

Wenn Sie daran interessiert sind, die .NET-Welt zu verlassen, ist es gut zu wissen, dass der Lambda-Service auch verwaltete Laufzeiten für andere Sprachen anbietet, wie Node.js, Python, Ruby, Java und Go. Vollständige Informationen zur Liste der verwalteten Laufzeiten und Versionen der unterstützten Sprachen finden Sie auf dieser Seite zu verfügbaren Laufzeiten.

Benutzerdefinierte Laufzeiten

Benutzerdefinierte Laufzeiten sind Laufzeiten, die Sie selbst erstellen und bündeln. Es gibt ein paar Gründe, warum Sie das tun würden. In den meisten Fällen möchten Sie eine Version von .NET verwenden, die vom Lambda-Service nicht als verwaltete Laufzeit angeboten wird. Ein weiterer, seltenerer Grund wäre, wenn Sie eine genaue Kontrolle über die Neben- und Patch-Versionen der Laufzeit haben möchten.

Das Erstellen der benutzerdefinierten Laufzeit ist von Ihrer Seite mit nur wenig Aufwand verbunden. Sie müssen dafür nur Folgendes tun:

--self-contained entspricht dem Build-Befehl.

Dies kann direkt mit dotnet build erfolgen. Sie können dies auch über die Datei aws-lambda-tools-defaults.json mit dem folgenden Parameter tun:

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

Das ist alles, ein einfaches Compiler-Flag beim Bündeln der Lambda-Funktion. Das bereitzustellende Paket enthält jetzt Ihren Code sowie die erforderlichen Dateien aus der ausgewählten .NET-Laufzeit.

Es liegt nun an Ihnen, die Laufzeit nach Belieben zu patchen und zu aktualisieren. Um die Laufzeit zu aktualisieren, müssen Sie die Funktion erneut bereitstellen, da der Funktionscode und die Laufzeit zusammen verpackt sind.

Das bereitgestellte Paket ist im Vergleich zur verwalteten Laufzeit deutlich größer, da es alle erforderlichen Laufzeitdateien enthält. Dies wirkt sich negativ auf die Kaltstartzeiten aus (dazu später mehr). Um diese Größe zu reduzieren, sollten Sie die .NET-Kompilierungsfunktionen Trimming und ReadyToRun verwenden. Bitte lesen Sie jedoch vorher die Dokumentation zu diesen Funktionen.

Sie können eine benutzerdefinierte Laufzeit mit jeder Version von .NET erstellen, die in Linux läuft. Ein häufiger Anwendungsfall ist die Bereitstellung von Funktionen mit den „aktuellen“ Versionen oder Vorschauversionen von.NET.

Wenn Sie benutzerdefinierte Laufzeiten verwenden, können Sie eine Vielzahl von Sprachen verwenden, die von der Community angeboten werden. Oder erstellen Sie sogar Ihre eigene benutzerdefinierte Laufzeit, wie es andere getan haben, um Sprachen wie Erlang und COBOL auszuführen.

Container-Images

Neben der verwalteten Laufzeit und der benutzerdefinierten Laufzeit bietet Ihnen der AWS-Lambda-Service auch die Möglichkeit, Ihren Code in ein Container-Image zu packen und dieses Image für den Lambda-Service bereitzustellen. Die Option eignet sich für Teams, die Zeit in die Erstellung und Bereitstellung ihres Codes in Containern investiert haben, oder für Teams, die mehr Kontrolle über das Betriebssystem und die Umgebung benötigen, in der der Code ausgeführt wird. Images mit einer Größe von bis zu 10 GB werden unterstützt.

AWS bietet eine Vielzahl von Basis-Images für .NET und .NET Core. https://gallery.ecr.aws/lambda/dotnet, mit diesen können Sie sehr schnell loslegen.

Eine andere Möglichkeit besteht darin, ein benutzerdefiniertes Image speziell für Ihre Funktion zu erstellen. Dies ist ein fortgeschrittenerer Anwendungsfall und setzt voraus, dass Sie das Dockerfile an Ihre Bedürfnisse anpassen. Dieser Ansatz wird in diesem Kurs nicht behandelt, aber wenn Sie diesen Pfad einschlagen, schauen Sie sich die Dockerfiles in diesem Repository an: https://github.com/aws/aws-lambda-dotnet/tree/master/LambdaRuntimeDockerfiles/Images.

Beachten Sie, dass die Aktualisierung Ihrer Lambda-Funktion bei Containern aufgrund der Größe des Uploads am langsamsten ist. Container bieten auch die schlechtesten Kaltstarts der drei Optionen. Mehr dazu später im Modul.

Die passende Laufzeit für Sie auswählen

Wenn Sie die beste Startleistung, eine einfache Bereitstellung und einen einfachen Einstieg wünschen und gerne bei den LTS-Versionen von .NET bleiben, entscheiden Sie sich für verwaltete .NET-Laufzeiten.

Container-Images sind eine großartige Option, mit der Sie Images verwenden können, die AWS für eine Vielzahl von .NET-Versionen erstellt hat. Oder Sie können Ihr eigenes Container-Image auswählen und das Betriebssystem und die Umgebung, in der der Code ausgeführt wird, optimieren. Container-Images eignen sich auch für Organisationen, die Container bereits ausgiebig verwenden.

Wenn Sie sehr spezifische Anforderungen an die Versionen von .NET und seinen Laufzeitbibliotheken haben und diese selbst steuern möchten, sollten Sie die Verwendung einer benutzerdefinierten Laufzeit in Betracht ziehen. Beachten Sie jedoch, dass es an Ihnen liegt, die Laufzeit zu pflegen und zu patchen. Wenn Microsoft ein Sicherheitsupdate veröffentlicht, müssen Sie das wissen und Ihre benutzerdefinierte Laufzeit entsprechend aktualisieren. In Bezug auf Leistung ist die benutzerdefinierte Laufzeit von diejenige der drei, die am langsamsten gestartet wird.

Sobald Ihre Lambda-Funktion gestartet wurde, wird die Leistung der verwalteten Laufzeit, des Container-Images und der benutzerdefinierten Laufzeit sehr ähnlich sein.

AWS SDK für .NET

Wenn Sie .NET-Anwendungen entwickelt haben, die AWS-Services verwenden, haben Sie wahrscheinlich das AWS SDK für .NET verwendet. Mit dem SDK kann .NET-Entwickler ganz einfach AWS-Services auf konsistente und vertraute Weise aufrufen. Das SDK wird auf dem neuesten Stand gehalten, wenn Services veröffentlicht oder aktualisiert werden. Das SDK kann von NuGet heruntergeladen werden.

Wie bei vielen Elementen rund um AWS ist das SDK in kleinere Pakete aufgeteilt, die sich jeweils mit einem einzelnen Service befassen.

Wenn Sie beispielsweise von Ihrer .NET-Anwendung aus auf S3-Buckets zugreifen möchten, verwenden Sie das NuGet-Paket AWSSDK.S3. Oder wenn Sie von Ihrer .NET-Anwendung aus auf DynamoDB zugreifen möchten, verwenden Sie das NuGet-Paket AWSSDK.DynamoDBv2.

Sie fügen jedoch nur die NuGet-Pakete hinzu, die Sie benötigen. Indem Sie das SDK in kleinere Pakete aufteilen, bleibt Ihr eigenes Bereitstellungspaket kleiner.

Wenn Ihr Lambda-Funktions-Handler Ereignisse von anderen AWS-Services empfangen muss, suchen Sie nach bestimmten ereignisbezogenen NuGet-Paketen. Sie enthalten die relevanten Typen für die Behandlung der Ereignisse. Die Pakete folgen dem Benennungsmuster von AWSSDK.Lambda. [SERVICE]Events.

Wenn Ihre Lambda-Funktion beispielsweise ausgelöst wird durch:

eingehende S3-Ereignisse, verwenden Sie das Paket AWSSDK.Lambda.S3Events

eingehende Kinesis-Ereignisse, verwenden Sie das Paket AWSSDK.Lambda.KinesisEvents

Für eingehende SNS-Benachrichtigungen verwenden Sie das Paket AWSSDK.Lambda.SNSEvents

eingehende SQS-Nachrichten, verwenden Sie das Paket AWSSDK.Lambda.SQSEvents

Die Verwendung des SDK für die Interaktion mit AWS-Services ist sehr einfach. Fügen Sie Ihrem Projekt einen Verweis auf das NuGet-Paket hinzu und rufen Sie den Service dann wie jede andere .NET-Bibliothek auf, die Sie möglicherweise verwenden würden.

Dass Sie das SDK von einer Lambda-Funktion aus verwenden, hat keinen Einfluss darauf, wie Sie es verwenden.

Denken Sie daran, dass Sie Ihrem Projekt nicht unbedingt AWS-SDK-NuGet-Pakete hinzufügen müssen. Wenn Ihre Lambda-Funktion beispielsweise einen AWS RDS SQL Server aufruft, können Sie einfach Entity Framework verwenden, um auf die Datenbank zuzugreifen. Es sind keine zusätzlichen AWS-spezifischen Bibliotheken erforderlich. Wenn Sie jedoch einen Benutzernamen/ein Passwort für die Datenbank von Secrets Manager abrufen möchten, müssen Sie das NuGet-Paket AWSSDK.SecretsManager hinzufügen.

Ein Hinweis zu Berechtigungen

In der Regel sollten Sie die niedrigste Berechtigungsebene verwenden, die für die Ausführung einer Aufgabe erforderlich ist. Während dieses Kurses werden Sie dazu angehalten und erfahren, wie das geht.

Der Einfachheit halber empfehlen wir jedoch, dass Sie einen AWS-Benutzer mit angehängter AdministratorAccess-Richtlinie verwenden. Mit dieser Richtlinie können Sie die Rollen erstellen, die für die Bereitstellung von Lambda-Funktionen erforderlich sind. Wenn Sie nicht an dem Kurs arbeiten, sollten Sie diese Richtlinie von Ihrem AWS-Benutzer entfernen.

Eine .NET-Lambda-Funktion im „Hello World“-Stil

Wie Sie in einem früheren Modul gesehen haben, ist es sehr einfach, eine .NET-Lambda-Funktion zu erstellen, bereitzustellen und aufzurufen. In diesem Abschnitt werden Sie dasselbe tun, aber langsamer, und ich werde erklären, was bei jedem Schritt passiert. Der generierte Code und die Konfigurationsdateien werden ebenfalls präsentiert.

Die Funktion erstellen

Sie müssen hierfür die erforderlichen Tools installieren. Weitere Informationen dazu finden Sie in Modul 3.

Wenn Sie jetzt nicht dorthin springen möchten, finden Sie hier eine kurze Erinnerung.

Installieren Sie die .NET Lambda-Funktionsvorlagen:

dotnet new -i Amazon.Lambda.Templates

Installieren Sie das .NET-Tool für die Bereitstellung und Verwaltung von Lambda-Funktionen:

dotnet tool install -g Amazon.Lambda.Tools

Nachdem Sie die Vorlagen installiert haben, können Sie eine neue Funktion erstellen

Führen Sie in der Befehlszeile Folgendes aus:

dotnet new lambda.EmptyFunction -n HelloEmptyFunction

Dadurch wird ein neues Verzeichnis namens „HelloEmptyFunction“ erstellt. Darin befinden sich zwei weitere Verzeichnisse, src und test. Wie die Namen schon vermuten lassen, enthält das src-Verzeichnis den Code für die Funktion, und das test-Verzeichnis enthält die Modultests für die Funktion. Wenn Sie in diese Verzeichnisse navigieren, werden Sie feststellen, dass sie jeweils ein anderes Verzeichnis enthalten. In diesen Unterverzeichnissen befinden sich die Codedateien für die Funktion und die Modultestdateien.

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

Schauen wir uns zuerst die Datei Function.cs an.

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();
    }
}

Einige Anmerkungen zu den Zeilen, die einer kleinen Erklärung bedürfen:

Zeile 4 ermöglicht die Konvertierung der JSON-Eingabe in eine .NET-Klasse.

Zeile 17, die JSON-Eingabe für die Funktion wird in eine Zeichenfolge umgewandelt.

In Zeile 17 wird ein ILambdaContext-Objekt als Parameter übergeben. Dieses kann für die Protokollierung verwendet werden, um den Namen der Funktion, die Dauer der Ausführung der Funktion und andere Informationen zu ermitteln.

Wie Sie sehen, ist der Code sehr einfach und sollte jedem bekannt sein, der mit C# gearbeitet hat.

Obwohl die FunctionHandler-Methode hier synchron ist, können Lambda-Funktionen wie jede andere .NET-Methode asynchron sein. Dafür ändern Sie den FunctionHandler zu

public async Task<string> FunctionHandler(..)

Schauen wir uns die Datei aws-lambda-tools-defaults.json an:

{
  "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"
}

Zeile 10 gibt an, dass die Funktion in der Release-Konfiguration gebaut werden soll.

Zeile 11 gibt dem Lambda-Service an, welche Laufzeit verwendet werden soll.

Zeile 12 gibt an, wie viel Speicher der Funktion zugewiesen werden soll, in diesem Fall 256 MB.

Zeile 13 gibt den Timeout für die Funktion an, in diesem Fall 30 Sekunden. Die maximal zulässige Timeout-Zeit beträgt 15 Minuten.

Zeile 14 gibt den Funktionshandler an. Das ist die Methode, die vom Lambda-Service aufgerufen wird, wenn diese Funktion aufgerufen wird.

Der Funktionshandler besteht aus drei Teilen:

"AssemblyName::Namespace.ClassName::MethodName"

In Kürze werden Sie diese Funktion erstellen und mithilfe der Konfiguration in dieser Datei für den AWS-Lambda-Service bereitstellen.

Aber zuerst schauen wir uns das Testprojekt und seine HelloEmptyFunction.Tests.cs-Datei an:

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);
    }
}

Der Code hier ist relativ einfach und verwendet das xUnit-Testframework. Sie können Ihre Lambda-Funktionen genauso testen, wie Sie jede andere Methode testen würden.

Zeile 14 erstellt eine neue Instance der Function-Klasse.

Zeile 15 erstellt eine neue Instance der TestLambdaContext-Klasse. Diese wird in der nächsten Zeile an die Lambda-Funktion übergeben.

Zeile 16 ruft die FunctionHandler-Methode für die Funktion auf und übergibt die Zeichenfolge „hello world“ und den Kontext. Sie speichert die Antwort in der upperCase-Variablen.

Zeile 18 erklärt, dass die upperCase-Variable „HELLO WORLD“ entspricht.

Sie können diesen Test über die Befehlszeile oder in Ihrer bevorzugten IDE ausführen. Es gibt andere Arten von Tests, die mit Lambda-Funktionen durchgeführt werden können. Wenn Sie mehr darüber erfahren möchten, lesen Sie bitte ein späteres Modul, in dem Sie eine Vielzahl von Möglichkeiten zum Testen und Debuggen Ihrer Lambda-Funktionen kennenlernen werden.

Bereitstellung der Funktion

Nachdem Sie nun eine Lambda-Funktion haben und möglicherweise einen Modultest ausgeführt haben, ist es an der Zeit, die Lambda-Funktion für den AWS-Lambda-Service bereitzustellen.

Navigieren Sie von der Befehlszeile aus zu dem Verzeichnis, das die Datei HelloEmptyFunction.csproj enthält, und führen Sie den folgenden Befehl aus:

dotnet lambda deploy-function HelloEmptyFunction  

Sie werden eine Ausgabe sehen, die Folgendes enthält (ich habe sie aus Gründen der Übersichtlichkeit gekürzt):

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

Zeile 1 kompiliert und veröffentlicht das Projekt. Beachten Sie, dass die Laufzeit linux-x64 ist und das eigenständige Flag falsch sind. (Das bedeutet, dass die Funktion die verwaltete .NET-Laufzeit auf dem Lambda-Service verwendet, im Gegensatz zu einer benutzerdefinierten Laufzeit).

Zeile 2: Komprimiert das veröffentlichte Projekt in eine ZIP-Datei.

In den Zeilen 3-8 werden die Dateien angezeigt, die komprimiert werden.

Zeile 9 bestätigt, dass die Zip-Datei erstellt wurde.

Als Nächstes werden Sie gefragt: „Select IAM Role that to provide AWS credentials to your code:“ (Wählen Sie eine IAM-Rolle aus, um AWS-Anmeldeinformationen für Ihren Code bereitzustellen:). Möglicherweise wird Ihnen eine Liste der Rollen angezeigt, die Sie zuvor erstellt haben, aber am Ende der Liste befindet sich die Option „*** Create new IAM Role ***“ (*** Neue IAM-Rolle erstellen***). Geben Sie die Zahl neben dieser Option ein.

Sie sehen die Aufforderung „Enter name of the new IAM Role“ (Namen der neuen IAM-Rolle einzugeben). Geben Sie „HelloEmptyFunctionRole“ ein.

Sie sehen dann die Aufforderung „Select IAM Policy to attach to the new role and grant permissions“ (IAM-Richtlinie auszuwählen, um sie an die neue Rolle anzuhängen und Berechtigungen zu gewähren), und eine Liste der Richtlinien wird angezeigt. Das wird wie folgt aussehen, Ihre Liste kann aber länger sein:

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

Wählen Sie „AWSLambdaBasicExecutionRole“, das ist Nummer 6 auf meiner Liste.

Nach einem Moment sehen Sie Folgendes:

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

Jetzt können Sie die Funktion aufrufen.

Aufrufen der Funktion

Befehlszeile

Sie können das dotnet-Lambda-Tool verwenden, um die Funktion von der Shell Ihrer Wahl aus aufzurufen:

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

Bei einfachen Lambda-Funktionen wie die oben genannten ist kein JSON-Escaping erforderlich, aber wenn Sie ein deserialisiertes Element in JSON übergeben möchten, variiert das Escaping der Nutzlast je nach verwendeter Shell.

Sie werden eine Ausgabe sehen, die wie folgt aussieht:

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

Die Ausgabe „Payload:“ ist die Antwort der Lambda-Funktion.

Beachten Sie, dass der Log-Tail nützliche Informationen über den Lambda-Funktionsaufruf enthält, z. B. wie lange er ausgeführt wurde und wie viel Speicher verwendet wurde. Für eine einfache Funktion wie diese mögen 244,83 ms viel erscheinen, aber dies war das erste Mal, dass die Funktion aufgerufen wurde, was bedeutet, dass mehr Arbeit ausgeführt werden musste, nachfolgende Aufrufe wären schneller gewesen. Weitere Informationen finden Sie im Abschnitt über Kaltstarts.

Wir nehmen jetzt eine kleine Änderung am Code vor, um einige unserer eigenen Protokollanweisungen hinzuzufügen.

Fügen Sie über der Rückgabeanweisung in der FunctionHandler-Methode Folgendes hinzu:

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

Stellen Sie erneut bereit mit:

dotnet lambda deploy-function HelloEmptyFunction

Dieses Mal wird es keine Fragen zu Rollen oder Berechtigungen geben.

Nachdem die Funktion bereitgestellt wurde, können Sie sie erneut aufrufen.

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

Dieses Mal wird die Ausgabe eine zusätzliche Protokollanweisung enthalten.

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

Dort, in Zeile 6, befindet sich die Protokollanweisung. Lambda-Funktion-Protokolle werden auch in CloudWatch-Protokolle geschrieben (vorausgesetzt, Sie haben der Lambda-Funktion die entsprechenden Berechtigungen erteilt).

AWS-Konsole

Eine andere Möglichkeit, die Funktion aufzurufen, ist die AWS-Konsole.

Melden Sie sich bei der AWS-Konsole an und wählen Sie die Lambda-Funktion aus, die Sie aufrufen möchten.

Klicken Sie auf die Registerkarte „Test“.

Scrollen Sie nach unten zum Abschnitt Event JSON und geben Sie „Invoking a Lambda function“ (Eine Lambda-Funktion aufrufen) ein, einschließlich der Anführungszeichen.

Klicken Sie dann auf die Schaltfläche „Test“ (Testen).

Sie werden eine Ausgabe ähnlich der folgenden sehen.

Beachten Sie, dass die Protokollausgabe ebenfalls sichtbar ist.

Eine .NET-Lambda-Funktion, die eine JSON-Nutzlast akzeptiert

Das vorherige Beispiel war eine einfache Funktion, die eine Zeichenfolge nahm und eine Zeichenfolge zurückgab. Es ist ein gutes Beispiel für den Einstieg.

Aber Sie werden wahrscheinlich JSON-Nutzlasten an Lambda-Funktionen senden wollen. Wenn ein anderer AWS-Service Ihre Lambda-Funktion aufruft, sendet er sogar eine JSON-Nutzlast. Diese JSON-Nutzlasten sind oft ziemlich komplex, aber ein Modell für die Nutzlast wird von NuGet verfügbar sein. Wenn Sie beispielsweise Kinesis-Ereignisse mit Ihrer Lambda-Funktion behandeln, verfügt das Amazon.Lambda.KinesisEvents-Paket über ein KinesisEvent-Modell. Das Gleiche gilt für S3-Ereignisse, SQS-Ereignisse usw.

Anstatt jetzt eines dieser Modelle zu verwenden, rufen Sie eine neue Lambda-Funktion mit einer Nutzlast auf, die eine Person darstellt.

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

Die entsprechende C#-Klasse zur Deserialisierung der JSON-Nutzlast lautet:

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

Die Funktion erstellen

Erstellen Sie wie zuvor eine neue Funktion mit dem folgenden Befehl:

dotnet new lambda.EmptyFunction -n HelloPersonFunction

Ändern Sie die Funktion

Navigieren Sie zur Datei Function.cs in HelloPersonFunction/src/HelloPersonFunction.

Ändern Sie den Code der FunctionHandler-Methode so, dass er wie folgt aussieht:
public string FunctionHandler(Person input, ILambdaContext context)
{
    return $"Hello, {input.FirstName} {input.LastName}";
}
Fügen Sie am Ende der Datei eine neue Klasse hinzu:
public class Person 
{
    public string FirstName { get; init; }
    public string LastName { get; init; }  
}

Dies ist derselbe Befehl, den Sie vor ein paar Minuten verwendet haben:

Dies ist derselbe Befehl, den Sie vor ein paar Minuten verwendet haben:
dotnet lambda deploy-function HelloPersonFunction

Die Funktion aufrufen

Befehlszeile
 

Jetzt kann Ihre Lambda-Funktion eine JSON-Nutzlast annehmen, aber wie Sie sie aufrufen, hängt von der Shell ab, die Sie verwenden, da JSON in jeder Shell maskiert wird.

Wenn Sie PowerShell oder Bash verwenden, verwenden Sie Folgendes:

dotnet lambda invoke-function HelloPersonFunction --payload '{ \"FirstName\": \"Alan\", \"LastName\": \"Adams\" }'
Wenn Sie jedoch die Windows-Eingabeaufforderung verwenden, verwenden Sie Folgendes:
dotnet lambda invoke-function HelloPersonFunction --payload "{ \"FirstName\": \"Alan\", \"LastName\": \"Adams\" }"
Dies ist nur ein einfaches Beispiel. Aber natürlich kann JSON so komplex wie nötig sein.
AWS-Konsole
 
Eine andere Möglichkeit, die Funktion aufzurufen, ist die AWS-Konsole.

Melden Sie sich bei der AWS-Konsole an und wählen Sie die Lambda-Funktion aus, die Sie aufrufen möchten.
Klicken Sie auf die Registerkarte „Test“.
Scrollen Sie nach unten zum Abschnitt „Event JSON“ (Ereignis-JSON) und geben Sie Folgendes ein:
{
  "FirstName": "Alan",
  "LastName": "Adams"
}
Klicken Sie dann auf die Schaltfläche „Test“ (Testen).

Sie werden eine Ausgabe ähnlich der folgenden sehen.
Die letzten Beispiele waren ziemlich einfach, und die Lambda-Funktion hat keine anderen AWS-Services verwendet, aber sie sind eine gute Möglichkeit, um loszulegen und sich mit dem AWS-Lambda-Service vertraut zu machen, Lambda-Funktionen zu schreiben, kompilierte Pakete bereitzustellen und die Funktionen aufzurufen.

Im nächsten Abschnitt erfahren Sie, wie Sie eine Lambda-Funktion bereitstellen, die auf HTTP-Anfragen reagiert.

Erstellen und Ausführen einer Web-API-Anwendung als Lambda-Funktion

In den vorherigen Beispielen wurden die Lambda-Funktionen alle über die Befehlszeile oder in der Testfunktion des Lambda-Services in der AWS-Konsole aufgerufen.

Sie können die Lambda-Funktion aber auch über eine HTTP-Anfrage aufrufen, was ein sehr häufiger Anwendungsfall ist.

Die AWS-Tools für .NET bieten einige Vorlagen, mit denen Sie eine einfache Lambda-Funktion erstellen können, die eine Web-API-Anwendung hostet.

Die bekannteste Vorlage wird wahrscheinlich die Serverless.AspNetCoreWebAPI-Vorlage sein. Dadurch wird eine einfache Web-API-Anwendung erstellt, die über eine HTTP-Anfrage aufgerufen werden kann. Die Projektvorlage enthält eine CloudFormation-Konfigurationsvorlage, die ein API-Gateway erstellt, das HTTP-Anfragen an die Lambda-Funktion weiterleitet.

Bei der Bereitstellung in AWS Lambda übersetzt das API-Gateway die HTTP-Anfrage in ein API-Gateway-Ereignis und sendet diesen JSON an die Lambda-Funktion. In der Lambda-Funktion wird kein Kestrel-Server ausgeführt, wenn sie für den Lambda-Server bereitgestellt wird.

Wenn Sie sie jedoch lokal ausführen, wird ein Kestrel-Webserver gestartet. Dadurch ist es sehr einfach, Ihren Code zu schreiben und ihn in einer vertrauten Web-API-Anwendung zu testen. Sie können sogar das normale zeilenweise Debugging durchführen. Sie erhalten das Beste aus beiden Welten!

Die Funktion erstellen

Führen Sie in der Befehlszeile den folgenden Befehl aus:
dotnet new serverless.AspNetCoreWebAPI -n HelloAspNetCoreWebAPI
Dadurch wird ein neues Verzeichnis namens HelloAspNetCoreWebAPI erstellt. Darin befinden sich zwei weitere Verzeichnisse, src und test. Wie die Namen schon vermuten lassen, enthält das src-Verzeichnis den Code für die Funktion, und das test-Verzeichnis enthält die Modultests für die Funktion. Wenn Sie in diese Verzeichnisse navigieren, werden Sie feststellen, dass sie jeweils ein anderes Verzeichnis enthalten. In diesen Unterverzeichnissen befinden sich die Codedateien für die Funktion und die Modultestdateien.
├───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

Die Funktion bereitstellen

Die Bereitstellung einer Funktion, die auf einer serverless.*-Vorlage basiert, ist etwas aufwändiger als die Bereitstellung einer Funktion, die auf einer lambda.*-Vorlage basiert.

Bevor Sie versuchen, die Serverless-Funktion bereitzustellen, benötigen Sie einen S3-Bucket. Dieser wird von den Bereitstellungstools verwendet, um einen CloudFormation-Stack zu speichern.

Sie können einen vorhandenen S3-Bucket oder, falls Sie keinen haben, die folgenden Anweisungen verwenden.
Den S3-Bucket erstellen
 
Wenn Sie die Region us-east-1 verwenden, können Sie den folgenden Befehl verwenden, um den Bucket zu erstellen:
aws s3api create-bucket --bucket your-unique-bucket-name1234 
Wenn Sie eine andere Region verwenden
aws s3api create-bucket --bucket your-unique-bucket-name1234 --create-bucket-configuration LocationConstraint=REGION
Ich habe in us-east-1 einen Bucket mit dem Namen lambda-course-2022 erstellt.
aws s3api create-bucket --bucket lambda-course-2022 
Zurück zur Bereitstellung der Funktion
 
Jetzt, da Sie einen S3-Bucket haben, können Sie den Bereitstellungsbefehl ausführen:
dotnet lambda deploy-serverless
Sie werden aufgefordert, einen CloudFormation-Stack-Namen einzugeben.
Enter CloudFormation Stack Name: (CloudFormation stack name for an AWS Serverless application)
Geben Sie AspNetCoreWebAPI ein

Sie werden dann nach dem S3-Bucket-Namen gefragt. Verwenden Sie den Namen des Buckets, den Sie zuvor erstellt haben, oder eines vorhandenen Buckets, den Sie für diesen Zweck verwenden möchten.

Nachdem Sie ihn eingegeben haben, beginnt der Erstellungs- und Bereitstellungsprozess.

Dies wird länger dauern als die Beispiele, die lambda.*-Projektvorlagen verwenden, da mehr Infrastruktur erstellt und angeschlossen werden muss.

Die Ausgabe wird in zwei verschiedene Abschnitte aufgeteilt.

Der obere Abschnitt wird dem ähneln, was Sie zuvor bei der Bereitstellung von Funktionen gesehen haben, eine Veröffentlichung und eine ZIP-Datei des Projekts, aber dieses Mal wird das Artefakt in S3 hochgeladen.
..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%
Danach wird der CloudFormation-Stack erstellt und alle erforderlichen Ressourcen werden bereitgestellt.
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/

Ganz unten befindet sich die öffentliche URL, mit der Sie die API aufrufen können.

Aufrufen der Funktion

Wenn Sie diese URL in Ihrem Browser oder Fiddler/Postman usw. öffnen, wird eine Antwort wie „Welcome to running ASP.NET Core on AWS Lambda“ (Willkommen beim Ausführen von ASP.NET Core auf AWS Lambda) angezeigt.

Versuchen Sie dann, https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/Prod/api/values zu öffnen. Sie rufen die GET-Methode des Werte-Controllers auf, genau wie in einer normalen Web-API-Anwendung.

Beachten Sie, dass bei Verwendung eines API-Gateways das Gateway ein eigenes Timeout von 29 Sekunden festlegt. Wenn Ihre Lambda-Funktion länger läuft, erhalten Sie keine Antwort.

Wenn Sie interessiert sind, gibt es verschiedene Möglichkeiten, die erstellten Ressourcen zu überprüfen.

Um die erstellten AWS-Ressourcen zu überprüfen, können Sie Folgendes verwenden:
aws cloudformation describe-stack-resources --stack-name AspNetCoreWebAPI
Dadurch erhalten Sie Details zu jeder Ressource im Stack.

Wenn Sie eine prägnantere Ausgabe wünschen, verwenden Sie Folgendes:
aws cloudformation describe-stack-resources --stack-name AspNetCoreWebAPI --query 'StackResources[].[{ResourceType:ResourceType, LogicalResourceId:LogicalResourceId, PhysicalResourceId:PhysicalResourceId}]'
Eine andere Möglichkeit besteht darin, die AWS-Konsole zu öffnen und zum Lambda-Service zu navigieren. Wählen Sie auf der linken Seite des Bildschirms „Application“ (Anwendung) (statt „Functions“ [Funktionen]) aus.


Sie werden die Anwendung sehen, die Sie erstellt haben. Wählen Sie sie aus und scrollen Sie dann zum Ende der sich öffnenden Seite. Sie werden alle Ressourcen sehen, die hier erstellt wurden.
Sie haben jetzt drei Beispiele für Lambda-Funktionen gesehen, die erste war eine einfache „Hello World“, die eine Zeichenfolge benötigte, die zweite war ebenfalls sehr einfach, nahm aber ein JSON-Objekt, und die dritte war etwas komplexer, aber immer noch sehr einfach zu erstellen und bereitzustellen.

Mit diesen Beispielen können Sie Ihre eigenen Lambda-Funktionen erstellen und bereitstellen. Und vielleicht haben Sie ein wenig darüber erfahren, wie .NET-Lambda-Funktionen aufgerufen werden. Das ist das Thema des nächsten Abschnitts.

Funktions-URLs – eine Alternative zu API Gateways

Wenn Sie lediglich eine Lambda-Funktion benötigen, die auf eine einfache HTTP-Anfrage reagiert, sollten Sie die Verwendung von Lambda-Funktions-URLs in Betracht ziehen.

Sie ermöglichen es Ihnen, einer Lambda-Funktion einen HTTPS-Endpunkt zuzuweisen. Anschließend rufen Sie die Lambda-Funktion auf, indem Sie eine Anfrage an den HTTPS-Endpunkt stellen. Weitere Informationen finden Sie in diesem Blog-Beitrag sowie in diesen Dokumentationen.

Bereinigen der Ressourcen, die Sie erstellt haben

Wenn Sie die Lambda-Funktion löschen möchten, führen Sie Folgendes aus:
dotnet lambda delete-function HelloEmptyFunction  
dotnet lambda delete-function HelloPersonFunction

Beachten Sie, dass die obigen Befehle die von Ihnen erstellte Rolle nicht löschen.

Um die Lambda-Funktion, die die Web-API-Anwendung hostete, und alle zugehörigen Ressourcen zu löschen, führen Sie Folgendes aus:

dotnet lambda delete-serverless AspNetCoreWebAPI

So wird eine .NET-Lambda-Funktion aufgerufen

Wie Sie den obigen Beispielen entnehmen können, können Sie eine .NET-Lambda-Funktion mit einer einfachen Zeichenfolge, einem JSON-Objekt und einer HTTP-Anfrage aufrufen. Lambda-Funktionen können auch von anderen Services wie S3 (wenn eine Dateiänderung erfolgt), Kinesis (wenn ein Ereignis eintrifft), DynamoDB (wenn eine Änderung an einer Tabelle erfolgt), SMS (wenn eine Nachricht eintrifft), Step Functions usw. aufgerufen werden.

Wie geht eine Lambda-Funktion mit all diesen verschiedenen Arten von Aufrufen um?

Wenn man es genau betrachtet, werden diese Lambda-Funktionen aufgerufen, wenn der Lambda-Service den Funktionshandler ausführt und ihm eine JSON-Eingabe übergibt. Wenn Sie sich die aws-lambda-tools-defaults.json angesehen haben, können Sie den angegebenen „function-handler“: sehen. Für .NET-Lambda-Funktionen besteht der Handler aus „AssemblyName::Namespace.ClassName::MethodName“.

Lambda-Funktionen können auch aufgerufen werden, indem ihnen ein Stream übergeben wird. Dies ist jedoch ein weniger verbreitetes Szenario. Weitere Informationen finden Sie auf der Seite zum Umgang mit Streams.

Jede Lambda-Funktion hat einen einzelnen Funktionshandler.

Zusammen mit der JSON-Eingabe kann der Lambda-Funktionshandler auch ein optionales ILambdaContext-Objekt verwenden. Dadurch erhalten Sie Zugriff auf Informationen über den aktuellen Aufruf, z. B. die verbleibende Zeit, der Funktionsname und die Version. Sie können auch über das ILambdaContext-Objekt Protokollnachrichten schreiben.

Alle Ereignisse sind JSON

Ein AWS-Service kann so einfach eine.NET-Lambda-Funktion aufrufen, da diese Services JSON ausgeben und die .NET-Lambda-Funktion, wie oben beschrieben, JSON-Eingaben akzeptiert. Die von verschiedenen Services ausgelösten Ereignisse erzeugen alle unterschiedlich geformtes JSON, aber die Ereignis-NuGet-Pakete von AWS Lambda enthalten alle relevanten Objekttypen, die erforderlich sind, um den JSON wieder in ein Objekt zu serialisieren, mit dem Sie arbeiten können.

Unter https://www.nuget.org/packages?packagetype=&sortby=relevance&q=Amazon.Lambda&prerel=True finden Sie eine Liste der verfügbaren Lambda-Pakete. Sie müssen in diesen Ergebnissen nach dem Ereignistyp suchen, an dem Sie interessiert sind.

Wenn Sie beispielsweise eine Lambda-Funktion als Reaktion auf eine Dateiänderung in einem S3-Bucket auslösen möchten, müssen Sie eine Lambda-Funktion erstellen, die ein Objekt vom Typ S3Event akzeptiert. Anschließend fügen Sie das Amazon.Lambda.S3Events-Paket zu Ihrem Projekt hinzu. Ändern Sie dann die Funktionshandler-Methode zu:

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

Das ist alles, was Sie benötigen, um das S3-Ereignis handhaben. Sie können das Ereignis programmgesteuert untersuchen, sehen, welche Aktion für die Datei ausgeführt wurde, in welchem Bucket sie sich befand usw. Mit Amazon.Lambda.S3Events können Sie mit dem Ereignis arbeiten, nicht mit S3 selbst. Wenn Sie mit dem S3-Service interagieren möchten, müssen Sie Ihrem Projekt auch das NuGet-Paket AWSSDK.S3 hinzufügen. Ein späteres Modul wird sich mit AWS-Services befassen, die Lambda-Funktionen aufrufen.

Das gleiche Muster gilt für andere Ereignistypen. Fügen Sie das NuGet-Paket hinzu und ändern Sie den Parameter in den Funktionshandler, um mit dem Ereignisobjekt zu arbeiten.

Hier sind einige der gängigen Pakete, die Sie verwenden könnten, um Ereignisse von anderen Services zu behandeln:

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

Sie sind nicht auf die Verwendung von AWS-definierten Ereignistypen beschränkt, wenn Sie eine Lambda-Funktion aufrufen. Sie können jede Art von Ereignis selbst erstellen. Denken Sie daran, dass die Lambda-Funktion jedes JSON annehmen kann, das Sie an sie senden

So läuft die Serialisierung ab

Sie werden sich erinnern, dass es zwei große Kategorien von Lambda-Projektvorlagen gibt: einmal die, die mit „Lambda“ beginnen, und dann solche, die mit „serverless“ beginnen.

Bei den „lambda.“-Vorlagen befindet sich oben in der Datei Function.cs ein Assembly-Attribut, das in Ihrem Funktionshandler für die Deserialisierung des eingehenden Ereignisses in den .NET-Typ sorgt. In der csproj-Datei gibt es einen Verweis auf das Amazon.Lambda.Serialization.SystemTextJson-Paket.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
Sie müssen nichts weiter tun.

Bei den „serverless.“-Vorlagen sieht es etwas anders aus.

Der Funktionshandler ist in der Datei serverless.template angegeben. Wenn Sie eine serverless.AspNetCoreWebAPI-Anwendung bereitstellen, suchen Sie unter Resources.AspNetCoreFunction.Properties.Handler nach dem Wert. Der Handler für diesen Projekttyp hat das Format Assembly::Namespace.LambdaEntryPoint::FunctionHandlerAsync.

Die LambdaEntryPoint-Klasse befindet sich in Ihrem Projekt und erbt von einer Klasse, die über eine FunctionHandlerAsync-Methode verfügt.

Der Funktionshandler kann so eingestellt werden, dass er vier verschiedene Ereignistypen behandelt: eine API-Gateway-REST-API, eine API-Gateway-HTTP-API-Nutzlast Version 1.0, eine API-Gateway-HTTP-API-Nutzlast Version 2.0 und einen Application Load Balancer.

Indem Sie ändern, von welcher Klasse der LambdaEntryPoint erbt, können Sie ändern, welchen JSON-Ereignistyp der Funktionshandler verarbeitet.

Obwohl es so aussieht, als würde die Lambda-Funktion auf eine HTTP-Anfrage antworten, die Sie an sie senden, ist dies bei von Ihnen definiertem JSON nicht der Fall. In Wirklichkeit wird Ihre HTTP-Anfrage von einem Gateway oder Load Balancer verarbeitet, der dann ein JSON-Ereignis erstellt, das an Ihren Funktionshandler gesendet wird. Dieses JSON-Ereignis enthält die Daten, die ursprünglich in der HTTP-Anfrage enthalten waren, bis hin zur Quell-IP-Adresse und den Anforderungsheadern.

Nebenläufigkeit

Bei der Arbeit mit Lambda-Funktionen sind zwei Arten von Nebenläufigkeit zu berücksichtigen: reservierte Nebenläufigkeit und bereitgestellte Nebenläufigkeit.

Ein AWS-Konto hat standardmäßig ein maximales Limit für die Anzahl gleichzeitiger Lambda-Ausführungen. Zum jetzigen Zeitpunkt liegt diese Grenze bei 1.000.

Wenn Sie eine reservierte Nebenläufigkeit für eine Funktion angeben, garantieren Sie, dass die Funktion die angegebene Anzahl gleichzeitiger Ausführungen erreichen kann. Wenn Ihre Funktion beispielsweise eine reservierte Nebenläufigkeit von 200 hat, stellen Sie sicher, dass die Funktion 200 gleichzeitige Ausführungen erreichen kann. Beachten Sie, dass dadurch 800 gleichzeitige Ausführungen für andere Funktionen übrig bleiben (1000-200=800).

Wenn Sie bereitgestellte Nebenläufigkeit angeben, initialisieren Sie eine bestimmte Anzahl von Lambda-Ausführungsumgebungen. Wenn diese initialisiert sind, kann die Lambda-Funktion sofort auf Anfragen reagieren, wodurch das Problem von „Kaltstarts“ vermieden wird. Für die Nutzung der bereitgestellten Nebenläufigkeit fällt jedoch eine Gebühr an.

Weitere Informationen finden Sie unter Verwaltung der reservierten Nebenläufigkeit in Lambda und Verwaltung der bereitgestellten Parallelität in Lambda.

Kaltstarts und Warmstarts

Bevor Ihre Lambda-Funktion aufgerufen werden kann, muss eine Ausführungsumgebung initialisiert werden. Dies erfolgt in Ihrem Namen durch den Lambda-Service. Ihr Quellcode wird aus einem von AWS verwalteten S3-Bucket (für Funktionen, die verwaltete Laufzeiten verwenden, und benutzerdefinierte Laufzeiten) oder aus einer Elastic Container Registry (für Funktionen, die Container-Images verwenden) heruntergeladen.

Wenn Ihre Funktion zum ersten Mal ausgeführt wird, muss Ihr Code JITed sein, und der Initialisierungscode wird ausgeführt (z. B. Ihr Konstruktor). Dies erhöht die Kaltstartzeit.

Wenn Ihre Funktion regelmäßig aufgerufen wird, bleibt sie „warm“, d. h. die Ausführungsumgebung bleibt erhalten. Bei nachfolgenden Aufrufen der Funktion wird die Kaltstartzeit nicht beeinträchtigt. „Warmstarts“ sind deutlich schneller als „Kaltstarts“.

Wenn Ihre Funktion für einen bestimmten Zeitraum nicht aufgerufen wird (die genaue Zeit wird vom Lambda-Service nicht angegeben), wird die Ausführungsumgebung entfernt. Der nächste Aufruf der Funktion führt erneut zu einem Kaltstart.

Wenn Sie eine neue Version des Funktionscodes hochladen, führt der nächste Aufruf der Funktion zu einem Kaltstart.

Die drei Optionen für die Ausführung von .NET in Lambda, verwaltete Laufzeit, benutzerdefinierte Laufzeit und von Container gehostet, haben jeweils unterschiedliche Kaltstartprofile. Am langsamsten ist der Container, gefolgt von der benutzerdefinierten Laufzeit. Die verwaltete Laufzeit ist am schnellsten. Wenn möglich, sollten Sie sich immer für die verwaltete Laufzeit entscheiden, wenn Sie .NET-Lambda-Funktionen ausführen.

Es wurde festgestellt, dass Kaltstarts in Test- oder Entwicklungsumgebungen häufiger vorkommen als in Produktionsumgebungen. In einer AWS-Analyse treten Kaltstarts bei weniger als 1 % der Aufrufe auf.

Wenn Sie eine Lambda-Funktion in der Produktion haben, die selten verwendet wird, aber schnell auf eine Anfrage reagieren muss, und Sie Kaltstarts vermeiden möchten, können Sie die bereitgestellte Nebenläufigkeit verwenden oder einen Mechanismus verwenden, um Ihre Funktion häufig zu „pingen“ und so warm zu halten.

Wenn Sie an weiteren Informationen zur Optimierung Ihrer Lambda-Funktion interessiert sind, können Sie im AWS-Lambda-Entwicklerhandbuch mehr über Kaltstarts, Warmstarts und bereitgestellte Nebenläufigkeit lesen oder die Blogserie von James zur Leistungsoptimierung lesen: Teil 1, Teil 2 und Teil 3.

Trimming und Ready to Run für .NET-Versionen vor .NET 7

Wenn Sie sich dafür entschieden haben, benutzerdefinierte Lambda-Laufzeiten für eine Version von .NET vor .NET 7 zu verwenden, gibt es eine Reihe von .NET-Funktionen, mit denen Sie die Kaltstartzeiten reduzieren können.

PublishTrimmed reduziert die Gesamtgröße des Pakets, das Sie bereitstellen, indem nicht benötigte Bibliotheken aus dem Paket entfernt werden.

PublishReadyToRun führt eine Vorabkompilierung Ihres Codes durch und reduziert so den Umfang der Just-in-Time-Kompilierung, die erforderlich ist. Es erhöht jedoch die Größe des Pakets, das Sie bereitstellen.

Für eine optimale Leistung müssen Sie Ihre Funktion testen, wenn Sie diese Optionen verwenden.

PublishTrimmed und PublishReadyToRun können von Ihrer cspproj-Datei aus aktiviert werden.

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

Zusammenfassung

Dieses Modul hat Sie in das Erstellen, Bereitstellen und Aufrufen von .NET-Lambda-Funktionen eingeführt. Es gab Ihnen einen Überblick über die verschiedenen Möglichkeiten, .NET in AWS Lambda auszuführen, und befasste sich mit einigen der Gründen, warum Sie sich für die eine oder andere Methode entscheiden könnten. Es wurden auch Konzepte rund um den „Kaltstart“ und Optimierungen erklärt.


Native Ahead-of-Time-Kompilierung für .NET 7

NET 7, veröffentlicht im November 2022, unterstützt die native Ahead-of-Time (AOT)-Kompilierung. Mit den .NET-Vorlagentools für AWS Lambda können Sie benutzerdefinierte .NET 7-Laufzeitfunktionen erstellen und bereitstellen. In Tests haben Lambda-Funktionen für .NET 7 im Vergleich zu verwalteten Laufzeiten von .NET 6 bis zu 86 % schnellere Kaltstarts.
 
Um dieses neue Feature nutzen zu können, müssen Sie Ihre .NET-Lambda-Projektvorlagen auf Version 6.7.0 oder höher und die AWS-Erweiterungen für .NET auf Version 5.6.1 oder höher aktualisieren.
 
Um die Updates durchzuführen, führen Sie Folgendes aus:
dotnet new -i "Amazon.Lambda.Templates::*"dotnet tool update -g Amazon.Lambda.Tools
Zum Zeitpunkt der Erstellung dieses Artikels gibt es zwei Vorlagen für Lambda-AOT-Funktionen: lambda.NativeAOT und serverless.NativeAOT. Sie müssen auch Docker installieren und ausführen.

Wissensabfrage

Sie haben jetzt Modul 2, Tools für die .NET-Entwicklung mit AWS Lambda, abgeschlossen. Mit dem folgenden Test können Sie überprüfen, was Sie bisher gelernt haben.

1. Welche Versionen von verwalteten .NET-Laufzeiten bietet der Lambda-Service? (Wählen Sie zwei Antworten aus)

a. .NET Core 5

b. .NET 6

c. .NET 7

d. .NET Core 3.1

e. .NET Framework 4.8

2. Worauf bezieht sich Kaltstart? (Wählen Sie eine Antwort aus)

a. Die Zeit, die benötigt wird, um eine Lambda-Ausführungsumgebung und den Initialisierungscode für die Funktion zu starten.

b. Eine Lambda-Funktion, die den AWS-S3-Glacier-Speicher verwendet.

c. Die Zeit, die benötigt wird, um Ihren Code für den Lambda-Service bereitzustellen.

d. Die Zeit, die benötigt wird, um eine Funktion zu aktualisieren

3. Wie verwenden Sie das AWS.NET SDK mit Ihren .NET-Lambda-Funktionen?

a. Sie fügen Ihrer Projektdatei einen Verweis auf das SDK-Paket hinzu.

b. Das müssen Sie nicht, es ist in den Lambda-Funktionsvorlagen enthalten

c. Das müssen Sie nicht, es ist im Toolkit für die IDEs enthalten

d. Sie fügen das SDK über die AWS-Konsole zum Lambda-Service hinzu

4. Wie lautet der Name der Datei, die die Konfiguration für die Funktion angibt, wenn Sie ein neues lambda.EmptyFunction-Projekt erstellen?

a. serverless.template

b. lambda.csproj

c. aws-lambda-tools-defaults.json

5. Welche der folgenden Möglichkeiten gibt es, eine Lambda-Funktion aufzurufen?

a. Befehlszeile mit Dotnet-Lambda-Tooling

b. HTTPS-Anforderungen

c. Zugriff von anderen AWS-Services

d. Alle der oben Genannten

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

Zusammenfassung

Dieses Modul hat Sie in das Erstellen, Bereitstellen und Aufrufen von .NET-Lambda-Funktionen eingeführt. Es gab Ihnen einen Überblick über die verschiedenen Möglichkeiten, .NET in AWS Lambda auszuführen, und befasste sich mit einigen der Gründen, warum Sie sich für die eine oder andere Methode entscheiden könnten. Es wurden auch Konzepte rund um den „Kaltstart“ und Optimierungen erklärt.

War diese Seite hilfreich?

FUNKTIONSWEISE MIT ANDEREN AWS-SERVICES