是否有一种方法可以对两个存储过程使用一个目标队列,以防止出现死锁的可能性?
我为两个存储过程设置了内部激活。一个,插入一个或多个记录,另一个,更新同一表中的一个或多个记录。因此,我有两个启动器,两个目标队列。到目前为止,它在开发上都可以正常工作,但是我想知道当我们将其移至经常调用这两个存储过程的产品时,可能会遇到什么类型的问题。我们已经遇到了由这两个存储过程引起的死锁问题。异步执行是此实现的主要目标。
问题:
是否可以对两个存储过程使用一个目标队列,以防止出现死锁的可能性?]] >>
我有什么办法使它更可靠?像一个执行错误不应停止传入的请求到队列?
提高可扩展性的提示(每秒执行次数高?)>
如果出现死锁,我可以设置重试吗?
这里是插入存储过程的部分代码;
CREATE QUEUE [RecordAddUsersQueue]; CREATE SERVICE [RecordAddUsersService] ON QUEUE [RecordAddUsersQueue]; ALTER QUEUE [AddUsersQueue] WITH ACTIVATION ( STATUS = ON, MAX_QUEUE_READERS = 1, --or 10? PROCEDURE_NAME = usp_AddInstanceUsers, EXECUTE AS OWNER); CREATE PROCEDURE [dbo].[usp_AddInstanceUsers] @UsersXml xml AS BEGIN DECLARE @Handle uniqueidentifier; BEGIN DIALOG CONVERSATION @Handle FROM SERVICE [RecordAddUsersService] TO SERVICE 'AddUsersService' ON CONTRACT [AddUsersContract] WITH ENCRYPTION = OFF; SEND ON CONVERSATION @Handle MESSAGE TYPE [AddUsersXML] (@UsersXml); END GO CREATE PROCEDURE [dbo].[usp_SB_AddInstanceUsers] AS BEGIN DECLARE @Handle uniqueidentifier; DECLARE @MessageType sysname; DECLARE @UsersXML xml; WHILE (1 = 1) BEGIN BEGIN TRANSACTION; WAITFOR (RECEIVE TOP (1) @Handle = conversation_handle, @MessageType = message_type_name, @UsersXML = message_body FROM [AddUsersQueue]), TIMEOUT 5000; IF (@@ROWCOUNT = 0) BEGIN ROLLBACK TRANSACTION; BREAK; END IF (@MessageType = 'ReqAddUsersXML') BEGIN --<INSERT>.... DECLARE @ReplyMsg nvarchar(100); SELECT @ReplyMsg = N'<ReplyMsg>Message for AddUsers Initiator service.</ReplyMsg>'; SEND ON CONVERSATION @Handle MESSAGE TYPE [RepAddUsersXML] (@ReplyMsg); END ELSE IF @MessageType = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog' BEGIN END CONVERSATION @Handle; END ELSE IF @MessageType = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error' BEGIN END CONVERSATION @Handle; END COMMIT TRANSACTION; END END GO
谢谢,
库兹
我为两个存储过程设置了内部激活。一个,插入一个或多个记录,另一个,更新同一表中的一个或多个记录。因此,我有两个启动器,两个目标队列。它...
是否有一种方法可以对两个存储过程使用一个目标队列,以防止出现死锁的可能性?
您可以而且应该。没有理由拥有两个目标服务/队列/过程。将两个不同的消息类型
我有什么办法使它更可靠?像一个执行错误不应该停止传入请求到队列?
SSB激活非常可靠,这不会有问题。只要您严格遵守事务边界(不要在处理完成之前进行出队操作),就永远不会丢失消息/更新。
提高可伸缩性的提示(每秒高执行量)?
读取Writing Service Broker Procedures和Reusing Conversations。为了实现高吞吐量处理,您必须将队列(TOP(1000)
)出队并成批处理为@table
变量。有关可用于处理一批消息的模式,请参见Exception handling and nested transactions。您需要阅读并理解Conversation Group Locks。
如果出现死锁,我可以设置重试吗?
无需,SSB激活将为您重试。回滚时,出队(RECEIVE
)将回滚,从而使消息再次可用于激活,并且该过程将自动重试。请注意,连续5次回滚将触发poison message trap
MAX_QUEUE_READERS = 1,-或10?
如果1无法处理负载,请添加更多。只要您了解适当的对话组锁定,并行激活的过程就应该处理无关的业务项目,并且决不死锁。如果在同一队列中的已激活过程实例之间遇到死锁,则意味着您在会话组逻辑中存在缺陷,并且允许SSB视为不相关(不同的组)的消息修改相同的数据库记录(相同的业务实体),并且导致死锁。
BTW,您还必须在启动程序服务队列上具有一个已激活的过程。参见How to prevent conversation endpoint leaks。
是否有一种方法可以对两个存储过程使用一个目标队列,以防止出现死锁的可能性?