gRPC-GoJuniorTechnical

Что такое Protocol Buffers (protobuf) и почему gRPC использует его вместо JSON?

Protocol Buffers — бинарный формат сериализации с компактным encoding по номерам полей. gRPC использует его для меньшего размера сообщений, быстрого парсинга и строгой типизации через .proto-схему.

Что такое Protocol Buffers

Protocol Buffers (protobuf) — язык описания схем данных и бинарный формат сериализации от Google. Схема описывается в .proto-файлах; инструмент protoc генерирует код для десятков языков. Каждое поле кодируется парой (номер поля, значение) без имён — это ключевое отличие от JSON.

Сравнение Protobuf vs JSON

  • Размер: Protobuf в среднем в 3–10 раз меньше JSON. Поля кодируются varint-числами вместо строк.
  • Скорость парсинга: бинарный формат парсится в 5–7 раз быстрее JSON; нет необходимости в лексере строк.
  • Типизация: все типы строго определены в .proto; опечатки в именах полей — ошибка компиляции, а не runtime-баг.
  • Эволюция схемы: поля идентифицируются по номерам, а не именам — переименование поля обратно совместимо.
  • Читаемость: JSON читаем человеком без декодера; бинарный protobuf требует инструментов (protoscope, grpcurl).

Пример .proto и генерация Go-кода

syntax = "proto3";
package product;
option go_package = "example.com/gen/product";

message Product {
  string id    = 1;
  string name  = 2;
  double price = 3;
  repeated string tags = 4;
}
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
protoc --go_out=. --go-grpc_out=. product.proto

Использование сгенерированного кода

package main

import (
	"fmt"
	"log"

	"google.golang.org/protobuf/proto"
	pb "example.com/gen/product"
)

func main() {
	p := &pb.Product{
		Id:    "sku-42",
		Name:  "Gopher Plush",
		Price: 19.99,
		Tags:  []string{"toys", "go"},
	}

	// Сериализация
	data, err := proto.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("protobuf bytes: %d\n", len(data)) // ~25 байт

	// Десериализация
	var p2 pb.Product
	if err := proto.Unmarshal(data, &p2); err != nil {
		log.Fatal(err)
	}
	fmt.Println(p2.Name)
}

Обратная совместимость полей

// v2 — безопасное добавление поля
message Product {
  string id       = 1;
  string name     = 2;
  double price    = 3;
  repeated string tags = 4;
  string currency = 5; // новое поле — старые клиенты игнорируют
}
// НЕЛЬЗЯ: менять тип поля 3 с double на int64 — нарушает wire-совместимость
// НЕЛЬЗЯ: переиспользовать номер 3 для другого поля после удаления старого

Подводные камни

  • Нельзя переиспользовать номера полей; удалённые поля следует помечать через reserved 3; и reserved "price";.
  • Значения по умолчанию в proto3 (0, "", false) не отличимы от явно выставленных; используйте optional или google.protobuf.BoolValue для явного null.
  • Бинарный формат не самодокументирован — без .proto-файла декодировать данные крайне сложно; храните схемы в Schema Registry.
  • Изменение типа существующего поля (например, int32int64) нарушает wire-формат даже при совпадении имени.
  • JSON-транскодинг (grpc-gateway) преобразует proto в JSON по правилам camelCase — имя user_id станет userId; фронтенд должен об этом знать.
  • Версия protoc и плагинов protoc-gen-go должна быть согласована во всей команде; разные версии могут генерировать несовместимый код.
  • proto.Clone не копирует неизвестные поля корректно в некоторых версиях; для глубоких копий проверяйте поведение вашей версии SDK.

Common mistakes

  • Давать ответ про protobuf и JSON в gRPC только на уровне определения, не показывая поведение в реальном приложении.
  • Игнорировать границы ответственности вокруг темы «protobuf и JSON в gRPC»: кто отменяет работу, кто владеет ресурсом и где формируется ответ клиенту.
  • Не связывать protobuf и JSON в gRPC с observability, тестированием или безопасностью, когда это влияет на продакшен-поведение.

What the interviewer is testing

  • Точно объясняет, что именно делает protobuf и JSON в gRPC и где это используется в Go-коде.
  • Связывает protobuf и JSON в gRPC с корректным lifecycle запроса, отменой, конкурентностью или конфигурацией сервера там, где это уместно.
  • Не изобретает API и опирается на реальные контракты официальной документации.

Sources

Related topics

Что такое Protocol Buffers (protobuf) и почему gRPC использует его вместо JSON? | Talanto