代码之家  ›  专栏  ›  技术社区  ›  bbmud

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

  •  2
  • bbmud  · 技术社区  · 16 年前

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

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

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

    你知道怎么做吗?

    3 回复  |  直到 16 年前
        1
  •  5
  •   cjs    16 年前

    这里的基本问题是,您已经有了一个完全不相关的模型,您正试图与关系数据库相匹配。那可不太管用。因此,从细节上向前看一秒钟,想想你的两个基本方向选择:

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

    2. 您可以坚持使用OO模型,并使用任何存储工具。

    对于第二个选项,您可以选择多种存储选项,您可以自由选择其中之一。

    RDBMS是一个选项,尽管您的模式是相当非关系的,并且您将无法利用RDBMS提供给您的一些强大的关系工具。我不会为此感到难过:如果你考虑过这两种模式,并决定去OO,你就有意识地做出了选择。最有可能的情况是,您的架构最终看起来像一个事件表,每个事件都有一个类型名,并且以键值形式显示每个事件的属性表。

    对象数据库将允许您以与内部使用相同的或多或少的形式保存您的资料,这可能很方便。但是请注意,如果您有性能问题,那么这个选项可能是最难分析和加速的。

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

    在这类事情上,我经常会遇到很多挫折,但正如Unix的管道、文本处理工具和脚本语言的成功所证明的那样,这些东西确实有效。Web服务器日志的标准在15年后仍然是文本格式,并查看它生成的所有分析工具。

    一旦你开始序列化,你就有了很多其他的存储选择。您也可以将序列化块存储在伯克利数据库或RDBMS中的列中。

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

    InvoiceCreate invoice_number=12345 date=2009-05-21 salesperson="Jill Gaines" ...
    

    这有许多优点:

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

    (再次强调一下,grep对这样的文件的操作速度是如此之快,您会感到惊讶:除非您有千兆字节的数据,或者您需要每秒执行数十个查询,否则这可能会提供您所需的所有性能。)

    这种方法的最后一点是:它是一种很好的、灵活的方法,可以体验到您所需要的实体和属性类型。虽然现在看起来你在这个领域中有数百种不同的东西,但你可能会发现,经过几个月的努力,你的理解已经发展到足够的程度,你可以用一种更简单的方式来建模。如果达到这一点,如果现在更适合您的模型,您可以考虑切换到RDBMS。

    这也可以作为一个卖点:如果你最终遇到了反对你不使用RDBMS的人(不管你是否需要它),在你设计模型的时候把它作为“体验阶段”来卖,并且在模型稳定下来后告诉他们你已经移动了。即使它没有移动,一旦你有了一个良好的工作系统,他们不会对你施加太大压力。

        2
  •  1
  •   dkretz    16 年前

    有一个很好的现实生活模拟,这是一个会计系统。每一个专业的会计系统基本上都是以交易日记账为基础的,这些日记账为财务状况的每一个变化提供了背景——相当于你的实体的状态变化。

    我已经使用了很多这种模式,它通常是一组(不太多)表,表的主键、时间戳和用户名最少。

    如果你想分享一下你的实体模型,我们可以讨论一些具体的案例。但通常情况下,表的结构会从与所记录的实际事件相关联的用例中删除。

    一些好处-

    1. 对于您的设计来说,his是一个很好的用户关系挂钩,因为它是数据库中为数不多的表之一,显然是不言自明的。(是的,这就是人们做的事情,当他们做的时候需要记录什么。)

    2. 它构建了一些现实生活中的灵活性,用于处理来自多个来源的事务,这些来源可能无法实时集成,但您需要重新构建时间顺序。(例如,从A点到B点和C点到D点的运输。)

        3
  •  0
  •   Steven A. Lowe    16 年前

    另一个选项是将相关的键和公共搜索值存储在常规列中,并将其余的值放入XML列(或等效的格式化文本,如JSON或任何适用于您的应用程序的文本)。

    这假设您所需要做的大部分时间都是从数据库中重新构造原始事件(如序列化/反序列化),而不是对每个可能的属性进行(有效)搜索。