Что такое Protobuf и как проектируются его схемы?

«Что такое Protobuf и как проектируются его схемы?» — вопрос из категории Архитектура, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Protobuf (Protocol Buffers) — это язык-независимый, платформенно-нейтральный, расширяемый механизм сериализации структурированных данных, разработанный Google. Его файлы (.proto) описывают структуру данных (сообщения, сервисы), на основе которой генерируется код для работы с этими данными на различных языках программирования.

Почему Protobuf? Protobuf используется для эффективной сериализации данных, обеспечивая компактный бинарный формат, что приводит к уменьшению размера передаваемых данных и повышению скорости их обработки по сравнению с текстовыми форматами, такими как JSON или XML. Он идеально подходит для межсервисного взаимодействия (RPC) и хранения данных.

Пример простого .proto файла (syntax proto3):

syntax = "proto3";

package myapp.data;

message Person {
  string name = 1;
  int32 age = 2;
  repeated string emails = 3;
  bool is_active = 4;
}

message Address {
  string street = 1;
  string city = 2;
  string zip_code = 3;
}

Ключевые особенности проектирования схем:

  • Синтаксис: Используется proto2 или proto3 (рекомендуется proto3 за его упрощенный синтаксис и отсутствие required полей).
  • Сообщения (message): Определяют структуру данных, аналогично классам или структурам.
  • Поля: Каждое поле имеет тип (скалярный, такой как int32, string, bool, или составной, как другое сообщение), имя и уникальный числовой тег (например, name = 1). Теги используются для идентификации полей в бинарном формате и должны быть стабильными.
  • Типы полей: singular (одно значение), repeated (список значений), map (словарь).
  • Генерация кода: Компилятор protoc использует .proto файл для создания классов или структур на выбранном языке (Python, Java, C++, Go и др.), которые позволяют легко сериализовать и десериализовать данные.

Пример использования в Python после компиляции: (Предполагается, что protoc --python_out=. person.proto был выполнен)

import person_pb2 # Сгенерированный модуль

# Создание объекта сообщения
person = person_pb2.Person(
    name="Alice", 
    age=30,
    emails=["alice@example.com", "alice.work@example.com"],
    is_active=True
)

# Сериализация в бинарный формат
serialized_data = person.SerializeToString()
print(f"Serialized data: {serialized_data}")

# Десериализация из бинарного формата
new_person = person_pb2.Person()
new_person.ParseFromString(serialized_data)

print(f"Deserialized name: {new_person.name}")
print(f"Deserialized age: {new_person.age}")
print(f"Deserialized emails: {new_person.emails}")

Проектирование Protobuf схем требует внимательности к обратной совместимости, так как изменения в схеме могут повлиять на уже развернутые системы.