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
PartitionReceivermuere y regresa, debe reanudar el procesamiento desde donde lo dejó. Para recordar los últimosEventDataprocesados conEventData,EPHutiliza elblobsuministrado al constructor deEPHpara 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 deEPHpuede realizar esta tarea y reanudarla desde eseCheckpoint.Equilibre / distribuya particiones en las instancias de
EPH: digamos, si hay 10 particiones y 2 instancias deEPHprocesan eventos de estas 10 particiones: necesitamos una forma de dividir las particiones en las instancias (el componentePartitionManagerde la biblioteca deEPHhace esto). Utilizamos elAzure Storage - Blob LeaseManagement-featurepara implementar esto. A partir de la versión2.2.10: para simplificar el problema,EPHasume 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:EPH1comenzó, al principio, solo y como parte de la puesta en marcha, creó receptores para las 10 particiones y está procesando eventos. En el inicio,EPH1anunciará que posee todas estas10particiones al adquirir Arrendamientos en10blobs de almacenamiento que representan estas10particiones de centro de eventos (con unanomenclatureestándar, queEPHcrea internamente en la cuenta de Almacenamiento) desde elStorageConnectionStringpasado alctor). Los contratos de arrendamiento se adquirirán por un tiempo determinado , después de lo cual la instancia deEPHperderá la propiedad de esta Partición. -
EPH1announcescontinuamente de vez en cuando, que aún es propietario de esas particiones, mediante larenewingcontratos de arrendamiento en el blob. La frecuencia derenewal, junto con otros ajustes útiles, se puede realizar usandoPartitionManagerOptions - ahora, digamos,
EPH2inicia, y usted también proporcionó el mismoAzureStorageAccountcomoEPH1alctordeEPH2. En este momento, tiene0particiones para procesar. Por lo tanto, para lograr el equilibrio de las particiones en las instancias deEPH, seguirá adelante ydownloadla lista de todos losleaseblobsque tienen la asignación deownerapartitionId. A partir de esto,STEALarrendará los arrendamientos por su parte justa departitions, que son5en nuestro ejemplo, y anunciará esa información en esalease blob. Como parte de esto,EPH2lee el último punto de control escrito porPartitionX, quiere robar el contrato de arrendamiento y continúa, y crea losPartitionReceivercorrespondientes con elEPOCHigual al delCheckpoint. - Como resultado,
EPH1perderá la propiedad de estas 5partitionsy se encontrará con diferentes errores según el estado exacto en el que se encuentre.- si
EPH1está invocando realmente elPartitionReceiver.Receive()call - mientras queEPH2está creando elPartitionReceiveren el mismo receptor,EPH1experimentará 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 siPrefetchCountes menor, ya que en ambos casos el receptor estaría realizando una E / S más agresiva. - si
EPH1está en el estado decheckpointingdelleaseo larenewingdellease, mientras que elEPH2stoleel contrato de arrendamiento,EventProcessorOptions.ExceptionReceivedeventHandler se marcaría con unaleaselostException(con409conflicto 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
EPH1no puederenewcontratos y vuelve a funcionar! - ¡e imagínese si el n / w de esta máquina permanece inestable durante un día - las instancias deEPHvan a jugarping-pongconPartitions! 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, queProcessEventsexcepciones no controladas que son fatales yProcessEventstodo 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
EPHtambié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
outage5 minutos en Azure dc donde se encuentra unaEventHub.Partitionespecí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?