Введение в Serverless вычисления и AWS Lambda
Serverless архитектура стала одним из главных трендов в современной облачной разработке. Вопреки названию, серверы всё ещё существуют, но разработчикам больше не нужно о них думать. AWS Lambda — это сервис Amazon, который позволяет запускать код без управления серверами. Вы платите только за вычислительное время, когда ваш код действительно выполняется.
В этой статье мы подробно разберём, как создавать serverless функции на Java с помощью AWS Lambda. Вы узнаете, как настроить проект, написать первый handler, задеплоить функцию и отладить её в реальных условиях.
Основы AWS Lambda для Java-разработчика
Что такое AWS Lambda?
AWS Lambda — это Function-as-a-Service (FaaS) платформа, которая выполняет ваш код в ответ на события. Lambda поддерживает Java 8, 11, 17 и 21 (Corretto). Функция запускается в изолированном контейнере, получает на вход событие (event) и контекст (context), а возвращает результат.
Ключевые понятия
- Handler — точка входа в вашу функцию. Обычно это метод, реализующий интерфейс
RequestHandlerилиRequestStreamHandler. - Event — данные, которые передаются в функцию (JSON, строка, бинарные данные).
- Context — объект с информацией о среде выполнения (ID запроса, тайм-аут, имя функции).
- Cold start — задержка при первом вызове функции после периода бездействия. Для Java это может быть 1-5 секунд.
- Layer — архив с библиотеками, который можно подключить к нескольким функциям.
Первый пример: простейшая Lambda на Java
Создадим Maven-проект и добавим зависимость:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.2</version>
</dependency>
Теперь напишем handler:
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
public class HelloHandler implements RequestHandler<String, String> {
@Override
public String handleRequest(String input, Context context) {
context.getLogger().log("Получено: " + input);
return "Привет, " + input + "!";
}
}
Этот handler принимает строку, логирует её и возвращает приветствие. Чтобы задеплоить функцию, упакуйте проект в JAR и загрузите в AWS Console или используйте AWS CLI.
Продвинутые техники работы с AWS Lambda на Java
Работа с JSON через Jackson
В реальных проектах вы будете обрабатывать JSON-события. Добавьте Jackson в pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
Пример handler для работы с JSON:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import java.util.Map;
public class JsonHandler implements RequestHandler<Map<String, Object>, String> {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public String handleRequest(Map<String, Object> event, Context context) {
try {
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(event);
context.getLogger().log("Событие: " + json);
return "Обработано успешно";
} catch (Exception e) {
throw new RuntimeException("Ошибка парсинга JSON", e);
}
}
}
Использование AWS SDK внутри Lambda
Часто Lambda-функции взаимодействуют с другими сервисами AWS. Например, запись в DynamoDB:
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import java.util.HashMap;
import java.util.Map;
public class DynamoHandler implements RequestHandler<Map<String, Object>, String> {
private final AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.defaultClient();
@Override
public String handleRequest(Map<String, Object> event, Context context) {
Map<String, Object> item = new HashMap<>();
item.put("id", event.getOrDefault("id", "unknown"));
item.put("data", event.getOrDefault("data", ""));
dynamoDB.putItem("MyTable", item);
return "Запись добавлена в DynamoDB";
}
}
Оптимизация cold start
Cold start — главная боль Java-разработчиков при работе с Lambda. Вот несколько советов:
- Используйте SnapStart — технология AWS, которая сохраняет снапшот состояния после инициализации.
- Минимизируйте зависимости — чем меньше JAR, тем быстрее загрузка.
- Избегайте статических инициализаторов — они выполняются при каждом cold start.
- Настройте Provisioned Concurrency — держит заданное количество "горячих" инстансов.
Деплой и отладка Lambda-функций
Деплой через Maven и AWS CLI
Самый надёжный способ — собрать uber-JAR и загрузить его через CLI:
mvn clean package shade:shade
aws lambda create-function \
--function-name my-java-function \
--runtime java17 \
--role arn:aws:iam::123456789:role/lambda-execution-role \
--handler com.example.HelloHandler::handleRequest \
--zip-file fileb://target/my-function-1.0.jar
Для обновления используйте update-function-code.
Локальная отладка с SAM CLI
AWS SAM (Serverless Application Model) позволяет запускать Lambda локально:
sam local invoke HelloFunction -e event.json
Создайте template.yaml:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: target/my-function-1.0.jar
Handler: com.example.HelloHandler::handleRequest
Runtime: java17