---
title: "gRPC — Как это работает"
url: "https://romankryvolapov.com/ru/grpc/"
description: "Как устроен gRPC поверх HTTP/2 и Protocol Buffers, чем он выигрывает у REST и как собрать сервер и клиент на Kotlin с Gradle."
language: ru
updated: 2026-01-21
---
## Что такое gRPC и Protocol Buffers {#Что-такое-gRPC-и-Protocol-Buffers}

**gRPC (Google Remote Procedure Calls):**\
система удалённого вызова процедур (RPC) с открытым исходным кодом, первоначально разработанная в Google в 2015 году. В качестве транспорта используется HTTP/2, в качестве языка описания интерфейса — Protocol Buffers. gRPC предоставляет такие функции как аутентификация, двунаправленная потоковая передача и управление потоком, блокирующие или неблокирующие привязки, а также отмена и тайм-ауты. Генерирует кроссплатформенные привязки клиента и сервера для многих языков. Чаще всего используется для подключения служб в микросервисном стиле архитектуры и подключения мобильных устройств и браузерных клиентов к серверным службам.

**Protocol Buffers:**\
протокол сериализации (передачи) структурированных данных, предложенный Google как эффективная бинарная альтернатива текстовому формату XML. Разработчики сообщают, что Protocol Buffers проще, компактнее и быстрее, чем XML, поскольку осуществляется передача бинарных данных, оптимизированных под минимальный размер сообщения.

## Почему gRPC лучше REST для внутренних сервисов {#Почему-gRPC-лучше-REST-для-внутренних-сервисов}

**Почему gRPC лучше REST для внутренних сервисов:**\
HTTP/2 бинарный формат (protobuf) → меньше трафика и CPU.\
Мультиплексирование в одном TCP-соединении → меньше соединений, ниже латентность.\
Односторонние, серверные и двусторонние стримы без long-polling.\
Сгенерированные типобезопасные клиенты на 15+ языках.\
Контракт-first: изменения схемы ловятся на этапе компиляции.\
Встроенные deadline, retry, load-balancing, TLS.\
Наблюдаемость: метаданные (headers/trailers) подходят для трассировок и метрик.\
Простой перенос наружу: можно положить grpc-gateway перед сервисом и получить REST/JSON без переписывания кода.

## Пример: создание grpc-server и grpc-client {#Пример-создание-grpc-server-и-grpc-client}

**Для примера сделаем grpc-server и grpc-client**

Структура проекта

```kotlin
simple-grpc
│ settings.gradle.kts
├─grpc-server
│  ├─build.gradle.kts
│  ├─src/main/proto/hello.proto
│  └─src/main/kotlin/com/example/grpc/Server.kt
└─grpc-client
   ├─build.gradle.kts
   ├─src/main/proto/hello.proto
   └─src/main/kotlin/com/example/grpc/Client.kt
```

В файле \*.proto записано, какие сообщения и методы понимает сервис.

**Примерно как договор между клиентом и сервером:**

**service:**\
перечисляет доступные операции (RPC-методы).

**message:**\
описывает поля запросов и ответов (тип, имя, порядковый номер).

Версия файла лежит в VCS; обе стороны генерируют код из этой одной схемы и получают строго типобезопасные классы.

**Зачем нужен:**\
Единый источник правды – ни клиент, ни сервер не могут «рассинхронизироваться» по формату.\
Автогенерация – писать надо только логику, а не сериализацию/десериализацию.\
Проверка на этапе сборки – изменил поле в контракте компилятор сразу покажет, где в коде нужно поправить.\
Мультиязычность – из одного и того же proto можно в пару команд получить клиент на Kotlin, Go, Python и т.д.\
\*.proto описывает API однажды; всё остальное генерируется.

После генерации появятся GreeterGrpcKt.GreeterCoroutineImplBase (для сервера) и GreeterCoroutineStub (для клиента).

**src/main/proto/hello.proto (копируем в оба модуля)**

```proto
syntax = "proto3";
package greet;


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


message HelloRequest { string name = 1; }
message HelloReply  { string message = 1; }
```

