16

我是 Sql Server Service Broker 新手,我正在尝试掌握为(看似)简单的用例设置 Service Broker 的最佳方法:我想创建一个简单的工作队列,其中一个应用程序将工作项放入队列,并且单独的应用程序从该队列中提取工作项并处理它们。第一个应用程序不需要从第二个应用程序获取状态消息。我希望队列存在于单个 Sql Server 实例中。

最让我困惑的是对话/对话与这种情况的关系。我知道您只能在对话/对话的上下文中发送/接收消息,但是由于两个应用程序之间没有来回的聊天,我对何时是创建新对话的正确时间感到迷茫。两个极端的选择似乎是:

  • 每次我将工作项排入队列时,我都会开始新的对话。因此,每个对话最终都会包含一条消息。
  • 在部署时,我手动创建了一个无限期对话。当需要将工作项排入队列时,我总是将其作为单个对话的一部分发送。

走这两条路线的后果是什么?

此外,在第一种情况下,似乎我需要进行一些 END CONVERSATION,以便 Sql Server 能够在内部清理资源。有什么指导什么时候可以把它们放在正确的地方吗?(或者最终依赖对话超时可能会更好?)

4

2 回答 2

27

您应该从每个工作项开始进行自己的对话。生产者(发起者)开始对话并发送描述工作项的消息,然后提交。消费者(目标)接收消息(或被激活),检查有效负载以了解工作项详细信息,执行工作,然后结束对话并提交。生成的 EndDialog 消息被发送回发起者服务队列,发起者队列上的激活过程通过结束发起者端的对话来响应它。

这是最简单的部署,启动并运行它将确保您有一个良好的基础来构建。当生产者将工作项排入队列时,不要偷工减料并在发起方结束对话,这是一劳永逸的,并且有几个缺点

如果您有高性能要求(每秒超过 200 个请求),那么您必须开始更明确地管理对话。我有一篇关于出于性能原因重用对话的博客条目。在接收端,我建议阅读编写服务代理程序

我还有一个博客条目,它几乎可以满足您的需求,尽管它不安排工作项目,而是启动一个自定义过程:异步过程执行

如果您决定从激活的上下文中使用工作项,从而利用激活的良好自我平衡功能,那么您需要了解激活发生的 EXECUTE AS 上下文

于 2009-08-12T03:00:20.000 回答
9

我真的很喜欢 Remus 的回答,尽管它并没有特别提到为什么您可能更愿意为每个工作项开始单独的对话,而不是将所有工作项放在一个对话中。与此相关的两个注释:

首先,如果您有多个线程/进程处理工作项,那么将所有工作项放在一个对话中可能会导致并发问题。Service Broker 工作进程看起来像这样(在伪代码中):

begin transaction
receive top n work items from queue
process work items
commit transaction

(通过在成功处理工作项之前不提交,您可以确保,例如,如果您的进程死亡,那么它已收到但尚未处理的工作项不会从队列中删除。)

并发问题会出现,因为服务代理被编程为每个 RECEIVE 命令获取队列中所有消息的独占读取锁,这些消息与被接收的消息共享相同的会话(或会话组)。该锁一直保持到事务提交为止。(请参阅对话组锁定。)因此,如果队列中的所有工作项都在一个对话中,那么当一个工作进程处于“处理工作项”步骤时,没有其他工作进程可以做任何工作。

将大量项目放入单个对话中的第二个问题是,它会增加您可能丢失或在某些错误条件下必须重新处理的工作项目的数量。为了恰当地描述这一点,我听从 Remus 的意见。请参阅他的Recycling Conversations,尤其是“重用单个对话框发送所有消息 [...] 就像将所有鸡蛋放在一个篮子中一样”的部分。您可能能够从其中一些错误情况中恢复,但它可能会给您的代码带来更多的复杂性。

反对对所有工作项目使用单一对话可能还有一些争论,但我对它们并不熟悉。

这并不是说正确的解决方案总是为每个工作项开始单独的对话。不过,在阅读了 Remus 的帖子后,他的建议似乎很合理。从每个对话一个工作项开始,然后在需要时增加复杂性。(但在任何情况下,您都不应该走极端,将所有消息放在一个对话中。)

于 2009-08-15T22:40:47.683 回答