Serverloses Computing mit AWS Lambda, Teil 2

In der ersten Hälfte dieses Artikels wurde ein Überblick über Serverless Computing mit AWS Lambda gegeben, einschließlich des Erstellens, Bereitstellens und Testens von AWS Lambda-Funktionen in einer Java-Beispielanwendung. In Teil 2 erfahren Sie, wie Sie Lambda-Funktionen in eine externe Datenbank integrieren, in diesem Fall in DynamoDB. Wir werden dann das AWS SDK verwenden, um Lambda-Funktionen aus unserer Java-Beispielanwendung aufzurufen.

AWS Lambda und DynamoDB

DynamoDB ist ein NoSQL-Dokumentenspeicher, der von Amazon Web Services (AWS) gehostet wird. DynamoDB definiert Datenabstraktionen als Tabellen, die gängige Datenbankoperationen wie Einfügen, Abrufen, Abfragen, Aktualisieren und Löschen akzeptieren. Wie bei vielen anderen NoSQL-Datenbanken ist das Schema von DynamoDB nicht festgelegt, sodass einige Elemente in derselben Tabelle Felder enthalten können, die andere nicht haben.

Eine der besten Funktionen von DynamoDB ist das abgestufte Preismodell. Im Gegensatz zum AWS Relational Database Service (RDS), bei dem AWS Ihre Datenbank mithilfe von EC2-Instanzen verwaltet, für die Sie bezahlen, ist DynamoDB "Pay-as-you-go". Sie zahlen für den von Ihnen verwendeten Speicher und den Durchsatz Ihrer Abfragen, aber nicht direkt für zugrunde liegende virtuelle Maschinen. Darüber hinaus bietet AWS eine kostenlose Stufe, die bis zu 25 GB Speicherplatz unterstützt und über einen ausreichenden Durchsatz verfügt, um bis zu 200 Millionen Anforderungen pro Monat auszuführen.

In Serverless Computing mit AWS Lambda, Teil 1, haben wir eine einfache, serverlose Java-Anwendung mit Lambda-Funktionen entwickelt. Sie können den Quellcode für die GetWidgetHandler-Anwendung jederzeit herunterladen. Wenn Sie Teil 1 noch nicht gelesen haben, empfehlen wir Ihnen, sich mit dem Anwendungscode und den Beispielen aus diesem Artikel vertraut zu machen, bevor Sie fortfahren.

Unser erster Schritt ist das Einrichten der DynamoDB-Datenbank in unserer AWS-Konsole. Danach aktualisieren wir die get-widgetFunktion aus Teil 1, um ein Widget aus einer DynamoDB-Tabelle abzurufen.

Richten Sie die DynamoDB-Datenbank in AWS ein

Wir beginnen mit der Erstellung der DynamoDB-Tabelle. Klicken Sie in der AWS-Konsole auf Dienste und wählen Sie im Datenbankabschnitt DynamoDB aus (siehe Abbildung 1).

Steven Haines

Nach dem Start wird das DynamoDB-Dashboard angezeigt. Klicken Sie auf die Schaltfläche Tabelle erstellen , um mit der Erstellung Ihrer Tabelle zu beginnen (siehe Abbildung 2).

Steven Haines

Jetzt sehen Sie die in Abbildung 3 gezeigte Seite.

Steven Haines

Geben Sie Ihrer Tabelle einen Namen (in diesem Fall "Widget") und setzen Sie den Primärschlüssel auf id, wobei Sie ihn als String. Durch Drücken erstellen , wenn Sie fertig sind , werden Sie auf die DynamoDB Tabellen Seite lenken. Wenn Sie in Zukunft zu dieser Seite navigieren müssen, wählen Sie Dienste -> DynamoDB und klicken Sie auf Tabellen .

Steven Haines

Wir erstellen manuell einen Eintrag in der neuen Widget-Tabelle. Klicken Sie daher auf die in Abbildung 5 gezeigte Schaltfläche Element erstellen .

Steven Haines

