【问题标题】:Service Broker : Sys.Conversation_endpoints filling up with CO/CONVERSING messages when using With CleanupService Broker:使用 With Cleanup 时,Sys.Conversation_endpoints 会填满 CO/CONVERSING 消息
【发布时间】:2010-08-10 10:28:44
【问题描述】:

我们最近发现我们的一个数据库存在问题,由于设置了“即发即弃”(即:会话在发送后立即关闭),我们的 sys.conversation_endpoints 表被 DI/DISCONNECTED_INBOUND 消息填满。这最终溢出到 tempDB 中,导致它急剧增长并占用宝贵的磁盘空间。我们最终通过注释掉这一行来解决了这个问题

END CONVERSATION @handle WITH CLEANUP

在我们的发送 SP 中并在我们的接收 SP 中使用相同的代码关闭对话,

END CONVERSATION @handle WITH CLEANUP

但是,我们现在有一个新问题。自从移动服务器(并从 SQL Server 2005 迁移到 SQL Server 2008)以来,我们最近发现 sys.conversation_endpoints 现在充满了 CO/CONVERSING 消息,表明对话没有关闭。接收 SP 正在关闭它们,或者至少正在运行命令来这样做,所以我不明白这些消息来自哪里。

我尝试返回在发送点结束对话,但没有任何效果。使用WITH CLEANUP 结束接收端的对话是错误的吗?还是有其他问题?

这个post on techtarget 似乎表明它是一个错误,并且运行清理剩余物的作业是唯一的解决方案...

更新: Pawel 在下面指出,我应该避免使用 Fire & Forget 模式,并且我已将激活的 SP 添加到发起者队列以结束任何对话。但是,sys.conversation_endpoints 仍然被填满,这次是 CD/CLOSED 消息。这是我的队列结构

发送_SP:

DECLARE @h UNIQUEIDENTIFIER 
BEGIN DIALOG CONVERSATION @h 
FROM SERVICE 'InitiatorQueue' TO SERVICE 'TargetQueue' 
ON CONTRACT 'MyContract' WITH ENCRYPTION = OFF; 
SEND ON CONVERSATION @h MESSAGE TYPE 'MyMessage' (@msg)

Receive_SP(TargetQueue 上激活的 SP)

DECLARE @type SYSNAME, @h UNIQUEIDENTIFIER, @msg XML;
DECLARE @target TABLE (
    [message_type_name] SYSNAME,
    [message_body] VARBINARY(MAX),
    [conversation_handle] UNIQUEIDENTIFIER
)
WHILE(1=1)
BEGIN TRANSACTION
    WAITFOR(RECEIVE TOP (1000) 
        [message_type_name],[message_body],[conversation_handle] 
        FROM TargetQueue INTO @target), TIMEOUT 2000            
    IF(@@rowcount!=0)
    BEGIN
        WHILE((SELECT count(*) FROM @target) > 0) 
        BEGIN
        SELECT TOP (1) @type = [message_type_name],
            @msg = [message_body],
            @h = [conversation_handle]  FROM @target;
        // Handle Message Here
        END CONVERSATION @h; 
        DELETE TOP (1) FROM @target;
    END
END
COMMIT TRANSACTION;

End_SP(在 InitiatorQueue 上激活的 SP)

DECLARE @type SYSNAME, @h UNIQUEIDENTIFIER, @msg XML;
DECLARE @init TABLE (
    [message_type_name] SYSNAME,
    [message_body] VARBINARY(MAX),
    [conversation_handle] UNIQUEIDENTIFIER
)
WHILE(1=1)
BEGIN TRANSACTION
    WAITFOR(RECEIVE TOP (1000) 
        [message_type_name],[message_body],[conversation_handle] 
        FROM InitiatorQueue INTO @init), TIMEOUT 2000           
    IF(@@rowcount!=0)
    BEGIN
        WHILE((SELECT count(*) FROM @init) > 0) 
        BEGIN
        SELECT TOP (1) @type = [message_type_name],
            @msg = [message_body],
            @h = [conversation_handle]  FROM @init;
        END CONVERSATION @h; 
        DELETE TOP (1) FROM @init;
    END
END
COMMIT TRANSACTION;

【问题讨论】:

    标签: sql-server sql-server-2008 service service-broker


    【解决方案1】:

    使用即发即弃模式将不可避免地导致此类问题和其他类型的问题。此外,它会使任何假设的错误都被忽视。是否有任何理由不能更改消息交换模式,以便目标在收到消息后发出 END CONVERSATION (不进行清理!),然后发起者在收到结束对话消息时仅调用 END CONVERSATION (同样,不进行清理)来自目标?

    【讨论】:

    • 嗨 Pawel,我当然可以删除我一直在使用的 WITH CLEANUP,你认为这会导致问题吗?我知道我使用的模式不是最好的,但它适合我们拥有的服务类型。
    • 当您说“即发即弃”模式适合您所拥有的服务类型时,您含蓄地承认“即发即弃”的固有问题也适合该服务类型。换句话说,您是说您可以接受 conversation_endpoints 已满、消息丢失和错误丢失。我个人不认为任何类型的服务(至少不是我想使用的任何服务)都可以处理这些事情,这就是为什么我建议放弃“即发即弃”的方法。但最后当然是你的选择。
    • 嗨,Pawel,我没有完全理解。我们目前有一个系统,它通过服务代理队列将单向消息从 asp.net 应用程序发送到数据库。接收激活过程使用表变量,一次从队列中拉出 1000 条消息,处理并结束每条消息。因此,消息可以在队列中停留几秒钟。我假设(可能是错误的)将发起者更改为也监听这些消息的结束对话会严重延迟系统(即每个请求几秒钟),这不准确吗?
    • 刚刚意识到我也可以将激活的 sp 放在启动器队列中,这当然可以消除任何延迟问题。多哈。不幸的是,它仍然无法正常工作 - 我现在正在更新问题
    • 目标端的对话端点应该在对话结束后停留一段时间(处于 CLOSED 状态)。这是一种安全措施,是设计使然。但是,它们应该在大约 30 分钟后消失。这是你看到的吗?
    猜你喜欢
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-22
    相关资源
    最近更新 更多