我应该如何为事件采购序列化域模型快照

时间:2013-05-31 13:48:34

标签: java serialization cqrs snapshot event-sourcing

我们正在使用LMAX Disruptor构建应用程序。使用Event Sourcing时,您通常希望保留域模型的定期快照(有些人称之为Memory Image模式)。

我需要一个比我们目前用于在拍摄快照时序列化我们的域模型更好的解决方案。我希望能够以可读格式“漂亮地打印”此快照以进行调试,并且我希望简化快照模式迁移。

目前,我们正在使用Googles' Protocol Buffers将我们的域模型序列化为文件。我们选择了这个解决方案,因为协议缓冲区比XML / JSON更紧凑,使用紧凑的二进制格式似乎是一个很好的想法来序列化一个大的Java域模型。

问题是,Protocol Buffers是针对相对较小的消息而设计的,我们的域模型非常庞大。所以域模型不适合一个大的分层protobuf消息,我们最终将各种protobuf消息序列化到一个文件,如下所示:

for each account {
    write simple account fields (id, name, description) as one protobuf message
    write number of user groups
    for each user group {
        convert user group to protobuf message, and serialize it
    }
    for each user {
        convert user to protobuf message, and serialize it
    }
    for each sensor {
        convert sensor to protobuf message, and serialize it
    }
    ...
}

这很烦人,因为操纵异构protobuf消息流很复杂。如果我们有一个包含所有域模型的大型protobuf消息会更容易,例如:

public class AggregateRoot {
    List<Account> accounts;
}

--> convert to big hierarchical protobuf message using some mapping code:

message AggregateRootMessage {
    repeated AccountMessage accounts = 1;
}

--> persist this big message to a file

如果我们这样做,很容易将快照打印出来:只需阅读大的protobuf消息,然后使用protobuf的TextFormat对其进行漂亮打印。使用我们当前的方法,我们需要逐个读取各种protobuf消息,然后再打印它们,这更难,因为流中的protobuf消息的顺序取决于当前的快照模式,所以我们的漂亮打印工具需要注意这一点。

当我们的域模型发展时,我还需要一个工具来将快照迁移到新的快照模式。我仍然在研究这个工具,但这很难,因为我必须处理各种protobuf消息流,而不是只处理一个大消息。如果只是一条重要信息,我可以: - 拍摄快照文件 - 使用前一个快照版本的.proto模式将文件解析为一个大的Java protobuf消息 - 使用Dozer和一些映射代码将这个大的protobuf消息转换为新版本的大protobuf消息 - 使用新版本的.proto模式将新的protobuf消息写入新文件

但是由于我正在处理各种类型的protobuf消息流,我的工具需要按正确的顺序处理这个流。

所以,是的...我想我的问题是:

  • 您是否知道任何可以将大型域模型序列化为文件的序列化工具,没有protobuf的限制,可能使用流式传输来避免OutOfMemorryErrors?

  • 如果您使用事件源或内存映像,您使用什么来序列化您的域模型? JSON? XML? protobuf的?还有别的吗?

  • 我们做错了吗?你有什么建议吗?

3 个答案:

答案 0 :(得分:5)

我定义问题解决方案的方法是将“规范”与“传输语法”分开。现在,我们已经定义了我们需要处理有线表示的消息规范,这可能支持机器效率和人类可读性之间的不同需求;

  • 二进制模式 - 最简洁但不可读的
  • 字符 - 代表命令和参数更具可读性,并提供强大的存储空间
  • 明文 - 说出调试目的

解决方案必须提供可切换的行为。我们可以将我们的解决方案建立在ASN.1和相关的工具集上,这与工具语言和平台无关,尽管Java(Bouncycastle等人)提供了丰富的生态系统。我们在网络上使用了相当大的消息blob而没有已知的问题:)

希望它能给出一些指示。

答案 1 :(得分:2)

从我的头顶开始(实际上并不知道你的快照文件有多大):

您是否尝试过Google的Gson JSON库?它似乎为基于JSON的文档提供了版本控制(https://sites.google.com/site/gson/gson-user-guide#TOC-Versioning-Support)和流式传输(https://sites.google.com/site/gson/streaming)。

现在我们正在谈论JSON,如何将快照存储在例如CouchDB(http://en.wikipedia.org/wiki/CouchDB)文件?

JSON可能需要更多空间,但它是可读的。

答案 2 :(得分:1)

我看到的最佳选项列表如下:https://github.com/eishay/jvm-serializers/wiki。你必须做一些快速测试才能看到你的速度。关于流式传输,我必须查看此列表中的每个库。

我不确定我是否理解漂亮的打印问题。似乎没有必要用相同的技术解决有效的序列化和漂亮的打印,因为必须非常有效地进行漂亮的打印。如果你已经有一个javabean表示,那么我可能会将数据重新加载到bean中,然后使用Jackson将数据打印到JSON。

关于版本控制/迁移,您是否已经解决了如何启动运行新域模型的新版本代码的问题?如果是,那么为什么不在新版本启动后创建新的快照呢?