0:00
[БЕЗ_ЗВУКА] Прежде
чем двигаться дальше, стоит поговорить о форматах сериализации.
В предыдущих видео мы видели активное использование json.
Также в примере с NET RPC я упоминал, что он использует формат gob.
В чем разница и почему один формат выгоднее или невыгоднее другого?
Сначала давайте рассмотрим json.
Вот код, который сериализует уже знакомую вам структуру Session.
В json эта структура занимает 40 байт,
хотя данных там вдвое меньше.
Дело в том, что json — это формат без схемы, схему он сериализует
прямо туда в виде имен полей.
Соответственно, вам нужно каждый раз сначала распаковать поле,
после этого распаковать тип данных.
Причем вам нужно проверять каждый символ, действительно каждый символ,
а не является ли он кавычкой, например, которая закрывает строку.
Или вдруг там перенос строки, который тоже нужно экранировать?
То есть формат json распаковать несколько накладнее, чем бинарный формат.
Он больше по размеру,
однако его плюсом является то, что он человекочитаем.
То есть вы можете открыть логи либо какой-то текстовый файл и посмотреть
глазами, что там есть.
Бинарный формат, как следует из названия, упакован гораздо плотнее,
он представлен не в текстовом виде, а в виде бинарных данных прямо, вот как есть.
За счет этого он гораздо легче в распаковке и может быть легче в упаковке.
Формат gob мы рассматривать не будем, потому что он специфичен для языка Go и
не очень широко распространен за его пределами.
Мы будем рассматривать формат protobuf,
protobuf — это формат, который разработан в компании Google.
Сейчас он достаточно широко распространен,
и я вам покажу, как он выглядит в бинарном виде.
Упаковка в этот формат, распаковка очень похожи на json:
json.Marshal и proto.Marshal, соответственно Marshal.
Теперь, сколько занимает эта же структура в protobuf.
Эта же структура в protobuf занимает 17 байт,
что более, чем в два раза меньше, чем json.
За счет чего?
Во-первых, protobuf — это формат с жестко заданной схемой.
То есть в json может быть любое количество полей, и, например,
в распаковке структур вы просто возьмете себе нужные.
С protobuf так не совсем получится,
вам нужна схема, вам нужен какой-то декодировщик этих полей.
Но сначала посмотрим, что лежит в этих 17 байтах.
Сначала у нас идет байт 10, в нем запакован
номер поля и его тип.
После этого — это у нас строковый тип — идет длина данных и сами данные.
Потом идет следующее поле, там идет тоже номер поля,
вместе с типом, которые упакованы в один байт, и опять-таки
длина данных 6 байт, вот эти 6 байт: 3 и 3, 6.
То есть для того чтобы, например, распаковать строку,
вам не нужно проходиться по каждому символу, вы просто копируете 6 байт и все,
вы знаете, что там уже все хорошо, что там нет никаких проблем
с экранированием или с внезапным концом строки.
Теперь я покажу,
каким образом используется этот формат, каким образом задается схема.
Формат protobuf описывается при помощи промежуточного языка EDL,
который описывает схему этого формата.
В данном случае у нас есть message,
message в Go переводится в структуру SessionID и Session.
Я задаю тип данных, имя этого поля и номер.
Обратите внимание, поля пакуются
в виде номеров, не в виде имени поля,
как, например, в json, а в виде номера.
За счет этого получается очень компактно.
Вы можете потом какие-то поля пропустить, например, добавить,
сделать вот так: ip = 3.
То есть формат расширяем, если каких-то полей в нем не будет, они будут null.
После этого вам нужно запустить внешний генератор кода,
который сгенерирует вам в случае с Go все структуры и
необходимый код для их десериализации.
Это запускается, всё, структура сгенерировалась.
И получаем вот такой файл.
Тут довольно много служебного кода, руками его трогать вам никогда не надо,
потому что в следующий раз он перезапишется.
И вот, например, структура SessionID: поле ID, строк,
ввод помощь для protobuf, структурные теги, то есть это для внутри bytes.
за номером ID, оно опционально,
наследие из второй версией protobuf, и имя.
Еще и для json сразу там все сгенерировалось.
И еще вспомогательные методы: сброс, привести к строке,
получить сообщение,
описание схемы в нем есть, ну и getter'ы для каждого из полей.
Теперь смотрим дальше.
Вот наше поле Session.
В нем тоже сгенерировалось два поля.
Ну и тут еще есть немножко, и в том числе схема там же есть.
Вроде кажется не очень удобно, каждый раз генерировать схему,
однако по этой схеме вы можете сгенерировать
код для других языков, не только для Go,
но и для «плюсов», для php, для json, для java, для python.
То есть, есть кодогенерация практически подо всё.
Это очень удобный формат, когда у вас очень много сообщений и вы
хотите сэкономить хотя бы на их сериализации, десериализации.
Формат protobuf используется в gRPC
как основной формат передачи данных,
который мы будем рассматривать дальше.
Следует заметить, что protobuf, конечно же,
не единственный формат в бинарной сериализации, который распространен.
Еще есть MessagePack и формат AVR.
Но мы их рассматривать не будем, а сосредоточимся на protobuf.
А теперь давайте перейдем уже к gRPC, посмотрим,
как при помощи protobuf можно сгенерировать весь код, нужный там,
и вдобавок ко всем структурам сгенерировать сразу еще и сервис.