gRPC в Kotlin: когда использовать и как не прогадать

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

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

Начать курс

gRPC в Kotlin: когда использовать, чтобы не пожалеть

Представьте: вы пишете микросервисы на Kotlin, всё работает, но запросы между ними становятся тормознутыми. REST API, который вы так любили, начинает раздражать — слишком много сериализации, слишком много HTTP-оверхеда. Вы начинаете гуглить "быстрый способ общения между микросервисами" и натыкаетесь на gRPC. И тут же возникает вопрос: "А не перебор ли это? Может, оставить как есть?"

Давайте разбираться. gRPC в Kotlin — это не просто "ещё один протокол". Это совершенно другой подход к межсервисному взаимодействию. Он быстрее, строже и мощнее REST, но и сложнее. В этой статье я расскажу, когда gRPC — ваш лучший друг, а когда лучше обойтись старым добрым REST. И, конечно, покажу реальный код на Kotlin.

Что такое gRPC и почему он так популярен в мире Kotlin?

gRPC — это фреймворк удалённого вызова процедур (RPC) от Google. Он использует Protocol Buffers (protobuf) для сериализации данных и HTTP/2 для транспорта. Если REST — это как отправка писем по почте (каждый запрос — отдельное письмо), то gRPC — это как прямой телефонный разговор: быстрый, двусторонний и с минимальными задержками.

Для Kotlin-разработчиков gRPC особенно интересен, потому что:

  • Kotlin корутины отлично сочетаются с асинхронными стримами gRPC.
  • Строгая типизация protobuf — меньше ошибок на этапе выполнения.
  • Поддержка двунаправленного стриминга — идеально для чатов, игр и real-time приложений.

Но давайте честно: gRPC не нужен везде. И сейчас я покажу, как понять, нужен ли он именно вашему проекту.

Когда использовать gRPC в Kotlin: 5 железобетонных сценариев

1. Микросервисы с высокими требованиями к производительности

Если ваши микросервисы общаются десятками тысяч запросов в секунду, gRPC выигрывает у REST в 2-5 раз по скорости. Всё благодаря бинарному формату protobuf и мультиплексированию HTTP/2.

Пример: у вас есть сервис рекомендаций на Kotlin, который должен за миллисекунды вернуть персонализированный контент. REST с JSON будет "тяжеловат" — каждый запрос содержит имена полей, скобки и прочий текстовый мусор. Protobuf передаёт только числа и строки без лишней обёртки.

// Определение в .proto файле
service Recommender {
    rpc GetRecommendations (UserRequest) returns (RecommendationsResponse);
}

message UserRequest {
    string user_id = 1;
    int32 max_results = 2;
}

message RecommendationsResponse {
    repeated Item items = 1;
}

Код на Kotlin-клиенте будет выглядеть лаконично:

val stub = RecommenderGrpc.newBlockingStub(channel)
val request = UserRequest.newBuilder()
    .setUserId("user_123")
    .setMaxResults(10)
    .build()

val response = stub.getRecommendations(request)
println("Получено ${response.itemsCount} рекомендаций")

2. Real-time стриминг данных

gRPC поддерживает четыре вида стриминга: серверный, клиентский, двунаправленный и простой unary. В Kotlin это особенно удобно с корутинами — вы можете стримить данные как Flow.

Пример: сервер логов, который отправляет новые записи клиенту в реальном времени.

// Серверная часть на Kotlin
class LogServiceImpl : LogServiceGrpcKt.LogServiceCoroutineImplBase() {
    override fun streamLogs(request: LogRequest): Flow<LogEntry> = flow {
        val logSource = getLogSource(request.logType)
        logSource.collect { logEntry ->
            emit(logEntry)
        }
    }
}

// Клиентская часть
val stub = LogServiceGrpcKt.LogServiceCoroutineStub(channel)
stub.streamLogs(LogRequest.newBuilder().setLogType("error").build())
    .collect { log ->
        println("Новый лог: ${log.message}")
    }

Попробуйте сделать то же самое с REST и WebSocket — получится громоздко и медленно.

3. Полиглот-системы (разные языки программирования)

Если одни сервисы написаны на Kotlin, другие на Python, третьи на Go — gRPC с protobuf обеспечивает единый контракт. Вы описываете структуры данных один раз в .proto файле, а кодогенератор создаёт классы для всех языков.

Это особенно актуально для образовательных проектов, где вы можете иметь Kotlin-бэкенд и Python-скрипты для анализа данных.

4. Внутренние API с жёсткими контрактами

Когда API используется только внутри вашей системы, gRPC даёт строгую типизацию и версионирование через package в protobuf. Вы не сможете случайно передать строку вместо числа — компилятор отругает.

Это резко контрастирует с REST, где вы можете получить "500" из-за того, что фронтенд отправил "age: 'twenty'" вместо "age: 20".

5. Мобильные и IoT-приложения (с оговорками)

gRPC-Web позволяет использовать gRPC из браузера. Для мобильных приложений на Android (Kotlin) это тоже хороший выбор — protobuf компактнее JSON, что экономит трафик.

Но тут есть нюанс: если ваше приложение работает через публичный интернет с нестабильным соединением, gRPC может быть избыточным. Для публичных API чаще выбирают REST.

Когда лучше НЕ использовать gRPC в Kotlin

1. Публичные API для внешних разработчиков

Если ваш API будут использовать сторонние разработчики, gRPC создаст лишние сложности. Им придётся генерировать клиенты, разбираться с protobuf, настраивать HTTP/2. REST с JSON — это стандарт де-факто, его понимают все.

2. Простые CRUD-приложения

Если ваше приложение — это просто "создать-прочитать-обновить-удалить", gRPC не даст преимуществ. REST справится быстрее и проще. Не усложняйте архитектуру, если нет реальной нагрузки.

3. Проекты с маленькой командой

gRPC требует дополнительного инструментария: настройка protoc, кодогенерация, понимание HTTP/2. Если в команде 2-3 человека и дедлайн горит, лучше остаться на REST — это быстрее в разработке.

Практический пример: gRPC сервер на Kotlin с корутинами

Давайте соберём простой, но рабочий пример. У нас будет сервис, который принимает запрос с именем пользователя и возвращает приветствие.

Шаг 1. Определяем .proto файл

syntax = "proto3";

package greeter;

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}

Шаг 2. Генериру

Блоги

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