Глубокое понимание принципов и инженерной практики ProtoBuf (обзор)

protobuf структура данных

Как кросс-платформенный, независимый от языка и расширяемый метод сериализации структурированных данных, ProtoBuf широко используется для обмена и хранения данных в сети. С развитием Интернета неоднородность системы будет становиться все более и более заметной, а потребность в кросс-языковости будет становиться все более и более очевидной.В то же время gRPC также, вероятно, заменит Restful.Как волшебное оружие для g RPC кросс-языковости и высокой производительности, необходим наш технический персонал

Глубокое понимание принципа ProtoBuf заложит основу для будущих технических обновлений и выбора.

Я подытожу прошлый процесс обучения и практический опыт в серии статей, и буду обсуждать и изучать с вами.Я надеюсь, что вы можете что-то получить.Конечно, если есть неточности, вы можете критиковать и исправлять их.

Эта серия статей в основном включает:

  1. Глубокое понимание принципов и инженерной практики ProtoBuf (обзор)
  2. Глубокое понимание принципов и инженерной практики ProtoBuf (кодирование)
  3. Глубокое понимание принципов и методов разработки ProtoBuf (сериализация)
  4. Глубокое понимание принципов ProtoBuf и инженерной практики (инженерная практика)

1. Что такое ProtoBuf

ProtoBuf (Protocol Buffers) — это кроссплатформенный, независимый от языка и расширяемый метод сериализации структурированных данных, который можно использовать для обмена и хранения данных в сети.

В механизме сериализации структурированных данных ProtoBuf является гибким, эффективным и автоматизированным.По сравнению с обычными XML и JSON он описывает ту же информацию.После сериализации ProtoBuf имеет меньший объем данных, более быструю сериализацию/десериализацию, проще.

