Apache Kafka - V - Consumer Groups

Un solo consumidor, teniendo que recibir y procesar mensajes en un solo thread, puede volverse rápidamente un cuello de botella. Este problema se acrecenta al aumentar la cantidad de topics y particiones. Kafka resuelve esta limitación permitiendo que varios consumidores repartan su carga de manera equitativa fijando el mismo valor en la propiedad group.id al momento de su creación. Haciendo esto, pasan a pertenecer al mismo consumer group.

Cuando un conjunto de consumidores tiene el mismo id de grupo, un broker dentro del cluster es asignado automáticamente como el coordinador del grupo. Su objetivo será monitorear a los consumidores del grupo y llevar cuenta de su pertenencia al mismo. El coordinador del grupo también se comunica con Zookeeper para balancear consumidores y particiones: idealmente, cada consumidor leerá una partición distinta del topic.

Cada consumidor envía periódicamente un heartbeat al cluster, con una frecuencia dada por la opción heartbeat.interval.ms. Si el coordinador no recibió un heartbeat de un consumidor luego de session.timeout.ms, lo considerará muerto, y esto disparará un rebalanceo. En este escenario, eso implica que el coordinador quitará al consumidor muerto del grupo, y asignará sus particiones a otro consumidor activo. El consumidor con su carga incrementada continuará leyendo desde el último offset enviado, o aplicará la política de reinicio que tenga configurada. Si hay una brecha entre la posición actual y el último offset enviado, esto puede causar mensajes duplicados, en el sentido de que fueron procesados por el consumidor muerto, y serán procesados por segunda vez por su sucesor. Que esto sea un problema o no, dependerá de la aplicación. Si lo es, puede que sea necesario enviar offsets manual y sincrónicamente.

Si un nuevo consumidor se une al grupo, o si se agrega una partición al topic, el protocolo de rebalanceo también se ejecutará. En todo caso, siempre buscará tener una relación 1:1 entre consumidores y particiones. Para mayor robustez, algunas aplicaciones usan más consumidores que particiones, para que si mueren consumidores, los que sobran los cubran y puedan mantener el ritmo de consumo hasta que los consumidores caídos se recuperen. Esto funciona porque si hay más consumidores que particiones, los consumidores sobrantes permanecerán inactivos hasta que se los necesite.

Opciones avanzadas para consumidores

Las siguientes opciones serán sólo descritas brevemente; ameritan un estudio más detenido.

  • Rendimiento del consumidor
    • fetch.min.bytes: Mínimo tamaño de lote a leer cuando elapsa el timeout de polling. Esto es análogo al tamaño de lote del productor.
    • max.fetch.wait.ms: Tiempo a esperar por más datos si fetch.min.bytes no se sobrepasa. En un sistema ocupado, este valor no debería entrar en juego.
    • max.partition.fetch.bytes: Para evitar leer más de lo que el bucle de procesamiento puede leer por iteración.
    • max.poll.records: Similar al anterior, pero medido en cantidad de mensajes en lugar de tamaño.

Temas avanzados no cubiertos

  • Control de posición del consumidor: usando el método seek, es posible leer un mensaje específico del topic. Con seekToBeginning, un consumidor puede reiniciar el offset manualmente. También existe seekToEnd para leer el mensaje más reciente directamente.
  • Control de flujo: esto permite pausar y reanudar el consumo de topics y particiones, si los consumidores deciden dinámicamente concentrarse en topics específicos por un tiempo, pausando otros temporalmente. Los métodos de la API son, esperablemente:
    • pause
    • resume
  • Rebalance listeners: Permiten a un consumidor ser notificado cuando ocurre un rebalanceo, para que puedan ajustar su comportamiento de ser necesario.
  • Kafka Schema Registry (de Confluent): Esto es lo suficientemente complejo para su propia serie de posts, pero la motivación para agregar esto a Kafka es para manejar los contratos de formato de datos entre productores y consumidores. Ello se logra definiendo esquemas de datos, con gestión de versionado incluido.
  • Kafka Connect (de Confluent): Otra extensión de Kafka cuyo objetivo es simplificar la integración con fuentes de datos usuales: bases de datos relacionales, Hadoop, archivos, y más. Estos "conectores" enlatados ahorran el esfuerzo de escribir productores y consumidores para dichas fuentes de datos una y otra vez.
  • Kafka Streams: Utiliza la infraestructura de Kafka para implementar procesamiento de streams en tiempo real. Es ideal para escenarios de tipo big data.

Comments

Popular posts from this blog

VB.NET: Raise base class events from a derived class

Apache Kafka - I - High level architecture and concepts

C++/CLI: Convert a String to BSTR or some other nasty stuff