Protocol Buffers: обзор
Protocol Buffers (protobuf) — бинарный формат сериализации данных от Google, компактнее и быстрее JSON, со строгой типизацией через .proto-схему.
Зачем нужно
JSON — текстовый формат, легко читаемый человеком, но избыточный: ключи повторяются в каждом объекте, числа хранятся как строки. Protobuf кодирует данные бинарно — сообщения в 3–10 раз меньше и десериализуются значительно быстрее. Это критично для микросервисной коммуникации с высокой нагрузкой. Protobuf является транспортным форматом gRPC.
Где используется
- gRPC — бинарный RPC-фреймворк Google (использует protobuf как единственный формат)
- Микросервисная коммуникация с жёсткими требованиями к производительности
- Мобильные API, где важен минимальный объём трафика
- Kafka и другие системы обмена сообщениями (Schema Registry)
Синтаксис .proto-файла
// user.proto
syntax = "proto3";
package myapp;
// Определение сообщения
message User {
int32 id = 1; // номер поля (1–536870911), не менять после релиза
string name = 2;
string email = 3;
UserRole role = 4;
repeated string tags = 5; // массив
Address address = 6; // вложенное сообщение
}
message Address {
string city = 1;
string country = 2;
}
enum UserRole {
USER_ROLE_UNSPECIFIED = 0; // всегда 0 как дефолт
USER_ROLE_ADMIN = 1;
USER_ROLE_EDITOR = 2;
}
// Сервис для gRPC
service UserService {
rpc GetUser(GetUserRequest) returns (User);
rpc ListUsers(ListUsersRequest) returns (stream User);
rpc CreateUser(CreateUserRequest) returns (User);
}
message GetUserRequest { int32 id = 1; }
message ListUsersRequest { int32 page = 1; int32 limit = 2; }
message CreateUserRequest { string name = 1; string email = 2; }
Сравнение с JSON
JSON (56 байт):
{"id":42,"name":"Anton","email":"anton@example.com"}
Protobuf (34 байта — ~40% компактнее):
<binary data: field tags + varint + raw bytes>
Скорость сериализации: protobuf в ~5–6 раз быстрее JSON
Генерация кода
# Установка protoc компилятора
# https://github.com/protocolbuffers/protobuf/releases
# Генерация JavaScript/TypeScript кода
protoc --js_out=import_style=commonjs:./out user.proto
# Для TypeScript через ts-proto
protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto \
--ts_proto_out=./out user.proto
Использование в Node.js (protobufjs)
// npm install protobufjs
const protobuf = require('protobufjs');
async function example() {
const root = await protobuf.load('user.proto');
const User = root.lookupType('myapp.User');
// Кодирование
const user = { id: 42, name: 'Антон', email: 'anton@example.com' };
const buffer = User.encode(User.create(user)).finish;
console.log('Размер:', buffer.byteLength, 'байт');
// Декодирование
const decoded = User.decode(buffer);
console.log(decoded.name); // Антон
}
Частые ошибки
- Изменение номера поля после релиза — ломает совместимость всех существующих сообщений
- Пропуск
USER_ROLE_UNSPECIFIED = 0в enum — protobuf3 требует нулевое значение - Использование protobuf там, где достаточно JSON — избыточная сложность для простых CRUD API
- Хранение бинарных protobuf-данных в PostgreSQL без документации схемы