Как только структура данных для обработки определена, соответствующий код может быть сгенерирован с помощью инструмента генерации кода ProtoBuf. Используйте Protobuf для описания вашей структуры данных один раз, затем используйте различные языки (proto3 поддерживает C++, Java, Python, Go, Ruby, Objective-C, C#) или из различных потоков для описания ваших структурированных данных Легко читать и писать.

2. Почему ProtoBuf

Вы можете подумать, что Google изобрел ProtoBuf для решения проблемы скорости сериализации, но на самом деле это не так.

ProtoBuf изначально использовался Google для решения протокола запроса/ответа индексного сервера. До ProtoBuf у Google уже был формат запроса/ответа для ручной обработки кодирования и декодирования запроса/ответа. Он также может поддерживать многоверсионные протоколы, но код недостаточно элегантен:

if (protocolVersion=1) {
    doSomething();
} else if (protocolVersion=2) {
    doOtherThing();
} ...

Если это очень четкое соглашение о формате, это сделает новое соглашение очень сложным. Потому что разработчик должен убедиться, что все серверы между инициатором запроса и фактическим сервером, обрабатывающим запрос, понимают новый протокол, прежде чем переключать коммутатор, чтобы начать использовать новый протокол.

Это проблема, связанная с низкой совместимостью версий и совместимостью между старыми и новыми протоколами, с которой сталкивался каждый разработчик серверов.

Для решения этих проблем и был создан ProtoBuf.

Изначально ProtoBuf поставлялся со следующими двумя функциями:

  • Легче вводить новые поля, а промежуточный сервер, которому не нужно проверять данные, может просто проанализировать и передать данные, не зная всех полей.
  • Форматы данных более информативны, может обрабатываться на различных языках (C++, Java и т. д.).

Эта версия ProtoBuf по-прежнему требует рукописного кода синтаксического анализа.

Однако, поскольку система медленно развивается и развивается, ProtoBuf имеет больше возможностей:

  • Автоматически генерируемый код сериализации и десериализации позволяет избежать ручного синтаксического анализа. (Официально предоставляет инструменты автоматической генерации кода, в основном для всех языковых платформ).
  • Помимо использования для обмена данными, ProtoBuf используется как удобный формат с самоописанием для сохранения данных.

ProtoBuf теперь является языком общения Google для обмена и хранения данных. В дереве кодов Google определено 48 162 различных типа сообщений, включая 12 183 файла .proto. Они используются как в RPC-системах, так и для сохранения данных в различных системах хранения.

ProtoBuf был создан для решения проблемы совместимости старых и новых протоколов (старших и младших версий) на стороне сервера, и его имя также очень предусмотрительно — «буфер протоколов». Лишь позже он постепенно перерос в передачу данных.

Буферы протокола названы в честь:

Why the name "Protocol Buffers"?

The name originates from the early days of the format, before we had the protocol buffer compiler to generate classes for us. At the time, there was a class called ProtocolBuffer which actually acted as a buffer for an individual method. Users would add tag/value pairs to this buffer individually by calling methods like AddValue(tag, value). The raw bytes were stored in a buffer which could then be written out once the message had been constructed.

Since that time, the "buffers" part of the name has lost its meaning, but it is still the name we use. Today, people usually use the term "protocol message" to refer to a message in an abstract sense, "protocol buffer" to refer to a serialized copy of a message, and "protocol message object" to refer to an in-memory object representing the parsed message.

3. Как использовать ProtoBuf

3.1 Рабочий процесс протокола ProtoBuf

Видно, что для протокола сериализации пользователю нужно обратить внимание только на сам бизнес-объект, то есть на определение idl, а код сериализации и десериализации нужно только сгенерировать инструментом.

3.2 Определение сообщения ProtoBuf

Сообщения ProtoBuf описаны в файле idl (.proto). В этом примере используется дескриптор сообщения customer.proto:

syntax = "proto3";

package domain;

option java_package = "com.protobuf.generated.domain";
option java_outer_classname = "CustomerProtos";

message Customers {
    repeated Customer customer = 1;
}

message Customer {
    int32 id = 1;
    string firstName = 2;
    string lastName = 3;

    enum EmailType {
        PRIVATE = 0;
        PROFESSIONAL = 1;
    }

    message EmailAddress {
        string email = 1;
        EmailType type = 2;
    }

    repeated EmailAddress email = 5;
}


Приведенное выше сообщение относительно простое: «Клиенты» содержит несколько «Клиентов», «Клиент» содержит поле идентификатора, поле «имя», поле «фамилия» и набор электронных писем.

В дополнение к этим определениям в верхней части файла есть три строки, которые помогают генератору кода:

  1. Прежде всего, синтаксис = "proto3" используется для версии синтаксиса idl. В настоящее время существует две версии, proto2 и proto3. Эти две версии имеют несовместимые синтаксисы. Если не указано, синтаксис по умолчанию - proto2. Поскольку proto3 поддерживает больше языков, чем proto2, и имеет более лаконичный синтаксис, в этой статье используется proto3.

  2. Во-вторых, есть домен пакета, определение. Эта конфигурация используется для вложения сгенерированных классов/объектов.

  3. Определена опция java_package. Генератор также использует эту конфигурацию для вложения сгенерированных источников. Разница здесь в том, что это только для Java. Есть две конфигурации, используемые для того, чтобы генератор вел себя по-разному при создании кода на Java и JavaScript. То есть классы Java создаются в пакете com.protobuf.generated.domain, а объекты JavaScript создаются в домене пакета.

ProtoBuf предоставляет больше опций и типов данных, эта статья не будет вдаваться в подробности, вы можете обратиться к ней, если вам интересноздесь.

3.3 Генерация кода

Сначала установите протокол компилятора ProtoBuf,здесьСуществует подробное руководство по установке, после завершения установки вы можете использовать следующую команду для создания исходного кода Java:

protoc --java_out=./src/main/java ./src/main/idl/customer.proto

Выполните команду из корневого пути проекта и добавьте два параметра: java_out, который определяет ./src/main/java/ как выходной каталог кода Java, и ./src/main/idl/customer.proto — это файл . каталог файлов proto.

Сгенерированный код очень сложный, но, к счастью, его использование очень простое.

        CustomerProtos.Customer.EmailAddress email = CustomerProtos.Customer.EmailAddress.newBuilder()
                .setType(CustomerProtos.Customer.EmailType.PROFESSIONAL)
                .setEmail("crichardson@email.com").build();

        CustomerProtos.Customer customer = CustomerProtos.Customer.newBuilder()
                .setId(1)
                .setFirstName("Lee")
                .setLastName("Richardson")
                .addEmail(email)
                .build();
        // 序列化
        byte[] binaryInfo = customer.toByteArray();
        System.out.println(bytes_String16(binaryInfo));
        System.out.println(customer.toByteArray().length);
        // 反序列化
        CustomerProtos.Customer anotherCustomer = CustomerProtos.Customer.parseFrom(binaryInfo);
        System.out.println(anotherCustomer.toString());

3.4 Данные о производительности

Мы просто используем клиентов в качестве модели для создания и выбора небольших объектов, обычных объектов и крупных объектов для сравнения производительности.

Длительность сериализации и сравнение размера данных после сериализации

Десериализация требует времени

Дополнительные данные о производительности могут относиться кОфициальный эталон

4. Резюме

Выше описано, что такое ProtoBuf, его предыстория и основное использование.

преимущество:

1. Высокая эффективность

С точки зрения объема сериализованных данных по сравнению с текстовыми протоколами, такими как XML и JSON, ProtoBuf кодируется методом T-(L)-V (TAG-LENGTH-VALUE), и его не нужно разделять символами ", { , }, : и т. д. При этом используется варинтное сжатие на уровне кодирования, поэтому для описания одной и той же информации сериализуемый объем ProtoBuf значительно меньше, а сетевой трафик, потребляемый при передаче в сети, меньше , а сетевые ресурсы ограничены, а требования к производительности очень высоки.В сценариях с высокой нагрузкой рекомендуется использовать протокол ProtoBuf.

// 我们简单做个对比
// 要描述如下JSON数据
{"id":1,"firstName":"Chris","lastName":"Richardson","email":[{"type":"PROFESSIONAL","email":"crichardson@email.com"}]}
# 使用JSON序列化后的数据大小为118byte
7b226964223a312c2266697273744e616d65223a224368726973222c226c6173744e616d65223a2252696368617264736f6e222c22656d61696c223a5b7b2274797065223a2250524f46455353494f4e414c222c22656d61696c223a226372696368617264736f6e40656d61696c2e636f6d227d5d7d
# 而使用ProtoBuf序列化后的数据大小为48byte
0801120543687269731a0a52696368617264736f6e2a190a156372696368617264736f6e40656d61696c2e636f6d1001

С точки зрения скорости сериализации/десериализации, по сравнению с XML и JSON, сериализация/десериализация ProtoBuf быстрее, в 20-100 раз быстрее, чем XML.

2. Поддержка кроссплатформенности, многоязычности

ProtoBuf не зависит от платформы: Android и ПК или C# и Java могут использовать ProtoBuf для безбарьерной связи.

proto3 поддерживает C++, Java, Python, Go, Ruby, Objective-C, C#.

3. Хорошая масштабируемость и совместимость

Благодаря функции обратной совместимости после обновления структуры данных старая версия все еще может быть совместима, что также является проблемой, которую ProtoBuf доверили решить в начале своего рождения. Потому что компилятор пропустит обработку нераспознанных новых полей.

4. Простота использования

ProtoBuf предоставляет набор инструментов компиляции, которые могут автоматически генерировать сериализованный и десериализованный шаблонный код, так что разработчикам нужно обращать внимание только на idl бизнес-данных, что упрощает работу по кодированию и декодированию и сложность многоязычного взаимодействия.

недостаток:

Плохая читабельность и отсутствие самоописания

XML, JSON являются самоописываемыми, а ProtoBuf — нет.

ProtoBuf — бинарный протокол, и закодированные данные плохо читаются, без idl-файла бинарный поток данных не понять, что не удобно для отладки.

Однако Charles уже поддерживает протокол ProtoBuf, просто импортируйте файл описания данных.Подробнее см.Charles Protocol Buffers

Кроме того, поскольку поток двоичных данных не может быть проанализирован без файла idl, ProtoBuf может в определенной степени защитить данные, повысить порог взлома основных данных и снизить риск кражи основных данных.

5. Ссылка

  1. Википедия

  2. Сериализация и десериализация

  3. Официальный эталон

  4. Charles Protocol Buffers

  5. choose-protocol-buffers

Автор: Ли Гуаньюнь