Почему требуется и необязательно удаляется в буфер протокола 3

216

Я недавно использую gRPCс proto3, и я заметил это requiredи optionalбыл удален в новом синтаксисе.

Кто-нибудь любезно объяснит, почему обязательные / дополнительные удаляются в proto3? Подобные ограничения просто необходимы для того, чтобы сделать определение надежным.

Синтаксис proto2:

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
}

Синтаксис proto3:

syntax = "proto3";
message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
yjzhang
источник

Ответы:

393

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

Позвольте мне объяснить больше причин, почему requiredполя должны использоваться экономно. Если вы уже используете Proto, вы не можете добавить обязательное поле, потому что старое приложение не будет предоставлять это поле, а приложения в целом не справляются со сбоем. Вы можете убедиться, что все старые приложения обновляются в первую очередь, но можно легко ошибиться, и это не поможет, если вы храните прототипы в любом хранилище данных (даже недолговечном, например, memcached). Такая же ситуация применяется при удалении обязательного поля.

Многие обязательные поля были «очевидно» обязательными, пока ... их не было. Допустим, у вас есть idполе для Getметода. Это очевидно требуется. Кроме того, позже вам может потребоваться изменить значение idс int на строку или с int32 на int64. Это требует добавления нового muchBetterIdполя, и теперь у вас осталось старое idполе, которое должно быть указано, но в конечном итоге полностью игнорируется.

Когда эти две проблемы объединены, количество полезных requiredполей становится ограниченным, и лагеря спорят о том, имеет ли оно ценность. Противники requiredбыли не обязательно против идеи, но против ее нынешней формы. Некоторые предлагали разработать более выразительную библиотеку валидации, которая могла бы проверять requiredчто-то более продвинутое name.length > 10, в то же время не забывая иметь лучшую модель сбоев.

Proto3 в целом, кажется, предпочитает простоту, а requiredудаление проще. Но, возможно, более убедительно, удаление имеет requiredсмысл для proto3 в сочетании с другими функциями, такими как удаление присутствия полей для примитивов и удаление переопределяющих значений по умолчанию.

Я не разработчик protobuf и никоим образом не авторитетен в этом вопросе, но я все еще надеюсь, что объяснение будет полезным.

Эрик Андерсон
источник
23
Ага. См. Также это расширенное объяснение того, что может оказаться
Kenton Varda
9
Опционально не удаляется; все не обязательно в proto3. Но да, видимость поля (has_field) была удалена для примитивов . Если вам нужна видимость поля, используйте wrappers.proto, в котором есть такие сообщения, как StringValue. Поскольку они являются сообщениями, доступно has_field. Это фактически «бокс», который распространен во многих языках.
Эрик Андерсон
9
Наоборот, похоже, что «опционально» было удалено в proto3. Каждое поле существует и заполняется значением по умолчанию. У вас нет возможности узнать, было ли заполнено примитивное поле пользователем или по умолчанию. Поля сообщения, которые в основном являются указателями, являются необязательными, поскольку они могут иметь нулевое значение.
Бродяга
15
я чувствую, что protobuf - это язык, специально разработанный для того, чтобы начать пламенные войны
Рэнди Л
5
Похоже, что большинство людей не хотят создавать версии своих API. Им легче сделать все необязательным для «обратной совместимости».
Holoceo
42

Вы можете найти объяснение в этом выпуске Github :

Мы удалили обязательные поля в proto3, потому что обязательные поля обычно считаются вредными и нарушающими семантику совместимости protobuf. Идея использования protobuf заключается в том, что он позволяет добавлять / удалять поля из определения протокола, при этом полностью совместимый с предыдущими / более старыми двоичными файлами. Обязательные поля нарушают это, хотя. Вы никогда не сможете безопасно добавить обязательное поле в определение .proto и не можете безопасно удалить существующее обязательное поле, поскольку оба эти действия нарушают совместимость проводов. Например, если вы добавите обязательное поле в определение .proto, двоичные файлы, созданные с новым определением, не смогут анализировать данные, сериализованные с использованием старого определения, поскольку обязательное поле отсутствует в старых данных. В сложной системе, где. Прото-определения широко распространены во многих различных компонентах системы, добавление / удаление обязательных полей может легко разрушить несколько частей системы. Мы неоднократно сталкивались с производственными проблемами, и практически везде в Google запрещено, чтобы кто-либо добавлял / удалял обязательные поля. По этой причине мы полностью удалили обязательные поля в proto3.

После удаления «обязательного» «необязательного» просто избыточно, поэтому мы также удалили «необязательного».

maiyang
источник
6
Я не понимаю этого; В чем разница между удалением сообщения после десериализации и десериализацией? он будет удален более старым клиентом, поскольку он не содержит нужного поля (например, id).
Шмуэль Х.
6
Я склонен согласиться с @ShmuelH. обязательные поля будут частью API, так или иначе. Ну, это поддерживается автоматически через синтаксис, данный обеим сторонам, или скрытый в бэкэнде, он все еще там. Может также сделать его видимым в определении апи
Cruncher
7
Я полностью согласен с @ShmuelH. поля в API так или иначе требуются, и это полезно знать клиенту. Это заставляет меня думать, что мы просто еще не получили правильную версию.
Патрикбаркер
6
Еще один голос за @ShmuelH. Если вы измените свой API обратно несовместимым способом (добавив обязательное поле), то наверняка вы хотите, чтобы ваш синтаксический анализатор обнаружил это? Версия ваших API! Вы даже можете сделать это полностью в Protobuf, если хотите, используя oneof { MessageV1, MessageV2, etc. }.
Тимммм
1
Это не может оправдать наличие обязательных полей изначально. А добавление обязательного поля является несовместимым изменением и обычно должно обрабатываться изменением версии протокола (т. Е. Нового типа сообщения).
кан