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