서비스 브로커가 백업되어 현재 수신 중이지만 처리하지 않는 것 같습니다.


20

이벤트 알림에 문제가 있습니다. 메시지가 수신되는 시스템 / 드라이브 / 데이터베이스 (수신자)에서 아무도보고 있지 않을 때 드라이브가 가득 차서 하루 종일 백업되었습니다.

이제 드라이브의 공간을 확보 했으므로 대기열에 메시지를 수락하지만 처리하지 않는 것 같습니다. 대기열에 현재 2 천 2 백만 개의 메시지가 있고 커지는 경우에도 새로운 레코드가 삽입되지 않습니다. 대기열이 활성화되었습니다.

is_activation_enabled = 1
is_receive_enabled = 1
is_enqueue_enabled = 1

에 활성화 된 SP가 표시 activation_procedure되지만에서 살펴보면 SP_WHOISACTIVE활성화 된 독자가 표시되지 않습니다.

드라이브를 다시 터뜨리기 전에 내가 뭘 잘못하고 있니? 메시지를 처리하거나 플러시하려면 어떻게해야합니까? 미리 감사드립니다.

최신 정보

한 가지 생각-내가 가지고 있기 때문에 is_enqueue_enabled모든 메시지를 처리 ​​할 수있을 때까지 모든 메시지를 저장하고 있습니까? 그렇다면 안전하게 끌 수 있습니까?

CREATE PROCEDURE [dbo].[Parse_EN_Messages]
AS
--mdb 2012/09/05 version 1.2  
-- With apologies and thanks to Remus Rusanu, Jonathon Kehayias, Mladen Prajdic, and Jasper Smith for writing
-- about EN, answering questions, and getting the word out about this awesome feature of SQL Server 2005+.
-- Also thanks to Mikael Eriksson for a faster parse with the XML filter.
-- Their code modified, combined, and used below.  Any errors herein are mine, not theirs.  
-- Part of the code came from MVP Deep Dives Vol 1 Chapter 28 (Mladen), PASS Presentations by Jasper and Jonathon,
-- and Stackexchange (below) from Remus and Mikael Eriksson
-- http://dba.stackexchange.com/questions/10273/how-to-create-an-event-notification-that-runs-a-job-procedure-when-mirroring-sta
-- http://stackoverflow.com/questions/12308099/t-sql-dynamically-filter-xml-on-multiple-conditions/12358926
--History:  1.00 2012/08/27 first release
--          1.01 2012/09/05 added server-based exclusions and eventsubclass = 0
--          1.1  2012/09/17 added exclusion_sets which allow multi-condition filtering and improved performance
--          1.11 2012/10/05 removing the 1=1 as per suggestion by Rusanu; 
--                              this could cause it to spin forever, blowing out the error_log..and the drive.
--          1.12 2012/11/14 adding a RETURN in the @@ROWCOUNT. It fails to exit and then hits a COMMIT, causing records
--                              in enaudit_error.  That was due to the 1.11 change where I no longer use a 1=1.
--          1.13 2014/01/16 changing ERRORLOG to write the first 500 chars to the CommandText field, as tested in Canada.

SET NOCOUNT ON 
DECLARE @message_type NVARCHAR(256),
@message VARBINARY(MAX),
@conversation_handle UNIQUEIDENTIFIER,
@auditdata XML,
@queuing_order BIGINT,
@conversation_group_id UNIQUEIDENTIFIER

