Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Service Broker内部激活问题_Sql_Sql Server_Internal_Service Broker_Activation - Fatal编程技术网

SQL Service Broker内部激活问题

SQL Service Broker内部激活问题,sql,sql-server,internal,service-broker,activation,Sql,Sql Server,Internal,Service Broker,Activation,我为两个存储过程设置了内部激活。一个用于插入一条或多条记录,另一个用于更新同一表中的一条或多条记录。所以,我有两个启动器,两个目标队列。 到目前为止,它在开发中运行良好,但我想知道当我们将它转移到prod时,可能会遇到哪些类型的问题,在prod中经常调用这两个存储过程。我们已经遇到了由这两个存储过程引起的死锁问题。异步执行是我使用此实现的主要目标 问题: 是否有一种方法可以对两个存储过程使用一个目标队列来防止死锁 我能做些什么使它更可靠吗?像一个执行错误一样,不应该停止传入的请求 排队 提高可伸

我为两个存储过程设置了内部激活。一个用于插入一条或多条记录,另一个用于更新同一表中的一条或多条记录。所以,我有两个启动器,两个目标队列。 到目前为止,它在开发中运行良好,但我想知道当我们将它转移到prod时,可能会遇到哪些类型的问题,在prod中经常调用这两个存储过程。我们已经遇到了由这两个存储过程引起的死锁问题。异步执行是我使用此实现的主要目标

问题:

  • 是否有一种方法可以对两个存储过程使用一个目标队列来防止死锁

  • 我能做些什么使它更可靠吗?像一个执行错误一样,不应该停止传入的请求 排队

  • 提高可伸缩性的技巧(每秒执行的次数高)

  • 如果出现死锁,我可以设置重试吗

  • 这是insert存储过程的部分代码

    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
    
    创建队列[RecordAddUsersQueue];
    在队列[RecordAddUsersQueue]上创建服务[RecordAddUsersService];
    通过激活更改队列[AddUsersQueue]
    (状态=开,
    最大队列读取器=1,--或10?
    过程\u NAME=usp\u AddInstanceUsers,
    作为业主执行);
    创建过程[dbo].[usp\U AddInstanceUsers]@UsersXml
    作为
    开始
    声明@Handle唯一标识符;
    开始对话@Handle
    来自服务[RecordAddUsersService]
    为“AddUsersService”提供服务
    根据合同[AddUsersContract]
    加密=关闭时;
    发送会话@Handle
    消息类型[AddUsersXML](@UsersXml);
    结束
    去
    创建过程[dbo]。[usp\U SB\U AddInstanceUsers]
    作为
    开始
    声明@Handle唯一标识符;
    声明@MessageType sysname;
    声明@UsersXML;
    而(1=1)
    开始
    开始交易;
    等待
    (接收顶部(1)
    @Handle=conversation\u Handle,
    @MessageType=消息类型名称,
    @UsersXML=消息体
    从[AddUsersQueue]),超时5000;
    如果(@@ROWCOUNT=0)
    开始
    回滚事务;
    打破
    结束
    IF(@MessageType='ReqAddUsersXML')
    开始
    --....
    声明@ReplyMsg nvarchar(100);
    挑选
    @ReplyMsg=N'AddUsers启动器服务的消息';
    发送会话@Handle
    消息类型[RepAddUsersXML](@ReplyMsg);
    结束
    其他的
    如果@MessageType=N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
    开始
    结束对话@Handle;
    结束
    其他的
    如果@MessageType=N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
    开始
    结束对话@Handle;
    结束
    提交事务;
    结束
    结束
    去
    
    谢谢,

    库齐

    是否有一种方法可以对两个存储过程使用一个目标队列来防止死锁

    你可以,你应该。没有理由有两个目标服务/队列/过程。向同一服务发送两种不同的消息类型,用于所需的两种操作。然后,激活的过程应根据消息类型执行添加逻辑或更新逻辑

    我能做些什么使它更可靠吗?像一个执行错误不应该停止对队列的传入请求

    SSB激活将非常可靠,这不会是一个问题。只要严格遵守事务边界(在处理完成之前不要提交出列操作),就永远不会丢失消息/更新

    提高可伸缩性的技巧(每秒执行的次数高)

    读和读。要实现高吞吐量处理,您必须将队列中的数据排出来并分批处理(
    TOP(1000)
    )到
    @table
    变量中。有关可应用于处理一批消息的模式,请参阅。你需要阅读和理解

    如果出现死锁,我可以设置重试吗

    不需要,SSB激活将为您重试。回滚时,退出队列(
    RECEIVE
    )将回滚,从而使消息再次可供激活,并且该过程将自动重试。请注意,一行5次回滚将触发

    最大队列读取器=1,--或10

    如果1无法处理负载,请添加更多。只要您理解正确的会话组锁定,并行激活的过程就应该处理无关的业务项,并且永远不会死锁。如果在同一队列上的激活过程实例之间遇到死锁,则意味着会话组逻辑中存在缺陷,并且允许SSB认为不相关(不同组)的消息修改相同的数据库记录(相同的业务实体)并导致死锁

    顺便说一句,您还必须在启动器服务队列上有一个已激活的过程。看

    是否有一种方法可以对两个存储过程使用一个目标队列来防止死锁

    你可以,你应该。没有理由有两个目标服务/队列/过程。向同一服务发送两种不同的消息类型,用于所需的两种操作。然后,激活的过程应根据消息类型执行添加逻辑或更新逻辑

    我能做些什么使它更可靠吗?像一个执行错误不应该停止对队列的传入请求

    SSB激活将非常可靠,这不会是一个问题。只要严格遵守事务边界(在处理完成之前不要提交出列操作),就永远不会丢失消息/更新

    提高可伸缩性的技巧(每秒执行的次数高)

    读和读。要实现高吞吐量处理,您必须将队列中的数据排出来并分批处理(
    TOP(1000)
    )到
    @table
    变量中。请参阅以了解模式