7

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

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

目前,我们正在使用Google 的 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 消息流,而不是只处理一个大消息。如果它只是一个大消息,我可以: - 获取快照文件 - 将文件解析为大 Java protobuf 消息,使用以前快照版本的 .proto 模式 - 将这个大 protobuf 消息转换为大 protobuf 消息新版本,使用 Dozer 和一些映射代码 - 将此新 protobuf 消息写入新文件,使用新版本的 .proto 模式

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

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

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

  • 如果你使用事件溯源或内存图像,你用什么来序列化你的域模型?JSON?XML?原型?还有什么?

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

4

3 回答 3

5

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

  • 二进制模式 - 最不冗长但不可读
  • 字符 - 表示命令和参数更具可读性并且还提供健壮的存储
  • 明文 - 用于调试目的

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

希望能给一些指点。

于 2013-06-07T11:27:52.397 回答
2

只是从我的头顶(实际上不知道你的快照文件会有多大):

你试过谷歌的 Gson JSON 库吗?它似乎同时提供版本控制(https://sites.google.com/site/gson/gson-user-guide#TOC-Versioning-Support)和流媒体(https://sites.google.com/site/gson/ streaming ) 用于基于 JSON 的文档。

既然我们正在讨论 JSON,那么将快照存储在例如 CouchDB ( http://en.wikipedia.org/wiki/CouchDB ) 文档中怎么样?

JSON 可能会占用更多空间,但它是可读的。

于 2013-06-03T20:51:35.210 回答
1

我见过的最佳选项列表在这里:https ://github.com/eishay/jvm-serializers/wiki 。你必须做一些快速测试,看看什么对你来说很快。关于流媒体,我必须查看此列表中的每个库。

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

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

于 2013-06-07T02:21:30.790 回答