EventStore事件和其他功能的部分排序

时间:2011-11-21 14:11:43

标签: cqrs

我正在尝试将EventStore评估为服务器软件内部的可靠排队机制。

MSMQ作为替代方案失败,因为它无法在消息的“对话”中支持部分排序​​,有序消息。并且因为它的4MB消息大小限制(可以通过部分排序来克服)。 SQL Service Broker确实支持部分排序​​,但是以编程方式设置和管理是一件很痛苦的事。

由于EventStore上的文档确实很少,具有EventStore经验的人可以帮助解决以下问题吗?

  • EventStore是否支持事件的事务处理 - 即 如果处理失败,可以将该队列退回吗?
  • 在各种线程,进程或机器中有多个读取器, EventStore是否强制将每个事件(仅)分派给一个事件 读者(一次,也许是在交易期间)
  • 假设以上是可能的,可以在不同的“对话”上进行事件 以任何顺序同时读取,而同一对话中的消息是 单独阅读并按顺序阅读?
  • 我读到EventStore基本上是“至少一次”交付。是吗 可能,使用某些存储提供商,以确保“完全一次” 递送
  • 如何处理“毒药”事件?处理期间出错的事件。也许是 错误本质上是暂时的,可以重试。也许它本质上是永久性的 需要行政干预。
  • 如有必要,可以手工操作EventStore存储吗?它可以 在其他读者继续阅读时完成?

(我读到存储引擎上的事务不是必需的,但我仍然使用事务语言来表示在EventStore级别替换事务的任何事情。如果从事务切换到任何事情都有重要的功能后果,请对他们发表评论。我不需要立即了解每个方面,只需要希望,以便花更多的时间进行实验。)

2 个答案:

答案 0 :(得分:4)

虽然可能会使用EventStore来构建一个完整的队列,但它的设计并没有考虑到这一点。这意味着构建库时有很多自以为是的决定违背了您的问题所强加的要求。

例如,完全一次传递的概念是消息传递系统并不真正支持的。上面提到的其他内容,比如有害消息,实际上并不是问题,因为EventStore没有以这种方式挂钩到消息管道中。

您尝试解决的问题似乎并不是EventStore可以帮助您的问题。因此,我建议评估一个完整的消息队列,例如RabbitMQ。

另外,你对你的邮件有什么影响,使它们大于4MB?如果您正在推动文件或大型二进制流,为什么不将它们推送到某种高度可用的“全局”存储(如Amazon S3),然后指向消息上的那些?

答案 1 :(得分:4)

一些想法,即使你似乎满意第一个答案:

  • 如果您跟踪邮件的因果关系,会发生部分订购。有办法做到这一点。这种天真的做法是简单地保存一个分布式网络中所有节点的列表,当你推送消息时,给定消息已经看到并附加到该列表。我说消息,但我真的是指那次谈话中的消息。

    现在,这可能适用于简单的系统,但是当您开始获得更复杂的系统时,您可能希望Saga能够跟踪哪些消息的确切含义。

    尽管如此,您可能需要在单个收件人节点上进行部分排序 - 然后是传真,对于消息流采用中心辐射模式对您没有帮助。那么也许你真的需要为你正在使用的传输添加一些逻辑。

    一种算法称为vector clocks,另一种算法称为version vectors。这是Go中矢量时钟的示例实现 - 如果你想花几个小时配对,我正在研究F#的一个小矢量时钟库 - 因为算法实际上非常简单。如果你想真正阅读对此有意义的内容,我推荐这本书 - Elements of Distributed Systems。第2-3章,第5章都很好。

    然后,您将在分布式系统中对会话进行部分排序。你无法通过队列得到这个的原因是你的队列和你的节点之间有一个网络鸿沟,如果节点或与队列在同一节点上的进程因为有消息而关闭在传输过程中,此消息将被重新排序并重新排序。如果你NACK消息也一样。你可以通过在队列和消费客户端上使用2PC来解决这个重新排序问题,或者你可以通过它们的向量时钟对消息进行排序,或者你可以根据发布/发送应用程序中给出的序列ID对它们进行排序,或者你可以从一些数据中对它们进行排序,因为它从消费者的角度来看具有语义意义。选择权归你所有。

  • 至于其他要求,这样的有害信息,你应该看一下服务总线给你的东西。我个人使用MassTransit,它可以很好地处理毒药信息。这些是消费消息的一些失败模式:

    • 序列化错误 - 您编写了一个编程错误。修复您的开发过程,因为这些不应该发生。如果它们仍然发生,只需将它们移动到毒性队列 - 这些消息可能已损坏。
    • 代码中未处理的异常 - 您犯了编程错误。同样,您的开发过程需要进行检查。除非你抛出它让你的服务总线运行时将消息移动到毒性队列。
    • 您可能在写入本地消费者数据库时遇到问题 - 这是一个操作问题,不应该在代码中发生。杀死你的过程,因为你现在无法从代码中做任何事情。 Naigos或其他一些进程监视器应该告诉你的操作人员有些东西已经关闭并且需要紧急修复 - 因为如果你不能写入你的阅读模型,那么你的阅读模型可能无法满足它的需求。 Puppet或其他一些进程监视器可能会在稍后重启您的进程,然后您可以执行相同的步骤,假设一切正常,但这一次,在您连接到数据库之前不要开始消耗队列(这是NHibernate在启动时对其静态初始化所做的事情) - 并在该重试逻辑之上实现重试策略,例如断路器。
  • 大事件 - 确保您的队列API块的字节数组太长。 ZeroMQ有多部分消息。 AMQP / RabbitMQ没有,所以你不得不自己砸它们,当然,迫使你再次重新订购它们。或者你可以在某个地方找到一个二进制blob的句柄,在那里你可以像我们其他人一样从中读取它。