DynamoDB füllt die Seite Element erstellen mit dem idFeld vor. Geben Sie eine leicht zu merkende ID ein, z. B. "1". Drücken Sie anschließend das Pluszeichen (+) neben der neuen ID und fügen Sie ein weiteres Feld mit dem Namen hinzu name. Geben Sie einen Wert für das nameFeld ein, z. B. "Widget 1". Drücken Sie Speichern , wenn Sie fertig sind.

Aktualisieren Sie die GetWidgetHandler-Klasse

Mit Daten in unserer Datenbank müssen wir als Nächstes die GetWidgetHandlerKlasse von Teil 1 aktualisieren. Zunächst fügen wir die DynamoDB-Abhängigkeit zu unserer ursprünglichen POM-Datei hinzu. Die aktualisierte pom.xmlDatei wird in Listing 1 gezeigt.

Listing 1. pom.xml (aktualisiert mit DynamoDB-Abhängigkeit)

 4.0.0 com.javaworld.geekcap aws-lambda-java jar 1.0-SNAPSHOT aws-lambda-java //maven.apache.org  1.8 UTF-8    com.amazonaws aws-lambda-java-core 1.1.0   com.amazonaws aws-java-sdk-dynamodb 1.11.135   junit junit 4.12 test      org.apache.maven.plugins maven-compiler-plugin 2.0.2  ${java.version} ${java.version}    org.apache.maven.plugins maven-shade-plugin 2.3  false    package  shade        

Listing 1 fügt die aws-java-sdk-dynamodbAbhängigkeit zur POM-Datei aus Teil 1 hinzu. Listing 2 zeigt die aktualisierte GetWidgetHandlerKlasse.

