Solución de problemas del procesador de eventos de Azure Event Hubs

Este artículo le ayuda a solucionar Azure Event Hubs problemas de procesador de eventos al usar el EventProcessorClient tipo . Úselo para resolver problemas comunes de propiedad, CPU, memoria y receptor. Para obtener soluciones a otros problemas comunes que pueden surgir al usar Azure Event Hubs, consulte Solución de problemas de Azure Event Hubs.

412 errores de condición previa cuando se usa un procesador de eventos

412 errores de condición previa se producen cuando el cliente intenta tomar o renovar la propiedad de una partición, pero la versión local del registro de propiedad está obsoleta. Este problema se produce cuando otra instancia del procesador roba la propiedad de la partición. Para obtener más información, vea la siguiente sección.

La propiedad de las particiones cambia con frecuencia

Cuando cambia el número de EventProcessorClient instancias (es decir, cuando se agregan o quitan instancias), las instancias en ejecución intentan equilibrar la carga de particiones entre sí mismas. Durante unos minutos después de que cambie el número de procesadores, las particiones cambian de propietario. Una vez equilibrada, la propiedad de la partición es estable y cambia con poca frecuencia. Si la propiedad de la partición cambia con frecuencia cuando el número de procesadores es constante, es probable que indique un problema. Abra una incidencia en GitHub con los logs y unos pasos para reproducirlo.

El CheckpointStore determina la propiedad de la partición mediante registros de propiedad. En cada intervalo de equilibrio de carga, EventProcessorClient realiza las siguientes tareas:

  1. Capture los registros de propiedad más recientes.
  2. Compruebe los registros para ver qué registros no actualizaron su marca de tiempo dentro del intervalo de expiración de la propiedad de la partición. Solo se tienen en cuenta los registros que coinciden con estos criterios.
  3. Si hay particiones sin propietario y la carga no está equilibrada entre instancias de EventProcessorClient, el cliente del procesador de eventos intenta reclamar una partición.
  4. Actualice el registro de propiedad de las particiones que posee y que tienen un vínculo activo con esas particiones.

Puede configurar los intervalos de equilibrio de carga y de expiración de propiedad al crear el EventProcessorClient a través del EventProcessorClientBuilder, como se describe en la lista siguiente.

Por ejemplo, si un registro de propiedad se actualizó a las 9:30 a. m. y partitionOwnershipExpirationInterval es de 2 minutos. Cuando se produce un ciclo de equilibrio de carga y detecta que el registro de propiedad no se ha actualizado en los últimos 2 minutos o a las 9:32 a. m., considera que la partición no tiene propietario.

Si se produce un error en uno de los consumidores de partición, cierra el consumidor correspondiente, pero no intenta recuperarlo hasta el siguiente ciclo de equilibrio de carga.

"... el receptor actual "<RECEIVER_NAME>" con la época "0" se está desconectando"

El mensaje de error completo es similar al siguiente resultado:

New receiver 'nil' with higher epoch of '0' is created hence current receiver 'nil' with epoch '0'
is getting disconnected. If you are recreating the receiver, make sure a higher epoch is used.
TrackingId:&lt;GUID&gt;, SystemTracker:&lt;NAMESPACE&gt;:eventhub:&lt;EVENT_HUB_NAME&gt;|&lt;CONSUMER_GROUP&gt;,
Timestamp:2022-01-01T12:00:00}"}

Este error se produce cuando se produce el equilibrio de carga después de agregar o quitar EventProcessorClient instancias. El equilibrio de carga es un proceso en curso. Cuando usa BlobCheckpointStore con su consumidor, aproximadamente cada 30 segundos (de forma predeterminada), el consumidor comprueba qué consumidores tienen asignada cada partición. A continuación, ejecuta cierta lógica para determinar si necesita "robar" una partición de otro consumidor. El mecanismo de servicio usado para afirmar la propiedad exclusiva sobre una partición se conoce como Época.

Sin embargo, si no estás añadiendo ni eliminando instancias, existe un problema subyacente que deberías solucionar. Para obtener más información, consulte la sección Cambios de propiedad de particiones con frecuencia y Presentación de problemas de GitHub.

Uso elevado de CPU

Normalmente, se produce un uso elevado de CPU porque una instancia posee demasiadas particiones. No supere tres particiones para cada núcleo de CPU. Comience con 1.5 particiones para cada núcleo de CPU y, a continuación, pruebe aumentando el número de particiones propiedad.

Memoria insuficiente y elección del tamaño del montón

