Открыть сервис

Protocol Buffers

Protocol Buffers (protobuf) — это язык описания данных и бинарный протокол сериализации структурированных данных, разработанный в компании Google. Protocol Buffers предназначен для замены текстовых форматов, таких как XML и JSON, в задачах обмена данными между сервисами, хранения конфигураций и сериализации объектов в распределённых системах. Основное преимущество — высокая скорость обработки и компактность результирующих данных.

История

Разработка Protocol Buffers началась в Google в 2001 году как внутренний проект для оптимизации обмена данными между серверами. К 2008 году система созрела настолько, что Google выпустил её в открытый доступ под лицензией BSD. Первая публичная версия (protobuf 2) была представлена в 2008 году и сразу привлекла внимание разработчиков благодаря скорости и простоте. В 2016 году вышла версия 3 (proto3), которая упростила синтаксис, добавила поддержку новых языков (например, Go, C#, Ruby) и устранила некоторые ограничения предыдущей версии. С тех пор Protocol Buffers активно развивается сообществом и используется в таких проектах, как gRPC, Apache Kafka, TensorFlow и многих других.

Архитектура и принцип работы

Protocol Buffers основан на двух ключевых компонентах: языке описания схемы (proto-файлы) и компиляторе protoc. Разработчик описывает структуру данных в файле с расширением .proto, используя простой синтаксис, напоминающий C-подобные языки. Затем компилятор protoc генерирует на основе этого описания исходный код на одном из поддерживаемых языков программирования. Сгенерированный код содержит классы для сериализации и десериализации данных в бинарный формат.

Синтаксис proto-файлов

Пример простого proto-файла для версии proto3:

```protobuf syntax = "proto3";

message Person { string name = 1; int32 age = 2; repeated string phone_numbers = 3; } ```

Ключевые элементы:

  • syntax — указывает версию языка (proto2 или proto3).
  • message — определяет структуру данных. Поля внутри сообщения нумеруются (1, 2, 3 и т.д.) — эти номера используются в бинарном формате для идентификации полей.
  • repeated — указывает, что поле является массивом (списком).
  • Типы полей: int32, string, bool, float, double, а также вложенные сообщения и перечисления (enum).

Процесс компиляции

Компилятор protoc читает .proto-файл и генерирует код на целевом языке. Например, для Python он создаёт файлы с расширением _pb2.py, для C++.pb.h и .pb.cc, для Java — .java. Сгенерированные классы содержат методы:

Преимущества и недостатки

Преимущества

  • Компактность: бинарный формат занимает в 3–10 раз меньше места, чем XML или JSON, за счёт отсутствия тегов и пробелов.
  • Скорость: сериализация и десериализация выполняются в десятки раз быстрее, чем для текстовых форматов.
  • Строгая типизация: ошибки на этапе компиляции, а не выполнения.
  • Обратная совместимость: при добавлении новых полей старые клиенты игнорируют их, а новые — пропускают отсутствующие.
  • Мультиязычность: поддержка C++, Java, Python, Go, C#, Ruby, JavaScript, Objective-C, PHP, Dart и других.
  • Автоматическая генерация кода: разработчику не нужно писать парсеры вручную.

Недостатки

  • Нечитаемость: бинарный формат невозможно просмотреть в текстовом редакторе без специальных инструментов.
  • Сложность отладки: для анализа данных требуется преобразование в читаемый формат (например, в JSON).
  • Необходимость компиляции: изменения в схеме требуют перекомпиляции и обновления всех клиентов.
  • Отсутствие встроенной поддержки сложных структур: например, для работы с JSON-like объектами (с произвольными ключами) требуется использовать google.protobuf.Struct.
  • Больший размер при малых объёмах данных: для единичных записей накладные расходы на заголовки могут быть выше, чем у JSON.

Применение

Protocol Buffers широко используется в высоконагруженных распределённых системах, где важна производительность и экономия трафика. Основные области применения:

  • gRPC: фреймворк удалённого вызова процедур (RPC), использующий Protocol Buffers как формат сериализации по умолчанию.
  • Хранение конфигураций: бинарные конфигурационные файлы, которые быстро загружаются.
  • Обмен данными между микросервисами: в системах с тысячами запросов в секунду.
  • Встроенные системы: где ограничен объём памяти и пропускная способность каналов.
  • Анализ данных и машинное обучение: например, TensorFlow использует protobuf для описания графов вычислений.
  • Мобильные приложения: для уменьшения размера передаваемых данных.

Версии и эволюция

Proto2 (2008)

Первая публичная версия. Поддерживала обязательные поля (required), необязательные (optional) и повторяющиеся (repeated). Имела строгие правила валидации.

Proto3 (2016)

Основные изменения:

  • Убраны обязательные поля — все поля стали необязательными.
  • Введены стандартные значения (например, 0 для чисел, пустая строка для строк).
  • Добавлена поддержка языков Go, C#, Ruby, Objective-C.
  • Упрощён синтаксис: убраны ключевые слова required и optional.
  • Введены map-поля (ассоциативные массивы).
  • Добавлены Any-типы для работы с произвольными сообщениями.

Сравнение с альтернативами

ХарактеристикаProtocol BuffersJSONXMLApache AvroFlatBuffers
ФорматБинарныйТекстовыйТекстовыйБинарныйБинарный
Размер данныхОчень малыйСреднийБольшойМалыйМинимальный
Скорость сериализацииВысокаяСредняяНизкаяВысокаяОчень высокая
ЧитаемостьНетДаДаНетНет
Строгая типизацияДаНетЧастичноДаДа
Необходимость схемыДаНетДа (DTD/XSD)ДаДа
Поддержка языковМногоВсеВсеМногоМного
Обратная совместимостьХорошаяПлохаяХорошаяХорошаяХорошая

Инструменты и экосистема

Для работы с Protocol Buffers существует ряд инструментов:

  • protoc — основной компилятор, поддерживающий все целевые языки.
  • protoc-gen-go, protoc-gen-java и т.д. — плагины для генерации кода на конкретных языках.
  • grpcurl — утилита для тестирования gRPC-сервисов.
  • protobuf-editor — онлайн-редакторы для просмотра и редактирования proto-файлов.
  • protobuf-json — библиотеки для преобразования protobuf в JSON и обратно.
  • protobuf-net — реализация для платформы .NET.

Примеры использования

В gRPC

В gRPC сервисы описываются в proto-файлах с помощью ключевого слова service. Например:

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

После компиляции генерируются клиентские и серверные заглушки, которые автоматически обрабатывают сериализацию и десериализацию.

В конфигурационных файлах

Protocol Buffers используется для хранения конфигураций в бинарном виде, что ускоряет загрузку и уменьшает размер файлов. Например, в проекте TensorFlow модели сохраняются в формате .pb (protobuf).

В мобильных приложениях

В Android-приложениях protobuf применяется для сериализации данных в кэше или при передаче по сети, что экономит трафик и ускоряет работу.

Критика и ограничения

Основные критические замечания:

  • Сложность отладки: бинарный формат затрудняет ручной анализ данных, особенно при ошибках.
  • Зависимость от схемы: при изменении схемы необходимо обновлять все клиенты, иначе возможны ошибки десериализации.
  • Отсутствие встроенной поддержки для динамических структур: например, для JSON-like объектов с произвольными ключами требуется использовать google.protobuf.Struct, что увеличивает сложность.
  • Проблемы с версионированием: хотя proto3 упростил обратную совместимость, неправильное использование (например, удаление полей) может привести к сбоям.

Источники

  • Google Developers. «Protocol Buffers Documentation».
  • «Protocol Buffers: Google's Data Interchange Format». O'Reilly Media.
  • «gRPC: Up and Running». Kasun Indrasiri, Danesh Kuruppu. O'Reilly Media.
  • «High Performance Browser Networking». Ilya Grigorik. O'Reilly Media.
  • Документация проекта Protocol Buffers на GitHub (github.com/protocolbuffers/protobuf).

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →