Введение в Serverless функции на Kotlin с AWS Lambda
Serverless-архитектура стремительно набирает популярность благодаря своей масштабируемости, экономичности и простоте развертывания. AWS Lambda — один из ведущих сервисов для запуска бессерверных функций, и хотя чаще всего его ассоциируют с JavaScript, Python или Java, язык Kotlin также отлично подходит для этой задачи. Благодаря полной совместимости с JVM и лаконичному синтаксису, Kotlin позволяет писать чистый, безопасный и производительный код для облачных функций.
В этой статье мы пройдем путь от создания простейшей Lambda-функции на Kotlin до ее деплоя, тестирования и мониторинга в AWS. Вы узнаете, как настроить проект с Gradle, обрабатывать события API Gateway, работать с AWS SDK и оптимизировать холодный старт.
Основы: создание первой Lambda-функции на Kotlin
Настройка проекта и зависимости
Для начала создадим новый Gradle-проект. Убедитесь, что у вас установлены JDK 11+ и Gradle 7+. В файле build.gradle.kts подключим необходимые зависимости:
plugins {
kotlin("jvm") version "1.9.22"
id("io.github.justinhj.kotlin-lambda") version "0.2.0"
}
dependencies {
implementation("com.amazonaws:aws-lambda-java-core:1.2.3")
implementation("com.amazonaws:aws-lambda-java-events:3.11.4")
implementation("com.google.code.gson:gson:2.10.1")
}
tasks.withType {
archiveFileName.set("lambda-function.zip")
}
Плагин kotlin-lambda упрощает сборку и деплой, а библиотеки aws-lambda-java-core и aws-lambda-java-events предоставляют интерфейсы для обработчиков и событий.
Простейший обработчик
Создадим класс HelloHandler, который реализует интерфейс RequestHandler:
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.RequestHandler
class HelloHandler : RequestHandler
Этот обработчик принимает JSON-объект с полем name и возвращает приветствие. Для деплоя соберите проект командой ./gradlew buildZip и загрузите полученный JAR в консоль AWS Lambda.
Продвинутые сценарии: работа с событиями и AWS SDK
Обработка событий API Gateway
Часто Lambda используется как бэкенд для REST API. Для этого потребуется обрабатывать формат событий API Gateway. Создадим класс ApiGatewayHandler:
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.RequestHandler
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent
class ApiGatewayHandler : RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
override fun handleRequest(request: APIGatewayProxyRequestEvent, context: Context): APIGatewayProxyResponseEvent {
val response = APIGatewayProxyResponseEvent()
val body = """
{
"message": "Привет от Kotlin Lambda!",
"method": "${request.httpMethod}",
"path": "${request.path}"
}
""".trimIndent()
response.statusCode = 200
response.body = body
response.headers = mapOf("Content-Type" to "application/json")
return response
}
}
Теперь ваша функция может отвечать на HTTP-запросы, передавать заголовки и статус-коды. В консоли AWS при создании функции выберите триггер API Gateway HTTP API.
Работа с Amazon S3 через Kotlin
Serverless-функции часто взаимодействуют с другими сервисами AWS. Покажем пример чтения файла из S3:
import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.GetObjectRequest
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.RequestHandler
class S3ReaderHandler : RequestHandler<Map<String, String>, String> {
private val s3 = S3Client.builder().build()
override fun handleRequest(input: Map<String, String>, context: Context): String {
val bucket = input["bucket"] ?: throw IllegalArgumentException("Missing bucket")
val key = input["key"] ?: throw IllegalArgumentException("Missing key")
val request = GetObjectRequest.builder().bucket(bucket).key(key).build()
val content = s3.getObjectAsBytes(request).asUtf8String()
return "Content from S3: $content"
}
}
Не забудьте добавить зависимость software.amazon.awssdk:s3:2.21.0 в build.gradle.kts и настроить IAM-роль с доступом к S3.
Оптимизация холодного старта и мониторинг
Уменьшение времени холодного старта
Холодный старт (cold start) — главный враг serverless-приложений на JVM. Вот несколько способов его минимизировать:
- Используйте SnapStart — функция AWS, которая делает снапшот состояния JVM после инициализации. Включите её в консоли Lambda.
- Сократите размер JAR — используйте Shadow JAR (плагин
shadow) и исключите ненужные зависимости. - Ленивая инициализация — создавайте тяжелые объекты (например, S3Client) внутри
companion object, чтобы они инициализировались только один раз:
class OptimizedHandler : RequestHandler<Map<String, String>, String> {
companion object {
private val s3 by lazy { S3Client.builder().build() }
}
override fun handleRequest(input: Map<String, String>, context: Context): String {
// используем s3
}
}
- Увеличьте память — больше памяти (например, 1024 MB) часто улучшает производительность CPU и сокращает время старта.
Логирование и мониторинг
Для отладки используйте встроенный логгер context.logger. Для продакшена рекомендуется подключить X-Ray или CloudWatch Logs:
context.log