Гайды

gRPC: основы и пример на Python и Go

Protobuf, кодоген, unary и streaming, mTLS и metadata, ошибки и когда выбирать gRPC вместо REST.

~11 мин чтения

gRPC: основы и пример на Python и Go

gRPC — RPC поверх HTTP/2 с Protobuf как контрактом: строгие типы, потоковые вызовы (client/server/bidi streaming), кодоген из .proto. Альтернатива JSON REST для внутренних сервисов. Сравнение стилей API — GraphQL vs REST; OpenAPI — спецификация и генерация клиентов.


1. IDL: пример service.proto

protobuf
syntax = "proto3";
package demo.v1;

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

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

Генерация:

bash
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. service.proto

2. Python: сервер (скелет)

python
from concurrent import futures
import grpc
import service_pb2
import service_pb2_grpc

class Greeter(service_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):
        return service_pb2.HelloReply(message=f"Hello, {request.name}")

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    service_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port("[::]:50051")
    server.start()
    server.wait_for_termination()

Клиент: stub + channel (grpc.insecure_channel("localhost:50051")).

Дедлайны: на клиенте оборачивайте контекст в context.WithTimeout; на сервере проверяйте context.Err() в длинных циклах. Без этого отменённые клиенты продолжают грузить CPU.

Отладка без кода клиента: grpcurl вызывает методы по имени, если включён server reflection (в проде reflection часто отключают).


3. Go: сервер (идея)

protoc с --go_out и --go-grpc_out; реализация интерфейса, grpc.NewServer(), RegisterGreeterServer.


4. Streaming

  • Unary — один запрос, один ответ.
  • Server streaming — один запрос, поток ответов (логи, прогресс).
  • Client streaming — загрузка чанками.
  • Bidi — чат, прокси-потоки.

5. mTLS и metadata

Для продакшена — TLS на канале, часто взаимная TLS между сервисами. Metadata в gRPC — аналог заголовков HTTP для трейсинга (grpc-trace-bin), JWT и т.д.


6. Ошибки и коды

context.set_code(grpc.StatusCode.NOT_FOUND) + set_details. Клиент различает сетевые сбои и бизнес-ошибки.


7. Keepalive и лимиты сообщений

На долгоживущих каналах задайте keepalive, чтобы прокси и балансировщики не рвали «тихие» соединения; ограничьте размер кадра, чтобы один крупный запрос не выбил память.

python
opts = [
    ("grpc.keepalive_time_ms", 10_000),
    ("grpc.keepalive_timeout_ms", 5_000),
    ("grpc.max_send_message_length", 8 * 1024 * 1024),
    ("grpc.max_receive_message_length", 8 * 1024 * 1024),
]
ch = grpc.insecure_channel("svc:50051", options=opts)

В Go — grpc.WithDefaultCallOptions, grpc.KeepaliveParams на grpc.NewClient / dial options (см. документацию вашей версии google.golang.org/grpc).


8. Когда gRPC уместен

  • Внутренняя микросервисная сеть, низкая латентность, контракт важнее человекочитаемого JSON в браузере.
  • Для публичного браузерного API чаще REST/GraphQL (gRPC-web — отдельная история).

9. Чек-лист

  • Версия в package или в имени сервиса (GreeterV2).
  • Keepalive и лимиты размера сообщения на клиенте и сервере.
  • Таймауты на канале и deadline в RPC.
  • Совместимость proto3 optional / JSON mapping по гайду команды.
  • Регенерация stubs в CI при изменении .proto.

Дальше: тег gRPC