Бессерверные вычисления с AWS Lambda, часть 2

В первой половине этой статьи был представлен обзор бессерверных вычислений с помощью AWS Lambda, включая создание, развертывание и тестирование функций AWS Lambda в примере приложения Java. Во второй части вы узнаете, как интегрировать лямбда-функции с внешней базой данных, в данном случае DynamoDB. Затем мы воспользуемся AWS SDK для вызова функций Lambda из нашего примера приложения Java.

AWS Lambda и DynamoDB

DynamoDB - это хранилище документов NoSQL, размещенное на Amazon Web Services (AWS). DynamoDB определяет абстракции данных как таблицы, которые принимают стандартные операции с базой данных, такие как вставка, получение, запрос, обновление и удаление. Как и во многих других базах данных NoSQL, схема DynamoDB не является фиксированной, поэтому некоторые элементы в одной таблице могут иметь поля, которых нет в других.

Одна из лучших особенностей DynamoDB - это многоуровневая модель ценообразования. В отличие от AWS Relational Database Service (RDS), в котором AWS управляет вашей базой данных с помощью платных инстансов EC2, DynamoDB оплачивается по факту использования. Вы платите за используемое хранилище и за пропускную способность ваших запросов, но не платите напрямую за какие-либо базовые виртуальные машины. Кроме того, AWS предоставляет вам уровень бесплатного пользования, поддерживающий до 25 ГБ пространства, с достаточной пропускной способностью для выполнения до 200 миллионов запросов в месяц.

В разделе «Бессерверные вычисления с AWS Lambda, часть 1» мы разработали простое бессерверное приложение Java с использованием функций Lambda. Вы можете скачать исходный код приложения GetWidgetHandler в любое время. Если вы еще не прочитали часть 1, я предлагаю ознакомиться с кодом приложения и примерами из этой статьи, прежде чем продолжить.

Наш первый шаг - настроить базу данных DynamoDB в нашей консоли AWS. После этого мы обновим get-widgetфункцию из Части 1, чтобы получить виджет из таблицы DynamoDB.

Настройте базу данных DynamoDB в AWS

Начнем с создания таблицы DynamoDB. В консоли AWS нажмите Services и выберите DynamoDB в разделе базы данных, как показано на экране 1.

Стивен Хейнс

После запуска вы увидите панель управления DynamoDB. Нажмите кнопку Create table , чтобы начать создание вашей таблицы, показанной на рисунке 2.

Стивен Хейнс

Теперь вы увидите страницу, показанную на рисунке 3.

Стивен Хейнс

Дайте своей таблице имя (в данном случае «Виджет») и установите для первичного ключа значение id, оставив его как String. Нажатие кнопки Создать , когда вы закончили направит вас на страницу DynamoDB таблицы. Если вам потребуется перейти на эту страницу в будущем, выберите « Службы» -> «DynamoDB» и нажмите « Таблицы» .

Стивен Хейнс

Мы вручную создадим запись в новой таблице виджетов, поэтому нажмите кнопку Create item , показанную на рисунке 5.

Стивен Хейнс

DynamoDB предварительно заполнит idполем страницу «Создать элемент» . Введите легко запоминающийся идентификатор, например «1». Затем нажмите плюс (+) рядом с новым идентификатором, добавив еще одно поле с именем name. Введите значение для nameполя, например «Виджет 1». По завершении нажмите Сохранить .

Обновите класс GetWidgetHandler

Имея данные в нашей базе данных, следующее, что нам нужно сделать, это обновить GetWidgetHandlerкласс из части 1. Мы начнем с добавления зависимости DynamoDB к нашему исходному файлу POM. Обновленный pom.xmlфайл показан в листинге 1.

Листинг 1. pom.xml (обновлен с учетом зависимости DynamoDB)

 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        

В листинге 1 добавлена aws-java-sdk-dynamodbзависимость файла POM из части 1. В листинге 2 показан обновленный GetWidgetHandlerкласс.

Листинг 2. GetWidgetHandler.java (обновлен для загрузки данных из DynamoDB)

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

Основным интерфейсом DynamoDB является DynamoDBобъект. Для создания DynamoDBэкземпляра нам понадобится клиент DynamoDB. Поскольку наша функция Lambda будет работать в AWS, нам не нужно предоставлять учетные данные, поэтому мы можем использовать клиент по умолчанию. Обратите внимание, что мы сможем запрашивать базу данных без учетных данных только потому, что get-widget-roleу части 1 есть dynamodb:GetItemразрешение.

Из DynamoDBэкземпляра мы можем вызвать, getTable("Widget")чтобы получить Tableэкземпляр. Тогда мы можем назвать getItem()по Tableпримеру, передавая ему первичный ключ элемента , который мы хотим получить. Если есть элемент с указанным первичным ключом, он вернет действительный ответ; иначе он вернется null. ItemКласс обеспечивает доступ к параметрам ответа, поэтому мы закончим реализацию путем создания нового Widgetобъекта с его именем загруженного из DynamoDB.

скачать Получить код Получить код обновленного приложения GetWidgetHandler. Создано Стивеном Хейнсом для JavaWorld.

Запрос DynamoDB с DynamoDBMapper

Существует несколько API-интерфейсов для запросов DynamoDB, от вызова службы RESTful до низкоуровневого интерфейса выше и пары интерфейсов более высокого уровня. Один из наиболее популярных интерфейсов - DynamoDBMapper. Этот интерфейс обеспечивает конструкцию, аналогичную той, что вы можете найти при сопоставлении объектов с реляционными данными в таком инструменте, как Hibernate. Давайте кратко рассмотрим, как получить Widgetиз DynamoDB с помощью DynamoDBMapperAPI.

Первое, что нам нужно сделать, это добавить несколько аннотаций к Widgetклассу, как показано в листинге 3.

Листинг 3. Widget.java (обновленный аннотациями DynamoDBMapper)

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

В DynamoDBTableаннотации указывается имя таблицы DynamoDB, с которой выполняется Widgetсопоставление. DynamoDBHashKeyАннотацию идентифицирует первичный ключ Widgetтаблицы. В DynamoDBAttributeаннотации указаны другие атрибуты класса, которые сопоставляются с атрибутами базы данных в DynamoDB. Если у вас есть другие атрибуты, которые вы хотите игнорировать, вы можете добавить @DynamoDBIgnoreаннотацию.

Теперь, когда Widgetкласс аннотирован, мы можем обновить GetWidgetHandlerкласс для использования DynamoDBMapper, как показано в листинге 4.

Листинг 4. GetWidgetHandler.java (обновленный с помощью 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; } } 

В предыдущей (часть 1) версии GetWidgetHandlerмы создали AmazonDynamoDBэкземпляр, используя AmazonDynamoDBClientBuilder.defaultClient()вызов. Теперь мы будем использовать этого клиента для инициализации DynamoDBMapperэкземпляра.

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.

Если вы случайно столкнулись с ошибкой OutOfMemoryErrorпри повторном тестировании своей функции, выберите вкладку « Конфигурация » и откройте раздел «Дополнительные настройки». Здесь вы можете увеличить объем памяти, как показано ниже.

Стивен Хейнс