Listing 2. GetWidgetHandler.java (aktualisiert, um Daten aus DynamoDB zu laden)

 package com.javaworld.awslambda.widget.handlers; import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; import com.amazonaws.services.dynamodbv2.document.DynamoDB; import com.amazonaws.services.dynamodbv2.document.Item; import com.amazonaws.services.dynamodbv2.document.Table; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.javaworld.awslambda.widget.model.Widget; import com.javaworld.awslambda.widget.model.WidgetRequest; public class GetWidgetHandler implements RequestHandler { @Override public Widget handleRequest(WidgetRequest widgetRequest, Context context) { //return new Widget(widgetRequest.getId(), "My Widget " + widgetRequest.getId()); // Create a connection to DynamoDB AmazonDynamoDB client = AmazonDynamoDBClientBuilder.defaultClient(); DynamoDB dynamoDB = new DynamoDB(client); // Get a reference to the Widget table Table table = dynamoDB.getTable("Widget"); // Get our item by ID Item item = table.getItem("id", widgetRequest.getId()); if(item != null) { System.out.println(item.toJSONPretty()); // Return a new Widget object return new Widget(widgetRequest.getId(), item.getString("name")); } else { return new Widget(); } } } 

Die Hauptschnittstelle zu DynamoDB ist das DynamoDBObjekt. Um eine DynamoDBInstanz zu erstellen , benötigen wir einen DynamoDB-Client. Da unsere Lambda-Funktion in AWS ausgeführt wird, müssen wir keine Anmeldeinformationen angeben, damit wir den Standardclient verwenden können. Beachten Sie, dass wir die Datenbank nur ohne Anmeldeinformationen abfragen können, da der get-widget-roleaus Teil 1 die dynamodb:GetItemBerechtigung hat.

Von der DynamoDBInstanz aus können wir aufrufen getTable("Widget"), um eine TableInstanz abzurufen . Dann können wir getItem()die TableInstanz aufrufen und ihr den Primärschlüssel des Elements übergeben, das wir abrufen möchten. Wenn es ein Element mit dem angegebenen Primärschlüssel gibt, wird eine gültige Antwort zurückgegeben. Andernfalls wird es zurückkehren null. Die ItemKlasse bietet Zugriff auf die Antwortparameter. Zum Abschluss der Implementierung erstellen wir ein neues WidgetObjekt, dessen Name aus DynamoDB geladen wird.

download Code abrufen Den Code für die aktualisierte GetWidgetHandler-Anwendung abrufen. Erstellt von Steven Haines für JavaWorld.

Abfragen von DynamoDB mit DynamoDBMapper

Es gibt mehrere APIs zum Abfragen von DynamoDB, von einem RESTful-Serviceaufruf über die oben genannte Low-Level-Schnittstelle bis hin zu einigen übergeordneten Schnittstellen. Eine der beliebtesten Schnittstellen ist DynamoDBMapper. Diese Schnittstelle bietet ein ähnliches Konstrukt wie beim Zuordnen von Objekten zu relationalen Daten in einem Tool wie Hibernate. Lassen Sie uns kurz untersuchen, wie Sie Widgetmithilfe der DynamoDBMapperAPI eine aus DynamoDB abrufen .

Als erstes müssen wir der WidgetKlasse einige Anmerkungen hinzufügen , die in Listing 3 gezeigt werden.

Listing 3. Widget.java (aktualisiert mit DynamoDBMapper-Anmerkungen)

 package com.javaworld.awslambda.widget.model; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable; @DynamoDBTable(tableName="Widget") public class Widget { private String id; private String name; public Widget() { } public Widget(String id) { this.id = id; } public Widget(String id, String name) { this.id = id; this.name = name; } @DynamoDBHashKey(attributeName="id") public String getId() { return id; } public void setId(String id) { this.id = id; } @DynamoDBAttribute(attributeName="name") public String getName() { return name; } public void setName(String name) { this.name = name; } } 

Die DynamoDBTableAnmerkung gibt den Namen der DynamoDB-Tabelle an, der die WidgetZuordnungen zugeordnet sind. Die DynamoDBHashKeyAnmerkung gibt den Primärschlüssel der WidgetTabelle an. Die DynamoDBAttributeAnnotation identifiziert andere Klassenattribute, die Datenbankattributen in DynamoDB zugeordnet sind. Wenn Sie andere Attribute hatten, die Sie ignorieren wollten, können Sie die @DynamoDBIgnoreAnmerkung hinzufügen .

Mit der Widgetkommentierten Klasse können wir jetzt die GetWidgetHandlerKlasse aktualisieren, um die zu verwenden DynamoDBMapper, die in Listing 4 gezeigt wird.

Listing 4. GetWidgetHandler.java (aktualisiert mit DynamoDBMapper)

 package com.javaworld.awslambda.widget.handlers; import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.javaworld.awslambda.widget.model.Widget; import com.javaworld.awslambda.widget.model.WidgetRequest; public class GetWidgetHandler implements RequestHandler { @Override public Widget handleRequest(WidgetRequest widgetRequest, Context context) { // Create a connection to DynamoDB AmazonDynamoDB client = AmazonDynamoDBClientBuilder.defaultClient(); // Build a mapper DynamoDBMapper mapper = new DynamoDBMapper(client); // Load the widget by ID Widget widget = mapper.load(Widget.class, widgetRequest.getId()); if(widget == null) { // We did not find a widget with this ID, so return an empty Widget context.getLogger().log("No Widget found with ID: " + widgetRequest.getId() + "\n"); return new Widget(); } // Return the widget return widget; } } 

In der früheren (Teil 1) Version von haben GetWidgetHandlerwir eine AmazonDynamoDBInstanz mithilfe eines AmazonDynamoDBClientBuilder.defaultClient()Aufrufs erstellt. Jetzt verwenden wir diesen Client, um DynamoDBMapperstattdessen eine Instanz zu initialisieren .

The DynamoDBMapper class provides access to execute queries, load objects by ID, save objects, delete objects, and so forth. In this case, we pass DynamoDBMapper the widget's class (Widget.class) and its primary key. If DynamoDB has a Widget with the specified primary key it will return it; if not it will return null.

Rebuild and then re-upload your new JAR file by opening your Lambda function dashboard, then click on the Code tab and press Upload. When you re-upload and subsequently call your function, AWS Lambda will create a new container for the new JAR file and push that to an EC2 instance. You should expect the first run to be slow.

Wenn Sie OutOfMemoryErrorbeim erneuten Testen Ihrer Funktion auf ein Problem stoßen , wählen Sie die Registerkarte Konfiguration und öffnen Sie den Abschnitt Erweiterte Einstellungen. Hier können Sie Ihr Gedächtnis erhöhen, wie unten gezeigt.

Steven Haines