我是一个SQL Server Service Broker的新手,我试图抓住设置服务代理了一个(貌似)简单的使用情况下,最好的办法:我想创建一个简单的工作队列,其中一个应用程序的工作下降项目进入队列,单独的应用程序从该队列中获取工作项并处理它们。第一个应用程序不需要从第二个应用程序返回状态消息。我希望队列存在于单个Sql Server实例中。
最令我困惑的是对话/对话与这种情况的关系。我知道你只能在对话/对话的上下文中发送/接收消息,但由于这两个应用程序之间没有来回的喋喋不休,我对于何时是创建新会话的正确时间感到迷茫。两种极端的替代方案似乎是:
走这两条路线的后果是什么?
此外,在第一种情况下,似乎我需要进行一些END CONVERSATION,以便Sql Server能够在内部清理资源。什么时候将它们放入正确的地方是否有任何指导? (或者最终可能更好地依靠对话超时?)
答案 0 :(得分:26)
您应该从每个工作项开始进行自己的对话。生产者(发起者)开始一个对话框并发送描述工作项的消息,然后提交。使用者(目标)接收消息(或被激活),检查有效负载以了解工作项详细信息,执行工作,然后结束对话并提交。生成的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。
答案 1 :(得分:9)
我真的很喜欢Remus的回答,虽然它并没有特别涉及为什么您可能更喜欢为每个工作项启动单独的对话,而不是将所有工作项放在一个对话中。与此相关的两个注释:
首先,如果您有多个线程/进程处理工作项,将所有工作项放入单个对话可能会导致并发问题。服务代理工作进程往往看起来像这样(伪代码):
begin transaction
receive top n work items from queue
process work items
commit transaction
(通过不提交直到工作项成功处理为止,您确保,例如,如果您的流程终止,那么它已收到但尚未处理的工作项将不会从队列中删除。)
因为服务代理被编程为使得每个RECEIVE命令获取队列中与RECEIVEd共享相同会话(或会话组)的所有消息的独占读锁定,所以会出现并发问题。该锁定一直持续到事务提交为止。 (参见Conversation Group Locks。)因此,如果队列中的所有工作项都在一个对话中,那么当一个工作进程处于“进程工作项”步骤中时,没有其他工作进程可以执行任何工作。
将大量项目放入单个对话的第二个问题是,它会增加您可能丢失或在某些错误条件下重新处理的工作项数量。为了正确描述这一点,我推迟到Remus;看到他的Recycling Conversations,尤其是“重复使用单个对话框发送所有信息的部分[...]就像将所有鸡蛋放在一个篮子里一样。”您可能能够从某些错误情况中恢复,但它可能会为您的代码带来更多复杂性。
对于所有工作项使用单个对话可能还有一些争论,但我对它们并不熟悉。
这并不是说正确的解决方案始终是为每个工作项启动单独的对话。在阅读了Remus的帖子之后,他的建议似乎很合理;从每个对话开始一个工作项,然后根据需要添加复杂性。 (但在任何情况下,你都不应该将所有信息放在一个对话中。)