1

我正在考虑为我们的内部服务之间的通信引入一种强类型(读取 - 使用预定义模式)数据交换格式。例如,我猜想 Thrift 或 Cap'n Proto 之类的东西。

使用它而不是像 JSON 这样的东西至少有两个明显的优势(对我来说)是

  1. 您将知道服务可以预期的数据的确切格式(因此在通信时留出更少的歧义和错误空间)和
  2. 该实现通常为您反序列化原始消息,并提供访问对象的方法。

与 JSON 之类的方法相比,这条路线的实际缺点是什么?

对于上下文——我们的系统由用 python 和 java 编写的服务组成——未来可能还有其他语言,并通过服务和消息代理(如 rabbitmq)之间的 HTTP 端点进行通信。

4

2 回答 2

2

与每个强类型系统一样,毫无疑问,一个主要优点是如果你犯了错误,它会在过程的早期失败,通常是在编译阶段,这是一件好事。

恕我直言,第二大优势是您已经说过的:因为字段和类型是众所周知的,所以编译器、库和相关代码知道期望什么数据,因此可以以更有效的方式编写/组织 - 或者简而言之:性能

相比之下,loose 类型的系统(如 Avro)虽然允许更大的灵活性而无需重新编译,但也有另一面:在运行时容易出现消息内容错误的缺点。

这是因为定义模糊的系统只定义了有效文档的语法(例如 XML),而将文档中内容的消息级语义留给了上层。强类型系统了解那些在编译时已经内置的消息级语义。因此,很容易检测/确定特定文档或消息是否不仅格式正确而且关于消息内容是否有效。如果您需要对丢失定义的系统执行相同操作,则需要在运行时提供附加信息(如 XML 模式)并根据它验证您的文档。

底线

在大多数情况下,您更喜欢哪种系统或多或少是个人喜好问题。我会根据这个问题做出决定,即我必须处理的数据有多大的可变性。如果使用强类型系统有意义,我会这样做,因为我非常喜欢尽早了解错误和错误。

但是,如果需要非常灵活的数据结构,那么走另一条路可能更有意义。尽管在强类型系统之上设计一个丢失类型的模式肯定是可能的,但它有点矛盾,你最终会得到一些过于复杂但过于通用的东西。

于 2015-02-25T21:13:18.383 回答
1

打字

带有类型标签的传入消息非常自由,只要可以在不阅读所有消息的情况下判断传入消息是什么。如果是这样,那么您不再关心消息顺序。这是因为消息的接收者很容易处理发送的任何内容。所以你可以有一个应用程序,它只是坐在那里接受它得到的任何东西,并且只做适合每个人的任何事情。

格式

允许您定义值和大小约束的模式语言非常有用。这意味着消息的发送者不会意外发送无效消息。此外,接收者可以自动判断传入消息是否符合模式。这是实现网络服务的真正好处;大部分消息验证已为您完成!

通过大小限制,我的意思是您可以指定数组在模式中的长度,并且生成的代码将拒绝处理更长或更短的数组。通过值约束,想象一个名为“bearing”的消息字段;您可能希望将其限制在 0 到 359 之间。

这些都允许您对接口是什么做出清晰、明确的陈述,并自动执行。最近发生了多少安全漏洞,其中一些网络接口数据验证实施不当......

选项

完成这一切的一种序列化标准是 ASN.1。我使用的工具采用 ASN.1 模式并生成用于序列化和反序列化的代码,自动检查是否满足值和大小约束,并告诉您传入的消息类型是什么。ASN.1 的工具可能相当陈旧,需要更新。如果更新,它将是各种用途的理想选择,提供二进制和文本格式。

现在也有 JSON 模式,它们似乎有类型、值和大小限制。这可能是您正在寻找的。

我相当确定 Google Protocol Buffers 不能很好地进行类型标记,也没有进行值和大小限制。我在 GPB 架构中看到了以下注释:

// 不能大于 10。

如果这就是写入模式的内容,那么模式语言可以说是不够的......

我不确定 Thrift,我不确定它是否有价值限制(如果我错了,请有人纠正我!)。

缺点

一个都想不出来!它会激怒开发人员;他们认为很好的代码很容易被发现产生垃圾信息,这让他们非常恼火......

于 2015-02-25T21:14:14.100 回答