当前位置: 首页 > 知识库问答 >
问题:

Protobuf 3破坏合同可加性

司空宣
2023-03-14

我在分布式环境(“微服务”)中使用Protobuf 3和gRPC。

由于缺乏支持的未设置/缺失的值在原型3我得到了以下问题有关的合同可加性。

假设我有服务A和两个由团队B和团队C拥有的消费者服务B和C。

如果我将一个字段(比如布尔值)添加到服务a的契约中,首先它将具有默认值,该值将按原样写入数据库。

然后,B队使用更新后的合约更新服务进行对话,并将“true”作为字段值传递。然后,C队仍然使用旧合约并调用相同的服务——值被替换为false。但C队不是故意的,而且他们根本不知道那个字段。

因此,服务A根本无法延长合同,因为由于各种原因没有更新的消费者可能会损害数据,而服务A对此无能为力。

在Thrift中,这样的事情只需一次检查(. isSet())即可完成。

有一些肮脏的变通方法,比如将原语包装到对象中,但它强制使用库实现特定的引用检查(至少在java中),这似乎是相当糟糕的hack而不是健壮的解决方案。此外,最终,我必须将所有内容包装在包装器中,正如您想象的那样,这也不是很好的解决方案。

2017年,您在Protobuf 3中使用了哪些最佳实践来管理此类情况?您如何管理/协调团队/服务之间的合同更新?谢谢

注意:这个问题并不完全是关于如何实现未设置/缺失值的无检测,而是关于如何适应这种情况并遵循Protobuf 3的理念。

共有2个答案

施博文
2023-03-14

使用其中一种看起来比包装器更好/更干净。请参见以下类似问题的答案:https://stackoverflow.com/a/40552570/618259

席银龙
2023-03-14

我认为这里的问题是,以这种方式检查字段的存在并不是协议缓冲区的惯用用法(甚至在proto2中也不是)。听起来您正试图通过添加新字段来改进模式,但不读取这些新字段,除非您确定它们来自更新的客户端。惯用的方法是这样做:只要确保新字段的默认值是合理的,如果没有显式设置,就保持兼容的行为。然后,不要尝试检查是否存在--只需阅读字段,老客户机将获得良好的默认行为。

举个例子,假设您添加了一个可以启用或禁用的新功能。正确的方法是在请求消息中添加一个名为enable_new_feature的bool字段。由于旧客户端不知道这个字段,他们的请求将默认为false,因此他们会得到他们期望的旧行为。添加disable_new_feature字段可能是错误的方式,因为这样您确实会通过启用旧客户端不想要的东西来破坏旧客户端。

 类似资料:
  • 问题内容: 我知道Go中没有析构函数,因为从技术上讲没有类。这样,我用来执行与构造函数相同的功能。但是,有没有办法在终止的情况下创建某些东西来模仿析构函数,例如使用关闭文件?现在,我只是打电话给我,但这有点荒唐,我认为设计很差。正确的方法是什么? 问题答案: 在Go生态系统中,存在一种处理包装了宝贵(和/或外部)资源的对象的惯用语:一种专门用于释放该资源的特殊方法,通常通过该机制进行 显式 调用。

  • 编辑1: 我目前从一个Main类调用它,如下所示: } 原文: 解释后代码如下: 我有一个带有JavaConfig的Spring应用程序,称之为主应用程序,它从库中导入另一个Spring JavaConfig类。这个导入的JavaConfig应该用一个方面包装在主应用程序中创建的任何数据源,这个方面有一个自动连接的LogDelegator。 只要主应用程序只包含一个数据源,一切都正常。但是,当我向

  • 使用这个延迟加载代码,我的lightbox中断:单击一个图像显示lightbox,但没有图像。 通过检查inspector,我可以看到lightbox img标签没有值。我猜在延迟加载将属性和值分配给图像之前,lightbox会检查src。 如何解决此问题?

  • 问题内容: 我有一个用Restify和Mongoose在node.js中构建的REST服务,以及一个mongoDB,它的集合包含大约30.000个常规大小的文档。我的节点服务通过pmx和pm2运行。 昨天,节点突然开始通过消息“ MongoError:拓扑已被破坏”消除错误,仅此而已。我不知道这是什么意思,可能触发了什么。谷歌搜索时也没有太多发现。所以我想在这里问。 今天重新启动了节点服务后,错误

  • 我想为我的移动应用程序添加背景,但当我使用“this.props.children”时,eslint说我“必须使用解构道具分配”。为什么我可以分解这些道具? 这是我的密码, 当我使用这个代码时 当我使用这个代码时, 提前感谢您的帮助!

  • 在实际应用中,destroy方法的可能示例是什么?为什么一个正在运行的应用程序想要销毁它的bean?如果bean是由spring容器(比如ContextLoaderListener)为web应用程序创建的,那么如何重新创建这些bean,因为容器已经启动了。有没有办法在不重启应用服务器的情况下重启spring IoC容器?