问题描述
Service Bus接收端的日志中出现大量的MessageLockLostException异常。完整的错误消息为:
|
Microsoft.Azure.ServiceBus.MessageLockLostException: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue. Reference:b2b452db-bf32-41c1-8b76-e546fbdc3856, TrackingId:625929b5-7392-4bf2-9beb-63c132837fc8_B0, SystemTracker:nchn-pr-dep-iot-bus:Queue:dep-iot-input-st-output, Timestamp:2020-12-01T06:13:15 |
问题原因
在接收方使用预提取后,Service Bus服务将锁定此次预提取的消息。通过锁定操作,其他接收方则无法接收到此预提取的消息(保持消息唯一消费)。如果接收方在锁定过期之前无法完成此消息,则该消息便对其他接收方可用。
MessageLockLostException)。
这一值可延长到 5 分钟。 通常在创建队列时进行设置。 这是队列级别的属性,不能在消息基础上进行更改。如下图中的Message lock duration(可以点击Change Link进行修改).
解决问题
方法一:修改Message Lock Duration的时间长度,最大可以修改到5分钟。
方法二:在设定消息CompleteAsync前,判断时间 message.LockedUntilUtc中的时间是否已经超过了Message Lock Duration,如果消息未到期但即将到期,可通过调用RenewLock,延续和扩展又一默认锁定时间段
if(message.LockedUntilUtc.Minute <= 1) message.RenewLock();
message.RenewLock() 延续和扩展又一默认锁定时间段
如果在消息过期期间往往无法使用预提取缓存区,这将导致重复预提取消息,但始终无法将其以可用(有效锁定)状态有效送达,并最终在超出最大传送数后移动到死信队列。
扩展问题
1:https://docs.azure.cn/zh-cn/service-bus-messaging/service-bus-prefetch#if-it-is-faster-why-is-prefetch-not-the-default-option)
这种吞吐量提升是应用程序作者不得不明确作出的某种权衡的结果:
通过 ReceiveAndDelete 接收模式,预提取缓存区获取的所有消息在队列中不再可用,仅驻留在内存中预提取缓存区,直到应用程序通过 Receive/ReceiveAsync 或 OnMessage/OnMessageAsync API 接收到它们 。 如果在应用程序接收到消息前终止应用程序,这些消息将丢失,且不可恢复。
在 PeekLock 接收模式下,提取到预提取缓存区的消息将以锁定状态进入缓存区,并且将超时时钟用于锁定计时。 如果预提取缓存区很大,且处理所需时间过长,以致消息锁定在驻留于预提取缓存区,甚至应用程序还在处理消息时就到期,可能出现一些令人困惑的事件要应用程序处理。 如MessageLockLostException
如果消息处理需要高度的可靠性,且处理需要大量精力和时间,则建议谨慎使用或者丝毫不用预提取功能。
如果需要较高吞吐量且消息处理通常比较便宜,则预提取会产生显著的吞吐量优势。
参考资料
Windows Azure MessageLockLostException : https://stackoverflow.com/questions/15303711/windows-azure-messagelocklostexception
使用服务总线消息传递改进性能的最佳实践: https://docs.azure.cn/zh-cn/service-bus-messaging/service-bus-performance-improvements?tabs=net-standard-sdk#prefetching