El problema de falta de memoria (OOM) puede producirse si el heap máximo actual de la JVM no es suficiente para ejecutar la aplicación. Puede que quiera medir las necesidades de memoria heap de la aplicación. A continuación, en función del resultado, ajuste el tamaño del montón estableciendo la memoria máxima del montón adecuada mediante la opción JVM -Xmx.

No especifique -Xmx como un valor mayor que la memoria disponible o el límite establecido para el host (la máquina virtual o el contenedor), por ejemplo, la memoria solicitada en la configuración del contenedor. Asigne suficiente memoria para que el equipo host pueda alojar el heap de Java.

En los siguientes pasos se describe una manera típica de medir el valor del montón máximo de Java:

  1. Ejecute la aplicación en un entorno cercano a producción, donde la aplicación envía, recibe y procesa eventos bajo la carga máxima esperada en producción.

  2. Espere a que la aplicación alcance un estado estable. En esta fase, la aplicación y JVM cargan todos los objetos de dominio, los tipos de clase, las instancias estáticas, los grupos de objetos (TCP, grupos de conexiones de base de datos), etc.

    En el estado estable, verá el patrón estable con forma de sierra para la colección del montón, como se muestra en el siguiente recorte de pantalla:

    Recorte de pantalla de la colección de memoria del montón que muestra el patrón de sierra estable.

  3. Una vez que la aplicación alcance el estado estacionario, fuerce una recolección de basura completa (GC) con herramientas como JConsole. Observe la memoria ocupada tras la GC completa. Desea ajustar el tamaño del montón de modo que solo el 30 % esté ocupado después del GC completo. Use este valor para establecer el tamaño máximo del montón (mediante -Xmx).

Si utiliza un contenedor, ajuste su tamaño para disponer de ~1 GB adicional de memoria para las necesidades de memoria no heap de la instancia de la JVM.

El cliente del procesador deja de recibir

El cliente del procesador suele funcionar continuamente en una aplicación host durante días. A veces, observa que EventProcessorClient no está procesando una o varias particiones. Normalmente, no hay suficiente información para determinar por qué se produjo la excepción. La detención de EventProcessorClient es el síntoma de una causa subyacente (es decir, la condición de carrera) que se produjo al intentar recuperarse de un error transitorio. Para obtener la información que necesitamos, consulte Presentación de problemas de GitHub.

EventData duplicado recibido cuando se reinicia el procesador

El servicio EventProcessorClient y Event Hubs garantizan una entrega al menos una vez. Puede agregar metadatos para distinguir eventos duplicados. Para más información, consulte ¿Azure Event Hubs garantiza una entrega al menos una vez? en Stack Overflow. Si necesita una entrega solo una vez, considere Service Bus, que espera una confirmación del cliente. Para obtener una comparación de los servicios de mensajería, consulte Elección entre los servicios de mensajería de Azure.

El cliente de bajo nivel deja de recibir

La biblioteca de Event Hubs proporciona el EventHubConsumerAsyncClient como cliente consumidor de bajo nivel. Está diseñado para usuarios avanzados que necesitan un mayor control y flexibilidad sobre sus aplicaciones reactivas. Este cliente ofrece una interfaz de bajo nivel, lo que te permite gestionar la contrapresión, los hilos y la recuperación dentro de la cadena de Reactor. A diferencia de EventProcessorClient, EventHubConsumerAsyncClient no incluye mecanismos de recuperación automática para todas las causas terminales. Por lo tanto, debe controlar los eventos terminales y seleccionar los operadores de reactor adecuados para implementar estrategias de recuperación.

El EventHubConsumerAsyncClient::receiveFromPartition método emite un error de terminal cuando la conexión encuentra un error que no se puede reintentar o cuando se produce un error consecutivo en una serie de intentos de recuperación de conexión, lo que agota el límite máximo de reintentos. Aunque el receptor de bajo nivel intenta recuperarse de errores transitorios, se espera que los usuarios del cliente de consumidor controle los eventos de terminal. Si se desea la recepción continua de eventos, la aplicación debe ajustar la cadena reactor para crear un nuevo cliente de consumidor en un evento de terminal.

Migración de la biblioteca cliente heredada a la nueva

La guía de migración incluye pasos para migrar desde el cliente heredado y migrar puntos de control heredados.

Pasos siguientes

Si la guía de solución de problemas de este artículo no ayuda a resolver problemas al usar el SDK de Azure para las bibliotecas cliente de Java, presente un problema en el SDK de Azure para el repositorio de Java GitHub.