1

我有一个没有任何明显原因的队列,在这个队列中我实现了一个位置消息处理。在处理过程中,它会记录并丢弃任何有害消息。

它运行良好一年多没有停止。但是最近(问题开始于四个星期前),它每周停止一次或两次。仅在本周它停止了两次。

而当我检查带有新中毒消息的表格时,没有!当我启用队列时,处理成功恢复并且“毒消息”情况不会重现。

关于队列的任务:每天大约接收2-3000条消息。它用于在事务之外运行存储过程。并且每条消息都可以持续一段时间进行处理(进行大量选择、插入、更新)。

让我解释一下这一点:数据库具有在事务内部触发的触发器,触发器发送消息以在触发器外部运行一些代码。异步行为可防止降低数据库的性能。

我检测到即使在处理消息时发生死锁,队列也会将消息视为中毒。所以原则上它不应该是一个性能问题。但是,可以吗?也许数据库正在增长并且处理消息的时间过长?

但是,如果它没有被检测为已定位,我怎么能找到它呢?
为什么队列停止的其他原因?
如何保存队列被禁用的时间和消息?
有人知道我如何进行取证分析吗?
任何想法?


更新暴露伪解决方案:
根据 Remus 的帖子,我尝试使用事件通知来获取队列停止的确切时刻。

CREATE EVENT NOTIFICATION [QueueDisabledEN]
  ON QUEUE [dbo].[ProcessQueue]
  FOR BROKER_QUEUE_DISABLED
  TO SERVICE 'Queue Watch Service', 'current database';

然后检查事件日志:

select * from sys.event_notificiation

但是由于很难知道事件发生的环境,(此时还有什么正在运行??),取证分析到此结束。幸运的是,我的代理服务实现将消息存储为发货日期、收货日期、处理日期……这有助于我检测到在 3 秒内队列中充斥着数百条需要很长时间才能处理的消息.

虽然我找到了一个真正的解决方案,但唯一的临时解决方案是每 x 分钟检查一次代理作业并启用它:

IF (EXISTS(SELECT * FROM sys.service_queues WHERE name like 'ProcessQueue' AND (is_receive_enabled = 0 OR is_enqueue_enabled = 0))) BEGIN
    PRINT convert(nvarchar, getdate(), 121)+ ': Activando la cola ProcessQueue'
    ALTER QUEUE ProcessQueue WITH STATUS = ON 
END

谢谢莱姆斯!

4

1 回答 1

4

当您发现队列处于禁用状态并重新启用队列时,我假设处理成功恢复并且“毒消息”情况不会重现。这将表明原因是暂时的或与时间相关的。它可能是正在运行的 SQL 代理作业并导致队列处理死锁,从而强制队列处理回滚。根据我的经验,死锁是最典型的中毒消息原因。您最好的取证工具是系统事件日志,因为激活的过程确实会将错误输出到 ERRORLOG 并因此输出到系统事件日志中。

每当队列被有害消息触发器(5 次连续回滚)禁用时,就会触发 QUEUE_DISABLED 类型的事件通知。您可以在处理此事件时捕获更多取证信息,因为它将在队列被禁用后不久运行。

作为旁注,您永远无法拥有真正的“毒药消息处理”。每当您增强处理以处理某些错误情况时,“毒消息”的定义都会更改为能够禁用新错误处理的消息

于 2011-01-26T18:04:44.343 回答