Serverless функции на Java: AWS Lambda от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в 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

Логирование и мони

Блоги

Рекомендаций по книгам