我们正在考虑一种基于scala的Akka持久性应用的序列化方法。我们认为持久化事件可能会随着时间的推移而“进化”,因此我们希望支持模式演化,并且首先考虑Avro。
我们希望避免在每条消息中包含完整的模式。但是,在可预见的将来,这个Akka持久性应用程序是唯一一个序列化和反序列化这些消息的应用程序,因此我们认为不需要单独的模式注册表。
通过检查avro和各种scala库的文档,我看到了将模式包含在消息中的方法,以及如何通过使用模式注册中心来使用它“模式-无”,但是中间的情况如何呢?没有模式的正确方法是什么,但在某种程度上包括一个标识符,以便能够查找反序列化对象的正确模式(在本地部署的代码库中可用)?我会直接创建一个模式来表示我的case类,但是为模式版本增加一个“标识符”字段,然后在运行时具有某种类型的标识符->模式的内存映射吗?
另外,是否为模式的每个版本设置一个序列化/反序列化类的正确方法,以便它知道如何将每个版本转换为/从最新版本?
最后,有关于如何测试模式演化的建议吗?例如,将消息存储在akka-persistence中,然后实际更改case类的定义,然后杀死参与者并确保其正确发展。(我不知道如何在运行时更改case类的定义。)
发布于 2018-02-16 18:53:33
花了更多时间在这个问题上,下面是我想出的答案。
使用avro4s,您可以使用默认的data输出流来包含每个序列化消息的架构。或者,您可以使用binary输出流,它只是在序列化每个消息时忽略架构。(“二进制”在这里有点用词不当,因为它所做的只是省略了模式。无论是哪种情况,它仍然是一个Array[Byte]。)
Akka本身提供了一个Serializer特征或一个SerializerWithStringManifest特征,它将自动在序列化的对象中包含一个“模式标识符”字段。因此,在创建自定义序列化程序时,可以扩展适当的特征,定义模式标识符,并使用binary输出流。当这些技术结合在一起时,您将成功地在包含模式标识符的同时使用无模式序列化。
一种常见的技术是“指纹”你的模式--把它当作一个字符串,然后计算它的摘要(MD5,SHA-256,什么的)。如果您构建了一个从指纹到模式的内存映射,这可以作为应用程序的内存中模式注册表。
因此,在反序列化时,传入对象将具有用于序列化模式的模式标识符(“写器”)。在反序列化时,您应该知道用于反序列化模式的标识符( "reader")。Avro4s支持为您指定两个使用构建器模式的方法,因此avro可以将对象从旧格式转换为新格式。这就是你支持“模式进化”的方式。因为这是如何工作的,您不需要为每个模式版本单独的序列化程序。您的自定义序列化程序将知道如何发展您的对象,因为这是Avro免费提供给您的部分。
至于单元测试,您最好的选择是探索性测试。实际上,在您的测试中定义一个案例类的多个版本,以及它的模式的多个伴随版本,然后通过编写将在该模式的不同版本之间演化一个对象的测试来探索Avro是如何工作的。
不幸的是,这与您正在编写的代码没有直接关系,因为在测试代码时很难模拟实际更改您正在测试的代码。
我开发了一个原型,演示了其中的几个答案,它是可在github上查阅。它使用avro、avro4s和akka持久性。对于这一次,我演示了一个更改的代码基,它实际上是跨提交更改的--您可以签出提交#1,运行代码,然后移动到提交#2等等。它针对cassandra运行,因此它将演示需要使用新模式进行演化的事件,所有这些事件都不需要使用外部模式注册表。
https://stackoverflow.com/questions/48591800
复制相似问题