Микросервисы на Kotlin: дорожная карта для начинающих

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

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

Начать курс

Почему Kotlin — лучший выбор для микросервисов в 2024?

Вы когда-нибудь писали микросервис на Python, а потом думали: «А что, если бы он работал быстрее, потреблял меньше памяти и при этом код оставался таким же читаемым?» Знакомо? Тогда добро пожаловать в мир Kotlin — языка, который Google выбрал для Android, а сообщество backend-разработчиков — для создания легковесных и производительных микросервисов.

Kotlin идеально ложится на микросервисную архитектуру: он статически типизирован, компилируется в байт-код JVM (или нативный код через Kotlin/Native), но при этом не требует тонны бойлерплейта как Java. А главное — его корутины (coroutines) позволяют обрабатывать тысячи запросов на одном потоке без боли в виде callback hell.

В этой статье мы не будем читать лекции по теории. Мы возьмём и напишем два микросервиса: User Service (REST API) и Notification Service (имитация отправки писем). Всё на чистом Kotlin + Ktor. Поехали!

1. Инструментарий: что ставить перед стартом

Прежде чем писать код, давайте убедимся, что ваш компьютер готов к бою.

Что нужно установить:

  • JDK 17+ — Kotlin работает на JVM, поэтому без Java никуда. Скачать можно с Adoptium.
  • IntelliJ IDEA Community Edition — лучшая IDE для Kotlin (да, она от JetBrains, и да, она бесплатна).
  • Gradle (или Maven) — система сборки. В IntelliJ он уже встроен, но если хотите ставить отдельно — gradle.org.
  • Docker (опционально, но сильно упростит деплой).

Если у вас macOS или Linux — вы уже на полпути к успеху. На Windows рекомендую WSL2.

2. Создаём первый микросервис: User Service на Ktor

Ktor — это фреймворк от создателей Kotlin. Он максимально лёгкий: вы сами решаете, какие модули подключать (маршрутизация, сериализация, логирование). Никакой магии — только чистый код.

2.1. Генерация проекта

Самый быстрый способ — использовать Ktor Project Generator. Выберите:

  • Build system: Gradle Kotlin DSL
  • Engine: Netty (самый популярный)
  • Plugins: Routing, Content Negotiation (JSON), Status Pages

Скачайте архив, откройте в IntelliJ — и через 2 минуты у вас готовый скелет.

2.2. Пишем REST API: получение пользователей

Создадим простую модель и эндпоинт. Код будет максимально читаемым:

// Model.kt
data class User(
    val id: Int,
    val name: String,
    val email: String
)

// UserRepository.kt
object UserRepository {
    private val users = mutableListOf(
        User(1, "Alice", "alice@example.com"),
        User(2, "Bob", "bob@example.com")
    )

    fun findAll(): List<User> = users
    fun findById(id: Int): User? = users.find { it.id == id }
}

// Application.kt (точка входа)
fun main() {
    embeddedServer(Netty, port = 8080) {
        configureSerialization()
        configureRouting()
    }.start(wait = true)
}

// Routing.kt
fun Application.configureRouting() {
    routing {
        route("/api/v1/users") {
            get {
                call.respond(UserRepository.findAll())
            }
            get("/{id}") {
                val id = call.parameters["id"]?.toIntOrNull()
                if (id == null) {
                    call.respond(HttpStatusCode.BadRequest, "Invalid ID")
                    return@get
                }
                val user = UserRepository.findById(id)
                if (user != null) {
                    call.respond(user)
                } else {
                    call.respond(HttpStatusCode.NotFound, "User not found")
                }
            }
        }
    }
}

Обратите внимание: мы используем coroutines неявно — Ktor сам переводит каждый запрос в корутину. Никаких CompletableFuture или ручного управления потоками.

2.3. Подключаем базу данных (Exposed)

Хранить данные в памяти — весело, но ненадёжно. Подключим PostgreSQL через Exposed — ORM от JetBrains для Kotlin:

// build.gradle.kts
dependencies {
    implementation("org.jetbrains.exposed:exposed-core:0.44.1")
    implementation("org.jetbrains.exposed:exposed-dao:0.44.1")
    implementation("org.jetbrains.exposed:exposed-jdbc:0.44.1")
    implementation("org.postgresql:postgresql:42.6.0")
}

// DatabaseFactory.kt
object DatabaseFactory {
    fun init() {
        Database.connect(
            url = "jdbc:postgresql://localhost:5432/users_db",
            driver = "org.postgresql.Driver",
            user = "postgres",
            password = "password"
        )
    }
}

// UsersTable.kt
object UsersTable : Table("users") {
    val id = integer("id").autoIncrement()
    val name = varchar("name", 50)
    val email = varchar("email", 100)

    override val primaryKey = PrimaryKey(id)
}

// Теперь в Application.kt вызываем DatabaseFactory.init() перед стартом сервера

Готово! Теперь ваш User Service умеет читать данные из реальной БД.

3. Второй микросервис: Notification Service

Пусть наш второй сервис будет совсем маленьким — он будет принимать запросы от User Service и «отправлять» письма (просто писать в лог).

3.1. Создаём ещё один проект Ktor

Повторите шаги из п. 2.1, но назовите проект notification-service и поставьте порт 8081.

3.2. Эндпоинт для отправки уведомлений

// NotificationRoutes.kt
fun Application.notificationRoutes() {
    routing {
        post("/api/v1/notifications/send") {
            val notification = call.receive<Notification>()
            // Имитация отправки
            log.info("Sending email to ${notification.email}: ${notification.message}")
            call.respond(HttpStatusCode.OK, NotificationResponse("Sent successfully"))
        }
    }
}

data class Notification(
    val email: String,
    val message: String
)

data class NotificationResponse(val status: String)

3.3. Как сервисы общаются между собой?

В микросервисах два основных паттерна: синхронный (HTTP) и асинхронный (через брокер сообщений, например, RabbitMQ или Kafka). Для начала используем HTTP-клиент из Ktor:

// В User Service добавляем вызов Notification Service
suspend fun sendWelcomeEmail(user: User) {
    val client = HttpClient(CIO) {
        install(ContentNegotiation) { json() }                

Блоги

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