问题详情
使用EPH获取Event Hub数据时,多次出现连接shutdown和LeaseLost的error ,截取某一次的error log如:
Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '29', Reason: 'LeaseLost'. Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '26', Reason: 'LeaseLost'. Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '1', Reason: 'LeaseLost'. Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '22', Reason: 'LeaseLost'. Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '8', Reason: 'LeaseLost'. Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '9', Reason: 'LeaseLost'. Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '7', Reason: 'LeaseLost'. Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '31', Reason: 'LeaseLost'. Time:2021-03-10 08:43:48.4650|NE:VSDN|Machine:RD0003FF01A8BE|Lv:INFO|ActivityId:|Msg:CdmEventProcessor Shutting Down. Partition '17', Reason: 'LeaseLost' ....
|
如何解释EPH的Shutting Down呢?为什么出现LeaseLost(租约丢失)情况呢?
问题解释
在Azure SDK Microsoft.Azure.EventHubs.Processor 的解释中列举出LeaseLost是The lease was lost or transitioned to a new processor instance,表示当前租约丢失,或者转移到一个新的Processor实例上。
这是因为Event Hub可以设置多个分区,同时也可以通过多个消费端来消费分区中的数据,但是多少个客户端是最好的呢?根据【Azure 事件中心的 .NET 编程指南】中对EPH(Event Processor Host)的介绍,客户端主机将尝试使用“贪婪”算法获取事件中心内每个分区上的租约,如果当前只有一个消费端连接Event Hub,则当前消费端会把所有分区的租约都获取过去。当有2个或者多个消费端时,它们会自动在多个消费端中进行负载均衡,最终达到动态平衡
- 只有一个消费端时(Azure Worker Role 1),8个分区都与它建立租约。
- 当有第二个消费端时(Azure Worker Role 2), EPH就自动动态平衡分区数,最终表现为各自处理4个分区数据。
- 而原来与Worker Role 1相连的5,6,7,8分区就会出现shutdown,原因时leaselost的日志记录。
所以,我们观察到的Shutdown LeaseLost日志消息就是因为EPH在自动进行多个实例间分区数的动态平衡而产生的。这是完全正常的现象。
EPH出现LeaseLost的详细分解
TLDR: This behavior is absolutely normal.
Why can't Lease Management be smooth & exception-free: To give more control on the situation to developer.
The really long story - all-the-way from Basics
EventProcessorhost
(herebyEPH
- is very similar to what__consumer_offset topic
does forKafka Consumers
- partition ownership & checkpoint store) is written byMicrosoft Azure EventHubs
team themselves - to translate all of theEventHubs partition receiver Gu
into a simpleonReceive(Events)
callback.... ...
译文内容为:
TLDR: This behavior is absolutely normal. 这是正常的行为
为什么不能让Event Hub分区租约的管理不出现异常呢?这是为了更好地让开发者来控制租约到期(Lease Lost)的情况。
这需要从EventProcessorHost(简称 EPH)从创建之时说起, EPH是由Microsoft Azure EventHubs团队开发,用来把所有的EventHubs partition receiver事件转换为一个简单的回调事件 onReceive。这样的目的是为了解决在读取高吞吐量分区数据流的情况下的2个主要的,众所周知的问题
1)容错接收管道 (Fault tolerant receive pipe-line) - 如果运行PartitionReceiver的Host 宕机后恢复正常,则它需要从其宕机的地方继续进行处理。 为了记住上一次成功处理的EventData,EPH使用提供给EPH构造函数的Blob来存储检查点(Checkpoints -调用context.CheckpointAsync()时)。 所以,当Host进程终止时(例如:突然重新启动或遇到硬件故障,再也无法恢复),任何EPH实例都可以执行此任务并从该Checkpoint恢复。
2)在EPH实例之间动态分配分区 (Balance/distribute partitions across EPH
instances) 假设有10个分区和2个EPH实例处理来自这10个分区的事件 - 需要一种在实例之间划分分区的方法(PartitionManager组件)。 使用Azure存储-Blob LeaseManagement功能来实现这一点。 从2.2.10版本开始 --- 简化为EPH假定所有分区均被加载。
基于以上的情况,我们来看一看EPH发生了什么,首先, 在上面的10个事件中心分区和2个EPH实例的示例中,处理其中的事件顺序如下:
一:假设第一个EPH实例(EPH1)最初是单独启动的,它为所有10个分区创建了接收器,并且开始处理事件。在启动过程中 --- EPH1将通过获取代表这10个事件中心分区的租约(存储Blob上)来宣布拥有所有这10个分区(EPH在存储帐户中内部创建-从StorageConnectionString中获取Blob)。但是该租约旨在指定时间内有效,有效期过后,EPH1会失去对分区的所有权
二:通过更新Blob上的租约,EPH1会连续续订这10个分区的租约。 续订频率以及其他有用的调整可以使用PartitionManagerOptions修改
三:启动第二个EPH实例(EPH2), 并且使用与EPH1相同的StorageConnectionString。开始时,EPH2有0个分区要处理,为了要在EPH实例之间实现分区的动态平衡,EPH2将下载租约列表(包含分区ID与拥有者的映射关系)。并会平均的截取5个分区的租约。在整个过程中,EPH2会根据所获取的分区信息得到最新的检查点(checkpoint),创建PartitionReceiver并继续接收消息
四:最后,EPH1将失去对这5个分区的所有权,并将根据其分区的实时状态而遇到不同的错误。
- 如果EPH1正在调用PartitionReceiver.Receive时,而且EPH2在同一分区创建PartitionReceive, EPH1就会遇见ReceiverDisconnectedException。并且调用EventProcessor.Close方法,Close Reason为LeaseLost
- 如果EPH1处于
checkpointing
或renewing
租约的状态,而EPH2窃取了租约,则产生EventProcessorOptions.ExceptionReceived异常,eventHandler带有leaselostException的信号(409 conflict error)-最终也会调用IEventProcess.Close (LeaseLost)
为什么不能让Event Hub分区租约的管理不出现异常呢?(Why can't Lease Management be smooth & exception-free)
为了使消费端简单和无错误,EPH可以吞下与租约相关的异常,而不通过用户代码的方式通知。 但是,我们意识到,抛出LeaseLostException可能使客户能够在IEventProcessor.ProcessEvents()回调中找到问题的根源 --- 可能是频繁进行分区移动造成
- 当消费端实例(EPH)发生轻微的网络抖动, 使得EPH无法续订租约而重启。如果这个实例的网络一直处于抖动情况,EPH将来来回回获取Partitions信息,同时不断的尝试从其他EPH中窃取租约。这将导致消费端无法处理正常的Event Hub事件。当发生这样的情况时,可以在日志中可见ReceiverDisconnectedException异常,这一点可以非常好的帮助开发者定位问题。
- 或是在ProcessEvents的逻辑代码中出现无法处理的异常,并导致整个进程被破坏,分区也会在多个EPH实例之间来回移动。
- 也有可能是在EPH中使用的储存账户上有执行write/delete操作,与EPH实例执行的操作冲突等。
- 也有可能是Azure的数据中心发生大范围的宕机事件(不希望这样的情况发生),分区也会在多个EPH实例之间来回移动。
在大多数情况下,对于Event Hub SDK而言,要检测以上这些异常是非常棘手的。 所以SDK团队将控制权委托给开发者,开发者通过抛出的异常来定位问题。
参考资料
CloseReason Enum:https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.eventhubs.processor.closereason?view=azure-dotnet#fields
What is causing Azure Event Hubs ReceiverDisconnectedException/LeaseLostException? https://stackoverflow.com/questions/41496754/what-is-causing-azure-event-hubs-receiverdisconnectedexception-leaselostexceptio
Event Hub事件使用者:https://docs.azure.cn/zh-cn/event-hubs/event-hubs-programming-guide#event-consumers