นายหน้าบริการได้รับการสำรองข้อมูลตอนนี้ได้รับแล้ว แต่ดูเหมือนว่าจะไม่ได้รับการประมวลผล


20

มีปัญหากับการแจ้งเตือนกิจกรรม บนเครื่อง / ไดรฟ์ / ฐานข้อมูลที่ข้อความถูกส่งไปยัง (ตัวรับสัญญาณ) หมายถึงไดรฟ์เต็มเมื่อไม่มีใครค้นหาดังนั้นจึงถูกสำรองตลอดทั้งวัน

ตอนนี้เราเพิ่มพื้นที่ว่างในไดรฟ์ก็ยอมรับข้อความในคิว แต่ดูเหมือนว่าจะไม่ประมวลผล - ไม่มีระเบียนใหม่แทรกแม้ว่าคิวจะมี 22 ล้านข้อความและเพิ่มขึ้น (!) เปิดใช้งานคิว IS:

is_activation_enabled = 1
is_receive_enabled = 1
is_enqueue_enabled = 1

ฉันเห็น SP ที่เปิดใช้งานอยู่activation_procedureแต่เมื่อฉันดูSP_WHOISACTIVEฉันไม่เห็นผู้อ่านที่ใช้งานอยู่

ก่อนที่ฉันจะระเบิดออกอีกครั้งฉันทำอะไรผิด ฉันจะนำไปดำเนินการหรือล้างข้อความได้อย่างไร ขอบคุณล่วงหน้า.

ปรับปรุง

One thought - ตั้งแต่ฉันมี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? ขั้นตอนการเปิดใช้งานของคุณมีลักษณะอย่างไร คุณสามารถโพสต์ได้ที่นี่? อาจเป็นไปได้ว่ากระบวนการกำลังพยายามประมวลผลข้อความทั้งหมดในครั้งเดียว (เช่นในธุรกรรมเดียว) ซึ่งอาจไม่ดี นอกจากนี้ยังไม่มีสิ่งใดที่ป้องกันไม่ให้คุณเปิดใช้งานการเปิดใช้งานด้วยตัวเอง
Ben Thul

2
คิวอาจถูกปิดใช้งานเนื่องจากข้อความพิษ (ความล้มเหลวมากเกินไป) โปรดสอบถาม sys.transmission_queue และแจ้งให้เราทราบว่ามีข้อผิดพลาดใดบ้างที่รายงาน หากความสงสัยของฉันถูกต้องคุณควรพยายามเริ่มคิวใหม่โดยใช้คำสั่ง ALTER QUEUE
Robert L Davis

3
@BenThul เพิ่มรหัสกระบวนงานที่เก็บไว้ในคำถาม FWIW ฉันไม่ได้ใช้ 1 = 1 ฉันพูดกับรีมัสรุซานูเกี่ยวกับเรื่องนี้เมื่อสองสามปีก่อนและเขาก็พูดว่าไม่มีเหตุผลอะไรที่จะใช้มันและฉันก็ดัดแปลงของฉันให้เหมาะสม ที่ถูกกล่าวว่าฉันอาจจะต้องดูที่การเปลี่ยนแปลงเพื่อดำเนินการแบทช์ 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]; endใน SSMS เพื่อปลอมมัน
เบ็นธูล

6
ลองดูที่rusanu.com/2008/08/03/understanding-queue-monitorsและดูว่ามันใช้ได้หรือไม่
Remus Rusanu

คำตอบ:


2

สำหรับปลายทาง tcp ทั้งสองข้างให้ลองใช้ acct ของบริการและเชื่อมต่อการอนุญาต - ลองให้สิทธิ์ใหม่จากนั้นเริ่มต้นใหม่บนจุดสิ้นสุด -> แม้ว่า gui หรือ dmv จะบอกว่าเริ่มแล้ว


รายละเอียดเพิ่มเติมเล็กน้อยอาจช่วยโปสเตอร์ต้นฉบับได้
joanolo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.