代码之家  ›  专栏  ›  技术社区  ›  Chris

SQL Server Service Broker:如何为简单的队列方案构造会话?

  •  16
  • Chris  · 技术社区  · 15 年前

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

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

    • 每次我将一个工作项排队时,我都会开始一个新的对话。所以每一次谈话最后都只有一条信息。
    • 在部署时,我手动创建一个单一的无限寿命会话。当需要将工作项排队时,我总是将其作为单独对话的一部分发送。

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

    另外,在第一种情况下,我似乎需要进行一些结束会话,以便SQL Server能够在内部清理资源。有没有什么指导说明什么时候放这些东西的地方是正确的?(或者最终依赖于谈话的时间安排可能更好?)

    2 回复  |  直到 15 年前
        1
  •  26
  •   Remus Rusanu    15 年前

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

    这是最简单的部署,让它运行并确保你有一个良好的基础。当生产者将工作项排队时,不要拐弯并结束启动器端的对话,这是 fire-and-forget and has several draw backs .

    如果您有高性能需求(每秒超过200个请求),那么您必须开始更明确地管理会话。我在上有一篇日志 reusing conversations for performance reasons . 在接收端,我建议阅读 Writing Service Broker Procedures .

    我还有一个博客条目,它几乎可以满足您的需要,尽管它不安排工作项,而是启动一个自定义过程: Asynchronous procedure execution .

    如果您决定从激活的上下文中使用工作项,从而利用激活的良好的自我平衡能力,那么您需要 understand the EXECUTE AS context under which activation occurs .

        2
  •  9
  •   Chris    15 年前

    我真的很喜欢雷姆斯的回答,尽管它没有特别的意义 为什么? 您可能更喜欢针对每个工作项启动单独的对话,而不是将所有工作项放在单个对话中。与此相关的两个注释:

    首先,如果您有多个线程/进程处理工作项,将所有工作项放入一个会话中可能会导致并发问题。ServiceBroker工作进程通常如下所示(在伪代码中):

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

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

    并发性问题会出现,因为ServiceBroker被编程为每个接收命令都获得队列中与接收到的消息共享相同会话(或会话组)的所有消息的独占读取锁。该锁一直保持到提交事务为止。(见 Conversation Group Locks 因此,如果队列中的所有工作项都在单个会话中,那么当一个工作进程处于“处理工作项”步骤时,其他任何工作进程都不能执行任何工作。

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

    可能还有更多的理由反对对所有工作项使用单独的对话,但我对它们不太熟悉。

    这并不是说正确的解决方案总是为每个工作项单独开始一次对话。不过,在阅读了雷姆斯的文章之后,他的建议似乎是合理的;从每个对话的一个工作项目开始,然后根据需要增加复杂性。(但在任何情况下,你都不应该极端地把所有的信息放在一次谈话中。)