为什么在协议缓冲区3中删除了必需和可选项

时间:2015-08-04 05:23:27

标签: protocol-buffers grpc proto3

我最近将gRPCproto3一起使用,我注意到requiredoptional已被新语法删除。

有人会解释为什么在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;
}

3 个答案:

答案 0 :(得分:290)

required的用处一直是许多辩论和火焰战争的核心。双方都有大型营地。一个阵营喜欢保证价值存在并且愿意忍受其局限但另一阵营感到required危险或无益,因为它无法安全地添加或删除。

让我解释为什么required字段应该谨慎使用的原因。如果您已经在使用proto,则无法添加必填字段,因为旧应用程序将不提供该字段,并且应用程序通常不能很好地处理故障。您可以确保首先升级所有旧应用程序,但它很容易出错,如果您将原型存储在任何数据存储区中,它就无济于事(即使是短暂的,如同memcached的)。删除必填字段时也会出现同样的情况。

许多必需的字段“显然”需要,直到......他们不是。假设您有id方法的Get字段。那显然是 。除此之外,您可能需要将id从int更改为string,或将int32更改为int64。这需要添加新的muchBetterId字段,现在您将留下必须指定的旧id字段,但最终会被完全忽略。

当这两个问题结合起来时,有益required字段的数量变得有限,并且难民营争论它是否仍有价值。 required的反对者并不一定反对这个想法,而是它目前的形式。有人建议开发一个更具表现力的验证库,可以检查required以及更name.length > 10等更高级的内容,同时确保更好的故障模型。

Proto3整体似乎更倾向于简单,required删除更简单。但也许更有说服力,在与其他功能结合使用时删除required对proto3有意义,例如删除基元的字段存在以及删除覆盖的默认值。

我不是一个protobuf开发者,在这个问题上绝不具有权威性,但我仍然希望这个解释很有用。

答案 1 :(得分:22)

您可以在此protobuf Github issue中找到说明:

  

我们在proto3中删除了必填字段,因为必填字段通常被认为有害并且违反了protobuf的兼容性语义。使用protobuf的整个想法是,它允许您从协议定义中添加/删除字段,同时仍与新/旧二进制文件完全向前/向后兼容。必填字段可解决此问题。您永远不能将必填字段安全地添加到.proto定义中,也不能安全删除现有的必填字段,因为这两个操作都会破坏导线的兼容性。例如,如果将必填字段添加到.proto定义,则使用新定义构建的二进制文件将无法解析使用旧定义序列化的数据,因为旧数据中不存在必填字段。在一个复杂的系统中,.proto定义在系统的许多不同组件之间广泛共享,添加/删除必填字段可能很容易导致系统的多个部分崩溃。我们已经多次看到由这种情况引起的生产问题,并且在Google内部几乎所有地方都禁止任何人添加/删除必填字段。因此,我们完全删除了proto3中的必填字段。

     

在删除“必需”之后,“可选”只是多余的,因此我们也删除了“可选”。

答案 2 :(得分:6)

可选字段在 protobuf 3.15 中返回