BEGIN
    BEGIN TRANSACTION;
    BEGIN TRY;
    WAITFOR (
        RECEIVE TOP(1)
        @conversation_handle = [conversation_handle], --aka dialog
        @conversation_group_id = [conversation_group_id],
        @message_type = message_type_name,
        @message = message_body, 
        @queuing_order = queuing_order
        FROM dbo.ENAudit_SBQueue --ORDER BY queuing_order --order by doesn't work there.
        ), TIMEOUT 5000 --we need the timeout so that it won't hold transactions open indefinitely.

    IF (@@ROWCOUNT = 0)
    BEGIN
        ROLLBACK TRANSACTION
  --mdb 1.12 2012/11/14 adding a return as otherwise it tries to commit later and fails, causing records in enaudit_error      
        RETURN 
    END

    SELECT @auditdata = CAST(@message AS XML)

    IF @message_type = N'http://schemas.microsoft.com/SQL/Notifications/EventNotification'
    -- Dynamically shred the XML and compare to our exclusion table.  You should be able to filter on any field.
    -- Exclusion set: unique char(2) name. Has to match every condition.  Servername is one of the fields handled.
    -- Be careful as the filters could impact performance.
    and NOT EXISTS --if all active members of the same exclusion_set match, the event is excluded.
    (
    SELECT * FROM 
    (
    select COUNT(*) AS match_count, exclusion_set
                  from enaudit_exclusion_list 
                  where exists (
                               select *
                               from (
                                    select X.N.value('local-name(.)', 'varchar(128)') as NodeName,
                                           X.N.value('./text()[1]', 'varchar(max)') as NodeValue
                                    from @auditdata.nodes('//*') as X(N)
                                    ) T
                               where T.NodeName = enaudit_exclusion_list.exclusion_type and
                                     T.NodeValue like enaudit_exclusion_list.excluded_value 
                                     AND  enaudit_exclusion_list.active = 1
                               )
    GROUP BY exclusion_set
    ) matches_per_set
    INNER JOIN 
    (SELECT COUNT(*) AS total_count, exclusion_set FROM enaudit_exclusion_list WHERE active = 1 GROUP BY exclusion_set) grouped_set
    ON match_count = total_count
    AND grouped_set.exclusion_set = matches_per_set.exclusion_set
    )
    BEGIN
    INSERT INTO ENAudit_Events
            ( ServerName ,
                queuing_order ,
                PostTime ,
                StartTime,
                EventType ,
                SPID ,
                LoginName ,
                UserName ,
                DatabaseName ,
                SchemaName ,
                ObjectName ,
                ObjectType ,
                TargetObjectName ,
                TargetObjectType ,
                CommandText ,
                insert_datetime,
                message_body_xml
            )
--over 128 elements exist, I've chosen the most useful for what I'm doing.
--To get a full list, GROUP BY in the XSD from http://schemas.microsoft.com/sqlserver/2006/11/eventdata/events.xsd
-- More information in EVENTDATA http://msdn.microsoft.com/en-us/library/ms187909.aspx
    SELECT 
        @auditdata.value('(/EVENT_INSTANCE/ServerName)[1]', 'varchar(128)' ) AS ServerName,
        @queuing_order AS Queuing_Order, 
        @auditdata.value('(/EVENT_INSTANCE/PostTime)[1]', 'datetime') AS PostTime,
        @auditdata.value('(/EVENT_INSTANCE/StartTime)[1]', 'datetime') AS StartTime,
        @auditdata.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)' ) as EventType,
        @auditdata.value('(/EVENT_INSTANCE/SPID)[1]', 'bigint') AS SPID,
        @auditdata.value('(/EVENT_INSTANCE/LoginName)[1]', 'varchar(128)' ) AS LoginName,
        @auditdata.value('(/EVENT_INSTANCE/UserName)[1]', 'varchar(128)' ) AS UserName,
        @auditdata.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(128)' ) AS DatabaseName,
        @auditdata.value('(/EVENT_INSTANCE/SchemaName)[1]', 'varchar(128)' ) AS SchemaName,
        @auditdata.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(128)' ) AS ObjectName,
        @auditdata.value('(/EVENT_INSTANCE/ObjectType)[1]', 'varchar(128)' ) AS ObjectType,
        @auditdata.value('(/EVENT_INSTANCE/TargetObjectName)[1]', 'varchar(128)' ) AS TargetObjectName,
        @auditdata.value('(/EVENT_INSTANCE/TargetObjectType)[1]', 'varchar(128)' ) AS TargetObjectType,
        --@auditdata.value('(/EVENT_INSTANCE/PropertyName)[1]', 'varchar(128)' ) AS PropertyName,
        --@auditdata.value('(/EVENT_INSTANCE/PropertyValue)[1]', 'varchar(128)' ) AS PropertyValue,
        --@auditdata.value('(/EVENT_INSTANCE/Parameters)[1]', 'varchar(128)' ) AS Parameters,
        CASE @auditdata.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)' )
        WHEN 'ERRORLOG' THEN @auditdata.value('/EVENT_INSTANCE[1]/TextData[1]', 'varchar(500)')
        ELSE @auditdata.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'varchar(max)' ) END AS CommandText,
        GETDATE(),
        @auditdata 
    --Other possibilities for doing a dynamic XML query?
    --      http://www.dotnetgenerics.com/Modules/TricksAndTips/SQLServer/DynamicWhereClause.aspx
    --      http://www.beefycode.com/post/Expressing-Filter-Queries-as-XML-in-SQL-Server.aspx
    --      http://stackoverflow.com/questions/923136/t-sql-filtering-on-dynamic-name-value-pairs
    --      http://stackoverflow.com/questions/1729973/filter-sql-queries-on-the-xml-column-using-xpath-xquery
    END         
    else 
    IF @message_type = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error' --log error messages
    BEGIN 
        WITH XMLNAMESPACES ('http://schemas.microsoft.com/SQL/ServiceBroker/Error' AS ssb)
        INSERT INTO ENAudit_Errors ([conversation_group_id], [conversation_handle], 
        [queuing_order], error_code, error_description, insert_datetime, message_body_raw)
        SELECT @conversation_group_id, @conversation_handle, @queuing_order,
                @auditdata.value('(//ssb:Error/ssb:Code)[1]', 'INT') AS error_code,
                @auditdata.value('(//ssb:Error/ssb:Description)[1]', 'NVARCHAR(4000)') AS error_description,
                GETDATE(), 
                @message

         end conversation @conversation_handle --close the conversation if there was an error
    END
    ELSE 
    IF @message_type =  N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
        begin
            end conversation @conversation_handle;
        end
    COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
    declare @xact_state int = xact_state(), 
            @error_number int = error_number(), 
            @error_message nvarchar(4000) = error_message(),
            @has_rolled_back bit = 0;
        if @xact_state = -1
        begin
            -- Doomed transaction, it must rollback
            rollback;
            set @has_rolled_back = 1;
        end
        else if @xact_state = 0
        begin
            -- transaction was already rolled back (deadlock?)
            set @has_rolled_back = 1;
        end
        insert INTO ENAudit_Errors(
            insert_datetime,
            error_code,
            error_description,
            message_body_raw)
        values (
            getdate(),
            @error_number,
            @error_message,
            @message);
        if (@has_rolled_back = 0)
        begin
            commit;
        end
    end catch
 END




