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. Сгенерированные классы содержат методы:
SerializeToString()— сериализация в бинарную строку.ParseFromString(data)— десериализация из бинарной строки.- Геттеры и сеттеры для каждого поля.
Преимущества и недостатки
Преимущества
- Компактность: бинарный формат занимает в 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 Buffers | JSON | XML | Apache Avro | FlatBuffers |
|---|---|---|---|---|---|
| Формат | Бинарный | Текстовый | Текстовый | Бинарный | Бинарный |
| Размер данных | Очень малый | Средний | Большой | Малый | Минимальный |
| Скорость сериализации | Высокая | Средняя | Низкая | Высокая | Очень высокая |
| Читаемость | Нет | Да | Да | Нет | Нет |
| Строгая типизация | Да | Нет | Частично | Да | Да |
| Необходимость схемы | Да | Нет | Да (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 →