是啥导致 Azure 事件中心 ReceiverDisconnectedException/LeaseLostException?
Posted
技术标签:
【中文标题】是啥导致 Azure 事件中心 ReceiverDisconnectedException/LeaseLostException?【英文标题】:What is causing Azure Event Hubs ReceiverDisconnectedException/LeaseLostException?是什么导致 Azure 事件中心 ReceiverDisconnectedException/LeaseLostException? 【发布时间】:2017-05-20 16:30:53 【问题描述】:我正在使用 EventProcessorHost 和 IEventProcessor 类(称为:MyEventProcessor)从 EventHub 接收事件。我通过在两台服务器上运行我的 EPH 将其扩展到两台服务器,并让它们使用相同的 ConsumerGroup 但唯一的主机名(使用机器名称)连接到集线器。
问题是:在白天/晚上的随机时间,应用程序会记录以下内容:
Exception information:
Exception type: ReceiverDisconnectedException
Exception message: New receiver with higher epoch of '186' is created hence current receiver with epoch '186' is getting disconnected. If you are recreating the receiver, make sure a higher epoch is used.
at Microsoft.ServiceBus.Common.ExceptionDispatcher.Throw(Exception exception)
at Microsoft.ServiceBus.Common.Parallel.TaskHelpers.EndAsyncResult(IAsyncResult asyncResult)
at Microsoft.ServiceBus.Messaging.IteratorAsyncResult`1.StepCallback(IAsyncResult result)
此异常与 LeaseLostException 同时发生,当它尝试检查点时从 MyEventProcessor 的 CloseAsync 方法抛出。 (大概是因为 ReceiverDisconnectedException 而调用了 Close?)
我认为这是由于事件中心在扩展到多台计算机时的自动租约管理所致。但是我想知道我是否需要做一些不同的事情来让它更干净地工作并避免这些异常?例如:带有时代的东西?
【问题讨论】:
可能会有所帮助social.msdn.microsoft.com/Forums/azure/en-US/… 你看到这个答案了吗:***.com/a/27832015/1658906? @OlegBogdanov 谢谢,我在这里发帖的目的是看看“是的,忽略它”是否是一个得到发布并获得社区支持的答案。要回答该海报的后续频率问题:我的例外情况有时会在 1 小时内发生 5 次,但随后可能会跳过几个小时,然后再次发生。我猜这 5 次出现可能是针对不同的分区,我注意到我没有记录发生异常的 partitionId。 @juunas 谢谢,使用两个消费者组不是我的答案,因为当您必须为多种目的读取数据时,应该使用单独的消费者组,即:去做不同的事情用它。就我而言,我出于一个目的读取数据,但将其扩展到多台机器(该链接也描述了这一点,但我认为我正在按照他们和 MS 的建议进行操作)。我只是不清楚为什么在多台机器(或工作角色)上运行我的 EPH 会导致抛出异常。他们的文档中没有一个人说会这样。 【参考方案1】:TLDR:这种行为是绝对正常的。
为什么租赁管理不能顺畅和无异常:让开发人员对情况有更多的控制权。
真正的长篇故事——从基础开始
EventProcessorhost
(特此EPH
- 与__consumer_offset topic
为Kafka Consumers
所做的非常相似 - 分区所有权和检查点存储)由Microsoft Azure EventHubs
团队自己编写 - 将所有EventHubs partition receiver Gu
转换为简单的@ 987654332@回调。
EPH
用于解决 2 个一般的、主要的、众所周知的问题,同时读取像 EventHubs
这样的高吞吐量分区流:
容错接收管道 - 例如:问题的更简单版本 - 如果运行 PartitionReceiver
的主机死亡并返回 - 它需要从哪里恢复处理它离开了。为了记住最后一次成功处理的EventData
,EPH
使用提供给EPH
构造函数的blob
来存储检查点——当用户调用context.CheckpointAsync()
时。最终,当主机进程终止时(例如:突然重启或遇到硬件故障并且永不/恢复) - 任何EPH
实例都可以接手该任务并从该Checkpoint
恢复。
在EPH
实例之间平衡/分配分区 - 假设有 10 个分区和 2 个 EPH
实例处理来自这 10 个分区的事件 - 我们需要一种划分方法跨实例分区(EPH
库的PartitionManager
组件执行此操作)。我们使用 Azure Storage - Blob LeaseManagement-feature
来实现这一点。从版本 2.2.10
开始 - 为简化问题,EPH
假设 所有分区均加载。
有了这个,让我们试着看看发生了什么:
因此,首先,在上面的 10
事件中心分区示例和 2
EPH
实例处理其中的事件:
-
让我们说第一个
EPH
实例-EPH1
最初是单独启动的,并且是启动的一部分,它为所有10 个分区创建了接收器并正在处理事件。在启动时 - EPH1
将通过在代表这些 10
事件中心分区的 10
存储 blob 上获取租约来宣布它拥有所有这些 10
分区(使用标准 nomenclature
- EPH
在内部创建在存储帐户中 - 从 StorageConnectionString
传递到 ctor
)。租约为acquired for a set time,之后EPH
实例将失去此分区的所有权。
EPH1
不断地 announces
偶尔 - 它仍然拥有这些分区 - 通过 blob 上的 renewing
租约。可以使用PartitionManagerOptions
执行renewal
的频率以及其他有用的调整
现在,可以说,EPH2
启动了 - 并且您还向 EPH2
的 ctor
提供了与 EPH1
相同的 AzureStorageAccount
。现在,它有0
分区要处理。因此,为了在EPH
实例之间实现分区平衡,它将继续处理download
的所有leaseblobs
列表,其中具有owner
到partitionId
的映射。据此,它将STEAL
租赁 公平份额的partitions
- 在我们的示例中为5
,并将公布有关lease blob
的信息。作为其中的一部分,EPH2
读取由PartitionX
编写的最新检查点,它想要窃取其租约并继续创建对应的PartitionReceiver
,EPOCH
与Checkpoint
中的相同。
因此,EPH1
将失去这 5 个partitions
的所有权,并会根据其所处的确切状态遇到不同的错误。
如果EPH1
实际上正在调用PartitionReceiver.Receive()
调用 - 而EPH2
在同一接收器上创建PartitionReceiver
- EPH1
将体验到ReceiverDisconnectedException。这最终将调用IEventProcessor.Close(CloseReason=LeaseLost)
。请注意,如果接收到的消息较大或 PrefetchCount
较小,则遇到此特定异常的可能性会更高 - 因为在这两种情况下,接收器都会执行更积极的 I/O。
如果EPH1
处于checkpointing
lease
或renewing
lease
的状态,而EPH2
stole
是租约,EventProcessorOptions.ExceptionReceived
eventHandler 将用@ 发出信号987654406@(leaseblob
上出现 409
冲突错误) - 最终也会调用 IEventProcess.Close(LeaseLost)
。
为什么租赁管理不能顺畅且无异常:
为了让消费者保持简单和无错误,与租赁管理相关的异常可能已被EPH
吞下,并且根本不会通知用户代码。然而,我们意识到,抛出LeaseLostException
可以让客户在IEventProcessor.ProcessEvents()
回调中发现有趣的错误——症状是——频繁的分区移动
EPH1
未能租用 renew
并重新启动! - 想象一下,如果这台机器的 n/w 一天都不稳定 - EPH
实例将与 Partitions
一起玩 ping-pong
!这台机器将不断尝试从其他机器窃取租约——从EPH
的角度来看这是合法的——但是对于EPH
的用户来说是一场彻底的灾难——因为它完全干扰了处理管道。 EPH
- 当 n/w 重新出现在这个易碎的 m/c 上时,会准确地看到 ReceiverDisconnectedException
!我们认为最好的也是唯一的办法就是让开发者闻到这种味道!
或一个简单的场景,例如,ProcessEvents
逻辑中的错误 - 引发未处理的致命异常并导致整个过程中断 - 例如:中毒事件。这个分区会经常移动。
客户,在 EPH
也在使用的同一存储帐户上执行写入/删除操作 - 错误地(如自动清理脚本)等。
最后但并非最不重要的——我们永远不希望发生这种情况——比如在 Azure d.c 上等待 5 分钟 outage
,那里有一个特定的 EventHub.Partition
——比如 n/w 事件。分区将在 EPH
实例之间移动。
基本上,在大多数情况下,我们很难检测差异。在这些情况和合法租约之间由于平衡而丢失,我们希望将这些情况的控制权委托给开发者。
more on Event Hubs...
【讨论】:
感谢您的详尽解释,非常感谢。关于 PartitionManagerOptions 的另一个小问题:您是否说我用于 LeaseInterval 的值应该始终大于我预期的消息处理时间,以避免分区在 EPH 之间弹跳而未完成消息处理?例如:我有一个 EventHub,其消息通过多次调用表存储来处理。对于此集线器上的一条消息,处理时间可能需要 1 分钟,因此当我在此 EventHub 上运行 2 个 EPH 时,我使用 LeaseInterval 超过 1 分钟是否至关重要? @plukich - partitionManagerOptions.LeaseInterval 和 RenewInterval 确定租约续订时间。续租不取决于 ProcessEventsAsync 调用所花费的时间。 @Sreeram 使用 EventHubClient 将事件重新发送到 EventHub 然后再次获取它会是一个很好的解决方案吗? 这不是对异常的某种“滥用”吗?正在向控制流抛出异常,而不是指示发生了意外错误。 我是一名 kafka 用户,并试图继续使用 azure eventthub。与 kafka 相比,Azure eventthub 并不快速和可靠。有很多连接丢失和消息异常。尚未准备好生产的驱动程序级别的代码。【参考方案2】:在我的情况下,我有一个本地实例,该函数应用程序在我的笔记本电脑上运行,另一个在云中运行。两者都具有相同的触发器配置(相同的 EH,相同的使用者)。
【讨论】:
以上是关于是啥导致 Azure 事件中心 ReceiverDisconnectedException/LeaseLostException?的主要内容,如果未能解决你的问题,请参考以下文章
Azure 通知中心:NotificationOutcome 中的成功和失败属性是啥
具有输入绑定的 Azure 函数的 Azure 事件中心存储容器配置
从 IoT 中心(Microsoft azure)获取数据的不同方法是啥?