【问题标题】:Reusing NServiceBus messages saga data重用 NServiceBus 消息 saga 数据
【发布时间】:2011-06-07 06:00:13
【问题描述】:

是否有任何理由不在 saga 数据中重用 NServiceBus 消息 (IMessage)?我的意思是有这样的消息:

public class Order : IMessage
{
   public virtual List<TillOrderLine> OrderLines { get; set; }
}

public class TillOrderLine : IMessage { ... }

然后在 saga 和 saga 数据中也使用它,如下所示:

public class OrderProcessingSaga : 
    Saga<OrderProcessingSagaData>, 
    IAmStartedByMessages<Order> { ... }

public class OrderProcessingSagaData : ISagaEntity
{
   public virtual Guid Id { get; set; }
   public virtual string Originator { get; set; }
   public virtual string OriginalMessageId { get; set; }

   // The message data is stored by the saga here.
   public virtual Order Order { get; set; }
}

我意识到消息是由传输层 (MSMQ) 存储的,而 saga 数据与 saga 一起保存到 DB。它适用于我当前的用例,并且似乎更优雅地重用该类,而不是为消息创建一个,为 saga 存储创建另一个。

我想知道这种方法是否有任何问题?

【问题讨论】:

    标签: nservicebus


    【解决方案1】:

    我同意 mookid8000 所说的一切,但我还有一点要补充。

    您的 saga 存储通常会有很多争用。为了保证一致性,saga 存储提供者通常会对数据设置更新锁,以保证来自同一个 saga 的另一条消息不能同时改变状态。

    如果您使用的是默认的 NHibernate saga 持久化器(并且您的虚拟属性向我表明您是这样的),那么 NHibernate 会使用一些假设来保存您的数据:

    • 您的 saga 数据中的复杂类型将导致数据库列遵循 ComplexTypePropName_ChildPropertyName 语法(或类似的 - 在此处从内存操作)。因此,您的 saga 数据仍将包含在一个表的 1 行中。
    • 如果你的 saga 数据中有一个列表,它显然必须创建一个新表来存储列表项。现在您的 saga 数据包含在一个主行和多个详细行中。
      • 为了让 NHibernate 映射它,您的集合类型还必须有一个名为 Id 的 Guid 属性,这意味着您不能存储原语列表,并且您的 TillOrderLine 类(公共消息的一部分)需要此 Id 属性这对您服务的商业目的毫无意义。
    • 如果您的 saga 数据中有一个复杂类型(订单,基本上是重用的消息),它本身包含一个(TillOrderLines 的)列表,我不知道您的情况会发生什么。

    在任何情况下,saga 持久化器需要将数据拆分到的表中的行越多,就越难使用细粒度的行锁来锁定所涉及的行。如果争用足够多,行锁将开始升级为页锁和表锁,然后你就真的遇到了问题。

    这就是文档数据库真正适合 saga 存储的原因,这也是他们在 NServiceBus 3.0 中将 RavenDB 设为默认 saga 持久化器的原因。

    在那之前,看看我写的XML Serialization based Saga Persister,它可以为您今天的应用程序带来即将到来的 RavenDB 风格的 saga 持久化器的一些好处。

    如果您必须坚持使用 NHibernate,我强烈建议您不要将消息与您的 saga 持久性解决方案紧密结合。我几乎可以保证它会回来困扰你。

    【讨论】:

    • 感谢您的回答大卫,感谢您的意见。我也很期待 3.0 中基于 RavenDB 的 saga 持久化器。这要自然得多。我的用例是我自己网站的订购场景。可悲的是,我预计不会因为高争用率而导致性能大幅下降 :( 说真的,它实际上是一个带有网络和合作伙伴订单和履行的单机站点。我更多地使用 NSB 来简化设计和开发- 哦,还有测试。
    【解决方案2】:

    如果你的 surrent saga 持久化者坚持数据而不抱怨,我想不出这种方法有什么问题 - 只要你意识到你为了两个目的重用一个类,从而引入了 saga 数据之间的耦合(对服务来说是私有的)和消息(本质上是公开的)关于存在的字段、命名等。

    然后,当您需要偏离消息的结构方式时,您可以为所有 saga 数据构建类。

    PS:TillOrderLine 不需要标记为 IMessage,如果它的唯一目的是在 Order 内部进行聚合。

    【讨论】:

    • 谢谢mookid,这很有道理。我也没有注意到 TillOrderLine 中的 IMessage - 很好 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多