【问题标题】:Reliable events log (the not really Event Sourcing)可靠的事件日志(不是真正的事件溯源)
【发布时间】:2018-12-24 05:58:10
【问题描述】:

我正在实现一个系统,该系统应该以一致的方式存储所有事件,但同时我想通过使用某种混合方法来保持一致性。尽管事件溯源的概念很清楚,所有的突变都进入 ES 日志,然后消费者创建物化视图,但让我感到困扰的是最终一致性,因为系统现在是全系统异步的。

CQRS + ES 方法建议这应该在 UI 级别解决,要求客户端等待。假设,我有一些接近 stackoverflow 的东西。当我完成这个问题时,我会点击“发布你的问题”按钮,网站会立即将我带到我的问题。使用 ES 方法,点击“发布您的问题”将意味着我的问题将被推送到 ES 商店以供稍后处理,我将看到“我们正在发布您的问题,请稍等”,对吗?这就是我想要避免的。我想出了以下架构:

CreateQuestionCommand command
    = new CreateQuestionCommand(uint userId, string questionBody, string[] tags)
QuestionSavedEvent result
    = command.execute() // save to DB as usual, return events
saveToES(result) // ugghhhhh...

如果我忘记了saveToES,ES 日志就会变得不一致并且实际上毫无用处。如果我团队中的任何开发人员忘记了它,同样的事情 - 整个 ES 日志只是一次性的。

这种方法是否可行?这将解决 ES 的缺点,即最终一致性,并且仍然保留它的优点,即始终可靠的事件日志。

我遇到了一些解决方案。

1.

  • 一些数据库将允许访问提交日志,这可能是事件的来源,但这种方法有点乏味,因为阅读提交日志并没有说明可能需要的应用程序业务逻辑,即您只需从提交日志中读取UPDATE users SET loggedIn = "2018-12-30 10:00:00" WHERE id = 1,本例中的事件只是UserUpdated,但在应用程序级别它可能会更好UserLoggedIn

ebay 采用的另一种方法(据称,我在一本关于 ES 的书中读过它,但不记得标题了)

2.

  • 开始事务 1
  • UPDATE domain.users SET loggedIn = "2018-12-30 10:00:00" WHERE id = 1
  • 启动事务 2(内部 trx)
  • INSERT INTO events.log SET event = "{name: UserLoggedIn, userId: 1}", timestamp = "2018-12-30 10:00:00"
  • 提交事务 2
  • 提交事务 1

然后另一个进程可以轮询此events.log 以将数据发布到 ES 存储中。 按照设计,每个数据修改器都应该被强制返回一个event 和一个指向transaction 1 的指针,这就是系统永远不会“忘记”向数据库提交事件的方式。

第三种方法是使用 2PC(两阶段提交),它需要分布式事务管理器,消息代理和数据库都支持 2PC,由于这个限制,我什至没有研究这个方向。

所以,我只是想知道,根据您的经验,保持系统“老式”(同步)但同时保证可靠事件日志的最佳方法是什么? (是的,我想要来自两个世界的所有好东西:))

免责声明:我知道这个问题有多臃肿,如果您因此认为这个问题不属于社区,请告诉我,我会删除它。

【问题讨论】:

    标签: transactions cqrs event-sourcing consistency eventual-consistency


    【解决方案1】:

    这种方法是否可行?这将解决 ES 的缺点,即最终一致性,并且仍然保留它的优点,即始终可靠的事件日志。

    这并没有什么问题,小心操作——重要的是确保您的事件和您的状态存储在同一个事务中,因此存储在同一个数据库中。

    在状态边存储事件的想法已经存在了一段时间。你会经常发现这样的讨论集中在“领域事件”的概念上,并使用一个聚合引发的事件来触发其他地方的行为。例如,请参阅 Udi Dahan 在Reliable Messaging without Distributed Transactions 上的演讲。

    在此过程中,我们放弃了 CQRS —— 取而代之的是,我们有一个将当前状态和事件历史存储在一起的单一逻辑数据模型。

    这是很好;如果 CQRS 不能解决您遇到的问题,那么您不应该使用它。

    将读模型与写模型分开相当于缓存;要获得好处,您必须解决缓存失效问题,这是two hard problems 之一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      • 1970-01-01
      • 2019-01-29
      • 1970-01-01
      • 1970-01-01
      • 2017-04-06
      • 2020-05-27
      相关资源
      最近更新 更多