Serialization 协议缓冲区-如何实现可扩展性和向后兼容性?

Serialization 协议缓冲区-如何实现可扩展性和向后兼容性?,serialization,protocol-buffers,Serialization,Protocol Buffers,请帮助我了解协议缓冲区内部实现的向后兼容性和可扩展性属性 如何在删除数据字段时实现向后兼容性?我设想生成的数据访问代码为数据流中不存在的属性返回空值,并且使用者代码必须始终专门检查这些空值并相应地执行操作。空值将如何标准化 同样在这种情况下,旧代码如何“知道”该属性不再存在于数据流中 我设想一种解决方案是,永远不会从内部流规范中删除旧数据,只使用空值替换,但通过字段的内部版本控制也可能实现同样的效果 也许有一个更清楚的问题:旧代码如何知道忽略新版本的.proto规范添加的新数据?这可能比1)更简

请帮助我了解协议缓冲区内部实现的向后兼容性和可扩展性属性

  • 如何在删除数据字段时实现向后兼容性?我设想生成的数据访问代码为数据流中不存在的属性返回空值,并且使用者代码必须始终专门检查这些空值并相应地执行操作。空值将如何标准化

    同样在这种情况下,旧代码如何“知道”该属性不再存在于数据流中

    我设想一种解决方案是,永远不会从内部流规范中删除旧数据,只使用空值替换,但通过字段的内部版本控制也可能实现同样的效果

  • 也许有一个更清楚的问题:旧代码如何知道忽略新版本的.proto规范添加的新数据?这可能比1)更简单,因为在内部序列化结构中有一个size字段,并且一次只读取那么多字节,同时也只在结构的末尾添加新字段

  • 试图理解所有这些,以便扩展旧的数据格式,从而作为一个辅助项目提供代码和数据之间的向后/向前兼容性

    编辑:格式化


    谢谢

    一些背景资料, 在协议缓冲区中定义一个字段,如

     optional string msg = 1;
    
    数字(示例中的1)用于标识数据消息(或数据记录)中的字段,并与程序使用的原始消息相匹配

    协议缓冲区存储数据消息,如

        FieldId1 Data1
        FieldId2 Data2
            .....
        FieldIdn Datan
    
    其中fieldId由字段编号和字段类型组成。如果字段没有任何数据,则不会存储在输出消息中(记录)。所以你可能有

       FieldId3 Data3
       FieldId7 Data7
       FieldId11 Data11
    

    回答你的问题:

  • 在协议缓冲区中,每个字段都有这些属性中的一个属性:必需可选重复。因此,要删除字段,可以将其设置为可选,而不在其中存储任何值。有些人通常将大多数字段设置为可选字段

  • 协议将数据消息中的字段编号与协议定义中的字段编号匹配。至少在java中,存在未知字段映射,其中存储了任何额外字段


  • 必须删除文档字段(包括字段名字段号),以确保从不重复使用字段名/编号


    如果重复使用字段,则可能会破坏现有代码

    谢谢您的回答!因此,如果一个字段被声明为可选的,那么这意味着代码需要处理缺少数据字段的情况——这使得它从一开始就至少与未来的数据定义有一点向前兼容。看起来索引是数据格式的灵活性所在。谢谢你的解释。两个都同意。我怀疑如果某个字段不再需要,您会将其设置为可选,但会继续填写。这样,发送和接收系统可以独立更新。当所有接收系统都已更新时,该字段可能会被完全删除。如果您碰巧需要一个必须
    反序列化
    并重新
    序列化
    消息的代理,则需要注意。(例如,聚合器、扇出器或……)在protobuf
    语法2
    中,任何新的未知字段都会在
    反序列化过程中保留。但是在protobuf
    语法3
    中,
    反序列化将删除任何未知字段。它们不会传递到重新序列化阶段。因此,首先更新您的代理,然后更新服务器和客户端,或者使用语法2生成的代码保留代理。@BruceMartin-Do document某处您将
    完全删除的字段,因为意外重用这些字段名或字段ID号可能会导致破坏性更改,可能会导致以后的数据丢失问题
    syntax 3
    允许您将它们标记为保留,但是
    syntax 2
    没有内置的方法来记录这些更改。