protobuf
Платформенно-независимый механизм сериализации структурированных данных, разработанный Google. Он позволяет определять структуры данных в специальных файлах .proto и затем генерировать исходный код для работы с этими структурами на различных языках программирования. Protobuf обеспечивает компактное представление данных, высокую производительность и обратную совместимость, что делает его идеальным выбором для систем хранения и обмена данными, таких как RPC-протоколы и конфигурационные файлы.
Особенности
- компактное бинарное представление данных с эффективной сериализацией и десериализацией;
- автоматическая генерация кода из определений
.protoс помощью компилятораprotoc; - обеспечение обратной совместимости за счёт механизма полевых тегов (field numbers) и правил эволюции схем;
- поддержка расширенных типов данных: вложенные сообщения, перечисления, одномерные и многомерные массивы, словари, объединения;
- интеграция с gRPC для генерации сервисов и клиентов RPC.
Основные компоненты
Библиотека Protobuf включает в себя язык описания схем, компилятор и набор библиотек времени выполнения для различных языков (подробнее с документацией можно ознакомиться здесь).
Язык описания протокола
Схемы данных описываются в файлах с расширением .proto на специальном языке. В них определяются структуры, поля с типами и тегами, а также сервисы для RPC.
Основные конструкции языка:
message— определение структуры данных с набором полей;enum— определение перечисления;oneof— объединение, в котором может быть установлено только одно поле из набора;map<key_type, value_type>— ассоциативный массив;repeated— поле, которое может повторяться (массив);serviceиrpc— определение RPC-сервисов для gRPC;- Пакеты (
package) и импорты (import) для организации кода и повторного использования.
Компилятор protoc
Компилятор protoc обрабатывает .proto файлы и генерирует код для целевого языка программирования. Он поддерживает плагины для расширения функциональности, например, для генерации gRPC-кода или специализированных сериализаторов.
Основные возможности protoc:
- Генерация классов для работы с сообщениями на выбранном языке;
- Поддержка параметров командной строки для настройки вывода (пути, префиксы, опции оптимизации);
- Интеграция с системами сборки (CMake, Bazel, Make) через плагины или прямые вызовы;
- Расширяемость через пользовательские плагины, написанные на любом языке, поддерживающем protobuf.
C++ API
Библиотека времени выполнения для C++ предоставляет классы и функции для работы с сообщениями, их сериализации, десериализации и рефлексии. Код, сгенерированный protoc, наследуется от базового класса google::protobuf::Message.
Основные классы и функции C++ API:
google::protobuf::Message— базовый класс для всех сообщений, предоставляющий методыSerializeToString(),ParseFromString(),SerializeToArray(),ParseFromArray(),DebugString()и др.;GetDescriptor()иGetReflection()— доступ к мета-информации о сообщении (поля, их типы, теги) для динамической работы;RepeatedPtrFieldиRepeatedField— контейнеры для полейrepeated;Map— реализация ассоциативных массивов для полейmap;EnumValueDescriptor— информация о значениях перечислений;TextFormat— парсинг и вывод в человеко-читаемый текстовый формат;util::JsonOptionsи связанные функции для работы с JSON-представлением.
Расширения и опции
Protobuf предоставляет механизм опций для настройки генерации кода и поведения сериализации. Опции могут быть как стандартными, так и пользовательскими.
Основные возможности расширения:
- Стандартные опции:
packed(для упаковкиrepeatedполей),deprecated,ctype,weakи др.; - Пользовательские опции — определяются в
.protoфайлах и могут быть использованы плагинами; Any— тип, позволяющий хранить произвольное сообщение с его типом;DurationиTimestamp— специальные типы для работы с временными промежутками и моментами.
Производительность и оптимизация
Protobuf спроектирован для высокой производительности. Библиотека использует эффективные алгоритмы сериализации и минимизирует накладные расходы.
Аспекты производительности:
- Отсутствие необходимости разбирать всю структуру для доступа к полям — сериализованные данные остаются в компактном виде;
- Возможность использования упаковки (
packed) дляrepeatedполей; - Наличие оптимизированных реализаций на C++ (арена-аллокаторы, избегание лишних копирований);