**grpc-server/build.gradle.kts**

```kotlin
plugins {
    kotlin("jvm") version "2.2.0"
    id("application")
    id("com.google.protobuf") version "0.9.4"
}

repositories { mavenCentral() }

dependencies {
    implementation("io.grpc:grpc-kotlin-stub:1.4.3")
    implementation("io.grpc:grpc-protobuf:1.73.0")
    implementation("io.grpc:grpc-stub:1.73.0")
    implementation("com.google.protobuf:protobuf-kotlin:4.31.1")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.21")
    runtimeOnly("io.grpc:grpc-netty-shaded:1.73.0")
}

application { mainClass.set("com.example.grpc.ServerKt") }

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:4.31.1" }
    plugins {
        id("grpc")   { artifact = "io.grpc:protoc-gen-grpc-java:1.73.0" }
        id("grpckt") { artifact = "io.grpc:protoc-gen-grpc-kotlin:1.4.3:jdk8@jar" }
    }
    generateProtoTasks.all().forEach { t -> t.plugins { id("grpc"); id("grpckt") } }
}

```

**grpc-client/build.gradle.kts (отличается только mainClass)**

```kotlin
plugins {
    kotlin("jvm") version "2.2.0"
    id("application")
    id("com.google.protobuf") version "0.9.4"
}

repositories { mavenCentral() }

dependencies {
    implementation("io.grpc:grpc-kotlin-stub:1.4.3")
    implementation("io.grpc:grpc-protobuf:1.73.0")
    implementation("io.grpc:grpc-stub:1.73.0")
    implementation("com.google.protobuf:protobuf-kotlin:4.31.1")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.21")
    runtimeOnly("io.grpc:grpc-netty-shaded:1.73.0")
}

application { mainClass.set("com.example.grpc.ClientKt") }

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:4.31.1" }
    plugins {
        id("grpc")   { artifact = "io.grpc:protoc-gen-grpc-java:1.73.0" }
        id("grpckt") { artifact = "io.grpc:protoc-gen-grpc-kotlin:1.4.3:jdk8@jar" }
    }
    generateProtoTasks.all().forEach { t -> t.plugins { id("grpc"); id("grpckt") } }
}
```

**Server.kt**

```kotlin
package com.example.grpc

import greet.GreeterGrpcKt
import greet.HelloReply
import greet.HelloRequest
import io.grpc.ServerBuilder

class GreeterService : GreeterGrpcKt.GreeterCoroutineImplBase() {
    override suspend fun sayHello(request: HelloRequest): HelloReply =
        HelloReply.newBuilder()
            .setMessage("Hello, ${request.name}")
            .build()
}

fun main() {
    val server = ServerBuilder
        .forPort(9090)
        .addService(GreeterService())
        .build()
        .start()
    println("gRPC server on 9090")
    Runtime.getRuntime().addShutdownHook(Thread { server.shutdown() })
    server.awaitTermination()
}
```

**Client.kt**

```kotlin
package com.example.grpc

import greet.GreeterGrpcKt
import greet.HelloRequest
import io.grpc.ManagedChannelBuilder
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val channel = ManagedChannelBuilder
        .forAddress("localhost", 9090)
        .usePlaintext()
        .build()
    val stub = GreeterGrpcKt.GreeterCoroutineStub(channel)
    val reply = stub.sayHello(
        HelloRequest.newBuilder().setName("Roman").build()
    )
    println(reply.message)
    channel.shutdownNow()
}
```

После запуска клиент выведет `Hello, Roman`, подтверждая работу gRPC-вызова.

## Примеры сгенерированных классов {#Примеры-сгенерированных-классов}

**HelloRequestKt.kt, HelloReplyKt.kt:**\
Kotlin-версии сообщений; у каждого есть Builder, методы parseFrom, toByteArray.

**GreeterGrpcKt.kt содержит два класса:**

**GreeterCoroutineImplBase:**\
базовый abstract-класс, от которого наследуется сервер; нужно реализовать sayHello.

**GreeterCoroutineStub:**\
типобезопасный клиент; метод sayHello - обычный suspend.

