【问题标题】:Protobuf 3 breaks contract additivityProtobuf 3 打破合约可加性
【发布时间】:2017-04-22 19:14:25
【问题描述】:

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

由于 Protobuf 3 中缺乏支持的未设置/缺失值,我遇到了以下与合同可加性相关的问题。

假设我有 Service ATeam B 拥有的几个消费者服务 BC 和 C 队。

如果我向服务 A 的合同添加一个字段,例如布尔值,首先它将具有默认值,该值将按原样写入数据库。

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

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

在 Thrift 中,此类事情只需通过单次检查 (.isSet()) 即可完成。

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

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

注意:这个问题不完全是关于 如何 实现对未设置/缺失值的检测,而是关于如何忍受它和@987654322 @。

【问题讨论】:

    标签: grpc protocol-buffers proto3 grpc-java


    【解决方案1】:

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

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

    【讨论】:

    • 谢谢,这是迄今为止我见过的最正确的处理方法。这意味着每当我不同意默认值时 - 我必须向这些字段另外发送 一个功能切换器
    • 然后,如果我需要强制新客户端遵循新规则,我可以通过要求功能切换器始终为真来强制执行合同,这将使旧客户端更新。这里的问题是,虽然还不清楚我什么时候可以摆脱这些功能标志,因为就像任何其他功能标志一样,这些标志也必须具有有限的生命周期,否则支持它们会带来太多负担。 ...这与拥有.isSet() 标志的情况基本相同,但对消费者来说更明确。我的方向正确吗?
    • 我认为这是正确的方向。我想说的是,一旦你的所有代码都被重新部署并且不再依赖它,就删除临时功能标志。
    【解决方案2】:

    使用oneof 看起来是包装器的更好/更清洁的替代品。查看类似问题的答案:https://stackoverflow.com/a/40552570/618259

    【讨论】:

    • 谢谢,您的评论让我意识到我需要更好地提出问题。更新说明,谢谢。 (是的,我知道这种解决方法,但这并不是我要问的)
    猜你喜欢
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    • 2023-01-19
    • 1970-01-01
    • 2018-07-09
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多