GO

1
따라서 문제 설명에서 내부 활성화를 사용하고 있습니다. sys.dm_broker_activated_tasks에 나열된 것이 있습니까? 활성화 절차는 어떻게됩니까? 여기에 게시 할 수 있습니까? 프로 시저가 모든 메시지를 한 번에 (즉, 한 트랜잭션에서) 처리하려고 할 수 있으며 이는 나쁠 수 있습니다. 또한 수동으로 정품 인증을 실행하는 것을 방해하는 것은 없습니다.
벤 툴

2
포이즌 메시지 (너무 많은 실패)로 인해 큐가 비활성화되었을 수 있습니다. sys.transmission_queue를 쿼리하여보고되는 오류를 알려주십시오. 내 의심이 맞으면 ALTER QUEUE 문을 사용하여 큐를 다시 시작해야합니다.
Robert L Davis

3
@BenThul이 활성화 된 저장 프로 시저 코드를 질문에 추가했습니다. FWIW, 나는 1 = 1을 사용하지 않습니다. 나는 몇 년 전에 Remus Rusanu와 그것에 대해 이야기했으며, 그것을 사용해야 할 이유가없는 방법에 대해 이야기했으며 그에 따라 광산을 수정했습니다. 즉, 속도를 위해 100/1000의 배치를 수행하도록 변경해야 할 것입니다. 그러나 그것이 백업 될 때까지, 그것은 챔피언처럼 일하고 있었기 때문에 나는 그것을 만지기를 싫어했습니다.
mbourgon

2
나는 현재 상황에 루프가 불필요하다는 데 동의하지 않습니다. 이 BOL 기사 ( technet.microsoft.com/en-us/library/… )에 따르면 정품 인증이 자주 트리거되지 않을 수 있습니다. 이것이 트리거 될 때 처리 할 남은 부분이 없을 때까지 각 프로 시저가 메시지를 계속 처리하기를 원하는 이유입니다. 내 두 센트. 당신이 지금 존재하는 구멍에서 자신을 파헤 치기 위해, 당신은 while exists (select 1 from dbo.ENAudit_SBQueue) begin exec [dbo].[Parse_EN_Messages]; endSSMS 와 같은 것을 가짜로 할 수 있습니다.
벤 툴

6
한 번 봐 가지고 rusanu.com/2008/08/03/understanding-queue-monitors를 하고 적용하는지
레무스 Rusanu을

답변:


2

tcp 엔드 포인트의 경우, gui 또는 dmv가 시작되었다고하더라도 양쪽 모두 서비스 액세스 사용 및 연결 권한 (재 부여를 시도한 후 엔드 포인트에서 새로운 시작)을 고려하십시오.


좀 더 자세한 내용은 원래 포스터에 도움이 될 것입니다.
joanolo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.