**GreeterGrpc.java (не показан):**\
то же самое, но без корутин; остаётся, если нужен Java-код.

**HelloRequestKt.kt (protobuf-kotlin)**

```kotlin
// AUTO-GENERATED BY PROTOC, DO NOT EDIT
package greet

import com.google.protobuf.kotlin.*

@OptIn(ProtobufSyntaxSupport::class)
class HelloRequest private constructor(
    _name: String = ""
) : com.google.protobuf.GeneratedMessageLite<
        HelloRequest, HelloRequest.Builder>(DEFAULT_INSTANCE) {

    var name: String = _name
        private set

    // builder pattern
    class Builder : com.google.protobuf.GeneratedMessageLite.Builder<
            HelloRequest, Builder>(DEFAULT_INSTANCE) {
        fun setName(value: String): Builder = apply { instance.name = value }
        fun build(): HelloRequest = instance
    }

    companion object {
        private val DEFAULT_INSTANCE = HelloRequest()
        fun newBuilder(): Builder = Builder()
        @JvmStatic fun parseFrom(bytes: ByteArray) = DEFAULT_INSTANCE.parseFrom(bytes)
    }
}
```

**HelloReplyKt.kt**

```kotlin
package greet

import com.google.protobuf.kotlin.*

class HelloReply private constructor(
    _message: String = ""
) : com.google.protobuf.GeneratedMessageLite<
        HelloReply, HelloReply.Builder>(DEFAULT_INSTANCE) {

    var message: String = _message
        private set

    class Builder : com.google.protobuf.GeneratedMessageLite.Builder<
            HelloReply, Builder>(DEFAULT_INSTANCE) {
        fun setMessage(v: String): Builder = apply { instance.message = v }
        fun build(): HelloReply = instance
    }

    companion object {
        private val DEFAULT_INSTANCE = HelloReply()
        fun newBuilder(): Builder = Builder()
    }
}

```

**GreeterGrpcKt.kt (gRPC-Kotlin plugin)**

```kotlin
// AUTO-GENERATED BY PROTOC, DO NOT EDIT
package greet

import io.grpc.kotlin.*
import kotlinx.coroutines.flow.Flow

object GreeterGrpcKt {
    const val SERVICE_NAME: String = "greet.Greeter"

    abstract class GreeterCoroutineImplBase(
        coroutineContext: kotlin.coroutines.CoroutineContext = kotlinx.coroutines.Dispatchers.Default
    ) : AbstractCoroutineServerImpl(coroutineContext) {

        open suspend fun sayHello(request: HelloRequest): HelloReply =
            throw io.grpc.Status.UNIMPLEMENTED.asRuntimeException()

        final override fun bindService() = service {
            unaryRpc(
                method = METHOD_SAY_HELLO,
                implementation = ::sayHello
            )
        }
    }

    class GreeterCoroutineStub private constructor(
        channel: io.grpc.Channel,
        callOptions: io.grpc.CallOptions
    ) : AbstractCoroutineStub<GreeterCoroutineStub>(channel, callOptions) {

        suspend fun sayHello(request: HelloRequest): HelloReply =
            unaryRpc(
                channel,
                METHOD_SAY_HELLO,
                request,
                callOptions,
                HelloReply.getDefaultInstance()
            )

        override fun build(channel: io.grpc.Channel, callOptions: io.grpc.CallOptions) =
            GreeterCoroutineStub(channel, callOptions)
    }

    private val METHOD_SAY_HELLO =
        io.grpc.MethodDescriptor.newBuilder<HelloRequest, HelloReply>()
            .setType(io.grpc.MethodDescriptor.MethodType.UNARY)
            .setFullMethodName(io.grpc.MethodDescriptor.generateFullMethodName(
                SERVICE_NAME, "SayHello"))
            .setRequestMarshaller(protoLiteRequestMarshaller(HelloRequest.getDefaultInstance()))
            .setResponseMarshaller(protoLiteResponseMarshaller(HelloReply.getDefaultInstance()))
            .build()
}

```

[ Copyright: Roman Kryvolapov ](https://t.me/RomanKryvolapov)
