5

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

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

由于 EventStore 的文档确实很少,有 EventStore 经验的人可以提供以下帮助吗?

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

(我读到存储引擎中的事务不是必需的,但我仍然使用事务的语言来表示在 EventStore 级别替换事务的任何内容。如果在从事务切换到任何内容时有关键的功能后果,请评论它们.我不需要马上了解每一个方面,只需要希望能有更多的时间去尝试。)

4

2 回答 2

4

虽然 EventStore 可能被用来构建一个完整的队列,但它的设计从未考虑到这一点。这意味着在构建库时有很多固执己见的决定与您的问题所提出的要求背道而驰。

例如,消息传递系统并不真正支持精确一次传递的概念。上面提到的其他事情,比如有毒消息,并不是真正的问题,因为 EventStore 没有以这种方式连接到消息管道中。

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

另外,您的邮件中有哪些内容使它们大于 4MB?如果您正在推送文件或大型二进制流,为什么不将它们推送到某种高度可用的“全局”存储(如 Amazon S3),然后在消息中获得指向这些内容的指针?

于 2011-11-22T04:06:02.160 回答
4

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

  • 如果您跟踪消息的因果关系,就会发生偏序。有一些方法可以做到这一点。最简单的做法是简单地保留分布式网络中给定消息已经看到的所有节点的列表,并在您推送消息时附加到该列表中。我说的是信息,但我真正指的是那次对话中的信息。

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

    不过,您可能需要在单个接收者节点上进行部分排序 - 然后 sagas,在消息流方面处于中心辐射模式对您没有帮助。那么也许您实际上需要为您正在使用的传输添加一些逻辑。

    一种算法称为向量时钟,另一种类似的称为版本向量这是Go中矢量时钟的示例实现——如果你想花几个小时配对,我正在为 F# 开发一个小型矢量时钟库——因为算法实际上非常简单。如果你想真正阅读一些有意义的东西,我推荐这本书 -分布式系统的元素。第2-3、5章很好。

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

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

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

于 2012-01-20T09:19:20.100 回答