如何在数据库中保存事件日志数据?

bbm*_*mud 2 architecture domain-driven-design

在我的应用程序中,我强烈要求记录实体的每个事件,我正在考虑使用事件源模式,即所有域更改都有显式类,域对象的任何更改都只能使用这些事件类.然后,您可以根据需要回滚并重新应用这些更改,就像在源代码管理系统中一样.

这将为我解决许多问题,但我不知道如何将事件对象持久化到db.我可能会有数百种事件类型,因此我的选择有限:

  • 为每个事件类型构建一个表(数百个表?对实体的引用怎么样?)
  • 为所有事件构建一个巨大的表(有数千列?)
  • 以某种方式在db(??)中存储事件的二进制表示
  • 将它存储在一些单独的文件中(??)

你有什么想法可以做到这一点吗?

Cur*_*son 5

这里你的基本问题是你有一个完全不相关的模型,你试图匹配一个关系数据库.这不会很好.所以从细节中提升一秒钟,考虑一下方向的两个基本选择:

  1. 您可以尝试构建更多关系模型.如果你走这条路线,最好根据数据库本身来考虑它,并且或多或少地忽略了编程方面:什么模式最能表达你的业务领域?

  2. 您可以坚持使用OO模型,并使用任何存储空间.

对于第二个选项,您可以使用各种存储选项,您可以随意选择它们.

RDBMS是一种选择,虽然您的架构将是非关系型的,并且您将无法利用RDBMS为您提供的一些强大的关系工具.我不会对此感到沮丧:如果你考虑过这两种模式,并决定去OO,你就会有意识地做出这样的选择.很可能您的模式最终看起来像一个事件表,每个事件都有一个类型名称,以及键值形式的每个事件的属性表.

一个对象数据库可以让你以与你内部使用它相同的形式保存你的东西,这可能很方便.但请注意,如果您遇到性能问题,此选项可能是最难分析和加速的.

平面文件是一个有趣的选项:只需将对象序列化为一些合理的形式并将其写出来.这通常是最快的方法,因为它提供了(特别是如果你gzip文件)一种最快的格式来完成数据的全面扫描.如果您需要经常进行特定查询,只选择在整个集合中分布的非常小的数据子集,使用某种可以使用索引的DBMS可能会有所帮助,但如果您在无论如何,你大部分时间都在扫描的位置,DBMS只会减慢你的速度.请注意,通过将它们放在不同的文件中,您可以(并且可能会)将事物分成一个或甚至两个维度.如果您有十几个基本业务领域,您正在记录您经常单独查询的事件,则可以为每个事件使用单独的文件,并且您也可以在每个月或每年滚动这些文件.

我经常在这方面受到很多阻碍,但正如Unix管道,文本处理工具和脚本语言的成功所证明的那样,这些东西确实有效.Web服务器日志的标准在十五年后仍然是一种文本格式,并查看它产生的所有分析工具.

无论如何,一旦你进行了序列化,你就有了很多其他的存储选择.您可以将序列化块存储在Berkeley DB中,也可以存储在RDBMS中的列中.

至于序列化本身,你也有各种各样的选择,你应该考虑.大多数语言都有某种标准的二进制序列化格式,它可以序列化所有内容并带回整个对象.这些通常很复杂,并且有版本问题,等等.我通常发现使用简单的自定义格式更容易.我可以像带有名称和键值列表的ASCII行一样简单:

InvoiceCreate invoice_number=12345 date=2009-05-21 salesperson="Jill Gaines" ...
Run Code Online (Sandbox Code Playgroud)

这有很多好处:

  • 它是人类可读的,因此易于调试.
  • 这样的文件可以使用grep,sed,awk等进行处理,以进行即席查询.
  • 它是人类可写的,有利于调试,测试和修复损坏的数据.
  • 它很容易解析.
  • 它没有链接到任何特定的对象结构,格式甚至语言,因此您可以轻松更改应用程序,而无需担心与序列化数据的兼容性.
  • 当您需要更改数据格式时,可以轻松更新数据本身(通常使用简单的sed脚本!).

(再强调一下,你会惊讶于grep如何快速操作这样的文件:除非你有数GB的数据,否则你需要每秒进行几十次查询,这可能会提供你需要的所有性能.)

关于这种方法的最后一件事:它是一种很好的,灵活的方式来体验你需要什么样的实体和属性.虽然现在看来你在域中有数百种不同的东西,你可能会发现,经过几个月的努力,你的理解已经发展到足以让你能够以更简单的方式对其进行建模.如果达到这一点,您可以考虑切换到RDBM,如果它现在更适合您的模型.

这也可以作为一个卖点:如果你最终有人反对你不使用RDBMS(无论你是否需要它),只需在制定模型时将其作为"体验阶段"出售并告诉他们,一旦模型稳定下来,你就会动起来.即使它没有移动,一旦你有一个良好的工作系统,他们不太可能给你施加很大的压力.

  • 我喜欢将我的二进制对象存储在数据库中,然后我提取出我将索引和查询的特定值.效果很好. (2认同)