c# - ¿Qué está causando los concentradores de eventos de Azure ReceiverDisconnectedException/LeaseLostException?
azureservicebus azure-eventhub (1)
TLDR : Este comportamiento es absolutamente normal.
¿Por qué Lease Management no puede ser suave y sin excepciones ? Para dar más control sobre la situación al desarrollador.
La historia realmente larga, de EventProcessorhost
básico EventProcessorhost
(en este documento EPH
) es muy similar a lo que el __consumer_offset topic
hace para los Kafka Consumers
(propiedad de partición y tienda de punto de control) está escrita por el equipo de Microsoft Azure EventHubs
- para traducir todos los EventHubs partition receiver Gu
en una simple devolución de llamada onReceive(Events)
.
EPH
se utiliza para abordar 2 problemas generales, principales y bien conocidos al leer en secuencias de particiones de alto rendimiento como EventHubs
:
línea de tubería de recepción con tolerancia a fallas (por ejemplo, una versión más simple del problema) si el host que ejecuta un
PartitionReceiver
muere y regresa, debe reanudar el procesamiento desde donde lo dejó. Para recordar los últimosEventData
procesados conEventData
,EPH
utiliza elblob
suministrado al constructor deEPH
para almacenar los puntos de control, cuando el usuario invocacontext.CheckpointAsync()
. Eventualmente, cuando el proceso del host se detiene (por ejemplo, se reinicia repentinamente o se produce un fallo de hardware y nunca / vuelve), cualquier instancia deEPH
puede realizar esta tarea y reanudarla desde eseCheckpoint
.Equilibre / distribuya particiones en las instancias de
EPH
: digamos, si hay 10 particiones y 2 instancias deEPH
procesan eventos de estas 10 particiones: necesitamos una forma de dividir las particiones en las instancias (el componentePartitionManager
de la biblioteca deEPH
hace esto). Utilizamos elAzure Storage - Blob LeaseManagement-feature
para implementar esto. A partir de la versión2.2.10
: para simplificar el problema,EPH
asume que todas las particiones se cargan por igual .
Con esto, vamos a tratar de ver qué está pasando: Entonces, para comenzar, en el ejemplo anterior de 10
particiones de centro de eventos y 2
instancias de EPH
procesan eventos fuera de ellas:
- Digamos que la primera instancia de
EPH
:EPH1
comenzó, al principio, solo y como parte de la puesta en marcha, creó receptores para las 10 particiones y está procesando eventos. En el inicio,EPH1
anunciará que posee todas estas10
particiones al adquirir Arrendamientos en10
blobs de almacenamiento que representan estas10
particiones de centro de eventos (con unanomenclature
estándar, queEPH
crea internamente en la cuenta de Almacenamiento) desde elStorageConnectionString
pasado alctor
). Los contratos de arrendamiento se adquirirán por un tiempo determinado , después de lo cual la instancia deEPH
perderá la propiedad de esta Partición. -
EPH1
announces
continuamente de vez en cuando, que aún es propietario de esas particiones, mediante larenewing
contratos de arrendamiento en el blob. La frecuencia derenewal
, junto con otros ajustes útiles, se puede realizar usandoPartitionManagerOptions
- ahora, digamos,
EPH2
inicia, y usted también proporcionó el mismoAzureStorageAccount
comoEPH1
alctor
deEPH2
. En este momento, tiene0
particiones para procesar. Por lo tanto, para lograr el equilibrio de las particiones en las instancias deEPH
, seguirá adelante ydownload
la lista de todos losleaseblobs
que tienen la asignación deowner
apartitionId
. A partir de esto,STEAL
arrendará los arrendamientos por su parte justa departitions
, que son5
en nuestro ejemplo, y anunciará esa información en esalease blob
. Como parte de esto,EPH2
lee el último punto de control escrito porPartitionX
, quiere robar el contrato de arrendamiento y continúa, y crea losPartitionReceiver
correspondientes con elEPOCH
igual al delCheckpoint
. - Como resultado,
EPH1
perderá la propiedad de estas 5partitions
y se encontrará con diferentes errores según el estado exacto en el que se encuentre.- si
EPH1
está invocando realmente elPartitionReceiver.Receive()
call - mientras queEPH2
está creando elPartitionReceiver
en el mismo receptor,EPH1
experimentará ReceiverDisconnectedException . Esto eventualmente, invocaráIEventProcessor.Close(CloseReason=LeaseLost)
. Tenga en cuenta que la probabilidad de alcanzar esta excepción específica es mayor si los mensajes que se reciben son mayores o siPrefetchCount
es menor, ya que en ambos casos el receptor estaría realizando una E / S más agresiva. - si
EPH1
está en el estado decheckpointing
dellease
o larenewing
dellease
, mientras que elEPH2
stole
el contrato de arrendamiento,EventProcessorOptions.ExceptionReceived
eventHandler se marcaría con unaleaselostException
(con409
conflicto de conflicto en elleaseblob
) - que también eventualmente invoca aIEventProcess.Close(LeaseLost)
- si
¿Por qué no puede la administración de arrendamientos ser fluida y sin excepciones ?
Para mantener al consumidor simple y sin errores, las excepciones relacionadas con la administración de arrendamientos podrían haber sido tragadas por EPH
y no haber sido notificadas al código de usuario en absoluto. Sin embargo, nos dimos cuenta de que lanzar LeaseLostException
podría ayudar a los clientes a encontrar errores interesantes en la devolución de llamada IEventProcessor.ProcessEvents()
, para lo cual el síntoma sería: movimientos frecuentes de partición
- interrupción menor de la red en una máquina específica - ¡debido a que
EPH1
no puederenew
contratos y vuelve a funcionar! - ¡e imagínese si el n / w de esta máquina permanece inestable durante un día - las instancias deEPH
van a jugarping-pong
conPartitions
! Esta máquina intentará continuamente robar el contrato de arrendamiento de otra máquina, lo cual es legítimo desde el punto de vista deEPH
, pero es un desastre total para el usuario deEPH
, ya que interfiere completamente con la tubería de procesamiento.EPH
- vería exactamente unaReceiverDisconnectedException
, cuando el n / w vuelva a aparecer en este m / c escamoso! Creemos que lo mejor y de hecho la única forma es permitir que el desarrollador huela esto. - o un escenario simple como, tener un error en la lógica de
ProcessEvents
, queProcessEvents
excepciones no controladas que son fatales yProcessEvents
todo el proceso, por ejemplo, un evento venenoso. Esta partición va a moverse mucho. - clientes, realizando operaciones de escritura / eliminación en la misma cuenta de almacenamiento que
EPH
también utiliza, por error (como un script de limpieza automatizado), etc. - Por último, pero no menos importante, lo que nunca desearíamos que sucediera, digamos una
outage
5 minutos en Azure dc donde se encuentra unaEventHub.Partition
específica deEventHub.Partition
. Diga n / w incidente. Las particiones se moverán a través de las instancias deEPH
.
Básicamente, en la mayoría de las situaciones, sería complicado, para nosotros detectar la diferencia. entre estas situaciones y un contrato de arrendamiento legítimo debido al equilibrio y queremos delegar el control de estas situaciones al Desarrollador.
Consulte el blog de nuestro PM Dan para obtener una descripción general.
Estoy recibiendo eventos de un EventHub utilizando EventProcessorHost y una clase IEventProcessor (llámelo: MyEventProcessor). Escalo a dos servidores ejecutando mi EPH en ambos servidores, y haciendo que se conecten al concentrador utilizando el mismo grupo de consumidores, pero los nombres de host únicos (utilizando el nombre de la máquina).
El problema es: en horas aleatorias del día / noche, la aplicación registra esto:
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)
Esta excepción se produce al mismo tiempo que una LeaseLostException, lanzada desde el método CloseAsync de MyEventProcessor cuando intenta un punto de control. (¿Se supone que se llama a Close debido a la ReceiverDisconnectedException?)
Creo que esto está ocurriendo debido a la gestión automática de arrendamiento de Event Hubs al escalar a múltiples máquinas. ¿Pero me pregunto si debo hacer algo diferente para que funcione de manera más limpia y evitar estas Excepciones? Ej .: ¿algo con épocas?