【问题标题】:Lagom | Return Values from read side processor拉戈姆 |读取端处理器的返回值
【发布时间】:2018-06-01 03:22:35
【问题描述】:

我们正在使用 Lagom 来开发我们的一组微服务。这里的诀窍是,虽然我们使用事件源并将事件持久化到 cassandra 中,但我们也必须将数据存储在其中一个图形数据库中,因为由于用例,它将是为大多数查询提供服务的数据库.

根据 Lagom 的文档,在命令处理程序将事件持久保存到 cassandra 之后,必须在 ReadSideProcecssor 中完成对 Graph 数据库(或任何其他数据库)的所有插入,遵循 CQRS 的理念。

现在这是我们面临的问题。我们认为ReadSideProcecssor 是一个监听器,在事件生成并持久化后触发。我们想要的是我们可以将响应从ReadSideProcecssor 返回到ServiceImpl。例如,将用户添加到系统时,必须将图形生成的唯一 ID 作为响应标头之一返回。由于响应是从 setCommandHandler 而不是 ReadSideProcessor 构建的,因此如何在 Lagom 中实现这一点。

此外,我们需要确保如果由于图形端的任何错误,API 应该通知客户端请求失败,但 ReadSideProcessor 中发生的异常不会传播到 PersistentEntity 或 @987654329 @ 班级。如何也能做到这一点?

非常感谢任何帮助。

【问题讨论】:

    标签: cqrs event-sourcing lagom


    【解决方案1】:

    读取端处理器不是附加到命令的侦听器 - 它实际上与持久实体完全断开连接,它可能在不同的节点上运行,在不同的时间,甚至可能在未来几年,如果你添加一个新的读取端处理器,它首先与历史上的所有旧事件同步。如果读取端处理器与命令同步连接,那么它就不是CQRS,命令端和查询端之间就不存在隔离。

    读取端处理器本质上是轮询数据库以获取新事件,并在检测到它们时对其进行处理。您可以随时添加新的读取端处理器,它会从所有历史记录中获取所有事件,而不仅仅是添加的新事件,这是事件溯源的一大优点,您无需预测从一开始就满足您的所有查询需求,您可以在查询需要时添加它们。

    进一步解释为什么您不希望两者之间建立联系 - 如果事件持续成功,但图表数据库上的更新失败会发生什么?也许图形数据库崩溃了。该命令是否必须重试?必须删除事件吗?如果进行更新的节点在有机会解决问题之前就崩溃了,会发生什么?现在您的读取端与您的实体处于不一致的状态。连接它们会导致在许多故障情况下出现不一致 - 例如,例如,当您向公用事业公司更新地址,但您的账单仍然转到旧地址时,您联系他们,他们说“是的,您的新地址是已在我们的系统中更新”,但它们仍会转到旧地址 - 如果您尝试将读取端和写入端连接在一起,那将是您注册用户的那种糟糕的用户体验。断开连接允许 Lagom 确保您在写入端发出的事件与在读取端消耗它们之间的一致性。

    因此,为了解决您的具体问题:ID 生成应该在写入端完成,或者,如果在读取端生成后续 ID,它还应该提供一种将写入端 ID 映射到读取端的方法侧面标识。至于在读取端处理错误 - 所有验证都应在写入端完成 - 写入端应确保它永远不会发出无效事件。

    现在如果读取端处理器遇到无效的东西,那么它有两个选择。一种选择是它可能会失败。在许多情况下,这是一个不错的选择,因为如果某些内容无效或不一致,那么您很可能有错误或某种形式的损坏。您不想做的是继续处理,好像一切都很愉快,因为这可能会使数据损坏或不一致变得更糟。相反,读取端处理器停止,然后您的监控应该检测到错误,您可以进入并找出错误是什么或修复损坏。当然,这样做也有不利之处,您的读取端将开始落后于写入端,而它无法处理新事件。但这也是 CQRS 的一个优势 - 写入端能够继续工作,继续强制执行一致性等,故障仅与读取端隔离,并且仅在更新读取端时发生。由于此错误,您的整个系统不会出现故障并拒绝接受新请求,而是将其隔离到问题所在。

    读取端的另一个选项是它可以将错误存储在某处 - 例如,将事件存储在死信表中,或提出某种故障单,然后继续处理。这样,您可以在事后去修复事件。这确保了更高的可用性,但确实存在这样的风险,即如果它未能处理的事件对后续事件的处理很重要,那么您可能只会让自己陷入更大的混乱。

    现在,这确实对您能做什么和不能做什么引入了具体限制,但我无法真正预料到那些对您的用例没有具体了解的人知道如何解决这些限制。一个常见的约束是设置验证——例如,您如何确保电子邮件地址对系统中的单个用户是唯一的? Greg Young(CQRS 专家)写了这篇关于这类问题的博文:

    http://codebetter.com/gregyoung/2010/08/12/eventual-consistency-and-set-validation/

    【讨论】:

    • 感谢@james 这么好的理解。我们总是留意您的宝贵建议。 :) 既然概念清楚地说明了事情的原因和方式,我们仍然需要精简一些事情。 1.)当然,我们需要在写入端创建要存储在图形数据库中的 uid。 2.)我们看到每次应用程序重新启动时,读取端处理器总是重放事件快照。我们需要一些如何根据某些条件停止它,因为它总是会在重新启动时触发图形数据库中的数据插入。对此的任何指示总是值得赞赏的。提前致谢。
    • 如果您的读取端在每次重新启动时将(相同的)数据插入到您的数据库中,我听起来好像您没有以持久的方式存储偏移量。应该发生的是,读取端会在重新启动之前从事件流中恢复。但这听起来像是 Stack Overflow 上的一个单独问题。
    猜你喜欢
    • 2014-08-31
    • 2016-04-14
    • 2010-09-18
    • 2020-12-08
    • 1970-01-01
    • 2016-05-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    相关资源
    最近更新 更多