Utworzono kopię zapasową brokera usług, który jest teraz odbierany, ale wydaje się, że nie jest przetwarzany

20

Problem z powiadomieniami o zdarzeniach. Na komputerze / dysku / bazie danych, do których wysyłane są wiadomości (odbiornik), dysk zapełnił się, gdy nikt go nie szukał, więc kopia zapasowa jest tworzona przez cały dzień.

Teraz, gdy zwolniliśmy miejsce na dysku, przyjmuje on wiadomości do kolejki, ale wydaje się, że nie przetwarza ich - nie wstawiono żadnych nowych rekordów, mimo że kolejka ma teraz 22 miliony wiadomości i rośnie (!). Kolejka jest włączona:

is_activation_enabled = 1
is_receive_enabled = 1
is_enqueue_enabled = 1

Widzę aktywowany SP activation_procedure, ale kiedy zaglądam SP_WHOISACTIVE, nie widzę aktywnych czytników.

Zanim ponownie wysadzę dysk - co robię źle? Jak mogę go przetworzyć lub opróżnić wiadomości? Z góry dziękuję.

Aktualizacja

Jedna myśl - skoro mam is_enqueue_enabled, może przechowuje wszystkie wiadomości, dopóki nie przetworzy ich wszystkich? Jeśli tak, czy mogę to bezpiecznie wyłączyć?

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,
        [email protected]('(/EVENT_INSTANCE/PropertyName)[1]', 'varchar(128)' ) AS PropertyName,
        [email protected]('(/EVENT_INSTANCE/PropertyValue)[1]', 'varchar(128)' ) AS PropertyValue,
        [email protected]('(/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
mbourgon
źródło
1
Tak więc z opisu problemu korzystasz z aktywacji wewnętrznej. Czy jest coś wymienionego w sys.dm_broker_activated_tasks? Jak wygląda twoja procedura aktywacji? Czy możesz to tutaj opublikować? Możliwe, że procedura próbuje przetworzyć wszystkie wiadomości naraz (tj. W jednej transakcji), co może być złe. Ponadto nic nie stoi na przeszkodzie, aby ręcznie uruchomić aktywację.
Ben Thul,
2
Kolejka jest prawdopodobnie wyłączona z powodu zatrutego komunikatu (zbyt wiele awarii). Zapytaj sys.transmission_queue i powiedz nam, jakie błędy zgłasza. Jeśli moje podejrzenia są prawidłowe, powinieneś spróbować zrestartować kolejkę za pomocą instrukcji ALTER QUEUE.
Robert L. Davis,
3
@BenThul dodał do pytania kod aktywowanej procedury składowanej. FWIW, nie używam 1 = 1. Rozmawiałem o tym z Remusem Rusanu kilka lat temu, a on mówił o tym, że nie ma żadnego powodu, aby go używać, i odpowiednio zmodyfikowałem mój. Biorąc to pod uwagę, prawdopodobnie powinienem zastanowić się nad zmianą, aby wykonać serie 100/1000, dla szybkości. Ale dopóki się nie cofnął, działał jak mistrz, więc nie chciałem go dotykać.
mbourgon
2
Nie zgadzam się z tym, że pętla nie jest potrzebna w sytuacji, w której się teraz znajdujesz. Zgodnie z tym artykułem BOL ( technet.microsoft.com/en-us/library/... ) aktywacja prawdopodobnie nie jest uruchamiana wystarczająco często. Dlatego po uruchomieniu chcesz, aby każda procedura kontynuowała przetwarzanie komunikatów, dopóki nie będzie już żadnych do przetworzenia. Tylko moje dwa centy. Aby wykopać się z dziury, w której się teraz znajdujesz, możesz zrobić coś takiego while exists (select 1 from dbo.ENAudit_SBQueue) begin exec [dbo].[Parse_EN_Messages]; endw SSMS, aby to sfałszować.
Ben Thul,
6
Zajrzyj na rusanu.com/2008/08/03/understanding-queue-monitors i sprawdź, czy to dotyczy
Remus Rusanu

Odpowiedzi:

2

W przypadku punktów końcowych TCP, obie strony, rozważ użyty acct usługi i połącz uprawnienia - spróbuj ponownie przyznać, a następnie nowy start w punktach końcowych -> nawet jeśli GUI lub DMV mówi, że zostało uruchomione.

RickWillemain
źródło
Więcej szczegółów może pomóc oryginalnemu plakatowi.
joanolo,