Mejores prácticas para escalar cargas de trabajo basadas en Kafka

Apache Kafka es conocido por su capacidad para procesar una gran cantidad de eventos en tiempo real. Sin embargo, para manejar millones de eventos, necesitamos seguir ciertas mejores prácticas al implementar tanto los servicios de productor de Kafka como los servicios de consumidor.

Antes de comenzara utilizar Kafka en tus proyectos, entendamos cuándo usar Kafka:

  • Flujos de eventos de alto volumen. Cuando tu aplicación/servicio genera un flujo continuo de eventos como eventos de actividad de usuario, eventos de clic en el sitio web, eventos de datos de sensores, eventos de registro o actualizaciones del mercado de valores, la capacidad de Kafka para manejar grandes volúmenes con baja latencia es muy útil.
  • Analítica en tiempo real. Kafka es especialmente muy útil para construir pipelines de procesamiento de datos en tiempo real, donde los datos necesitan ser procesados tan pronto como llegan. Te permite transmitir datos a motores de análisis como Kafka Streams, Apache Spark o Flink para análisis/información inmediata y procesamiento por lotes o en tiempo real.
  • Desacoplamiento de aplicaciones. Al actuar como un hub central de mensajes, puede desacoplar diferentes partes de una aplicación, permitiendo el desarrollo y escalado independiente de servicios y fomentando el principio de segregación responsable.
  • Integración de datos entre sistemasCuando se integran sistemas distribuidos, Kafka puede transferir eficientemente datos entre diferentes aplicaciones de equipos/proyectos, actuando como un broker de datos confiable.

Diferencias clave respecto a otros sistemas de encolado 

A continuación se presentan las diferencias de Apache Kafka con sistemas como ActiveMQ, ZeroMQ y VerneMQ:

Almacenamiento persistente

Kafka almacena eventos en un registro distribuido, lo que permite la capacidad de reproducir datos en cualquier momento y la persistencia de datos incluso en caso de fallos del sistema/nodo, a diferencia de algunas colas de mensajes tradicionales, que pueden depender de un almacenamiento en memoria como Redis.

Particionamiento

Los datos se dividen en particiones entre brokers y temas, lo que permite el procesamiento paralelo de grandes flujos de datos y un alto rendimiento. Esto ayuda a los hilos consumidores a conectarse a una partición individual, promoviendo la escalabilidad horizontal.

Grupos de consumidores

Varios consumidores pueden suscribirse al mismo tema y leer desde diferentes posiciones dentro de una partición, permitiendo patrones de consumo duplicados para que diferentes equipos consuman y procesen los mismos datos para diferentes propósitos. Algunos ejemplos son:

  • Actividad de usuario consumida por equipos de aprendizaje automático para detectar actividad sospechosa
  • Equipo de recomendaciones para construir recomendaciones
  • Equipo de anuncios para generar anuncios relevantes

Mejores prácticas del productor de Kafka

Tamaño de lote y tiempo de espera

Al configurar batch.size y linger.ms, puedes aumentar el rendimiento de tu productor de Kafka. batch.size es el tamaño máximo del lote en bytes. Kafka intentará agruparlo antes de enviarlo a los productores. 

Linger.ms determina el tiempo máximo en milisegundos que el productor esperará para que se agreguen mensajes adicionales al lote para su procesamiento. 

Configurar los ajustes de tamaño de lote y linger.ms ayuda significativamente al rendimiento del sistema al controlar cuántos datos se acumulan antes de enviarlos a los sistemas de procesamiento, lo que permite un mejor rendimiento y latencias reducidas al tratar con grandes volúmenes de datos. También puede introducir ligeros retrasos dependiendo de los valores elegidos. Especialmente, un gran tamaño de lote con un correcto linger.ms puede optimizar la eficiencia de la transferencia de datos.

Compresión

Otra forma de aumentar el rendimiento es habilitar la compresión a través de la configuración compression.type. El productor puede comprimir datos con gzip, snappy o lz4 antes de enviarlos a los brokers. Para grandes volúmenes de datos, esta configuración ayuda a reducir la sobrecarga de compresión con la eficiencia de la red. También ahorra ancho de banda y aumenta el rendimiento del sistema. Además, al establecer el serializador y el serializador de claves apropiados, podemos asegurar que los datos se serialicen en un formato compatible con sus consumidores.

Reintentos e Idempotencia

Para asegurar la fiabilidad del productor de Kafka, debe habilitar reintentos e idempotencia. Al configurar retries, el productor puede reenviar automáticamente cualquier lote de datos que no reciba ack del broker dentro de un número especificado de intentos.

Agradecimientos

Esta configuración controla el nivel de reconocimiento requerido del broker antes de considerar un mensaje enviado con éxito. Al elegir el nivel de acks correcto, puede controlar la fiabilidad de su aplicación. A continuación se presentan los valores aceptados para esta configuración.

  • – el más rápido, pero sin garantía de entrega del mensaje.
  • 1 – el mensaje se reconoce una vez que se escribe en el broker líder, proporcionando una fiabilidad básica.
  • all – el mensaje se considera entregado solo cuando todas las réplicas lo han reconocido, asegurando alta durabilidad.

Ajuste de Configuración Basado en la Carga de Trabajo

deberías comenzar a rastrear métricas como la tasa de envío de mensajes, el tamaño del lote y las tasas de error para identificar cuellos de botella en el rendimiento. Revisa y ajusta regularmente la configuración del productor según las modificaciones o actualizaciones de características/datos.

Mejores Prácticas del Consumidor de Kafka

Grupos de Consumidores

Cada consumidor de Kafka debería pertenecer a un grupo de consumidores; un grupo de consumidores puede contener uno o más consumidores. Al crear más consumidores en el grupo, puedes escalar para leer de todas las particiones, lo que te permite procesar un enorme volumen de datos. La configuración group.id ayuda a identificar el grupo de consumidores al que pertenece el consumidor, permitiendo el balanceo de carga entre múltiples consumidores que consumen del mismo tema. La mejor práctica es usar IDs de grupo significativos para identificar fácilmente los grupos de consumidores dentro de tu aplicación.

Confirmación de Desplazamiento

Puedes controlar cuándo tu aplicación confirma los desplazamientos, lo que puede ayudar a evitar la pérdida de datos. Hay dos formas de confirmar los desplazamientos: automática y manual. Para aplicaciones de alto rendimiento, deberías considerar la confirmación manual para un mejor control.

  • auto.offset.reset – define qué hacer cuando un consumidor comienza a consumir un tema sin desplazamientos comprometidos (por ejemplo, un tema nuevo o un consumidor que se une a un grupo por primera vez). Las opciones incluyen earliest (leer desde el principio), latest (leer desde el final) o none (lanzar un error). Elija “earliest” para la mayoría de los casos de uso para evitar perder datos cuando un nuevo consumidor se une a un grupo.Controla cómo un consumidor comienza a consumir datos, asegurando un comportamiento adecuado cuando se reinicia un consumidor o se agrega a un grupo.
  • enable.auto.commit – ayuda a configurar para comprometer automáticamente desplazamientos periódicamente. Generalmente, establecemos el valor en false para la mayoría de los escenarios de producción donde no necesitamos una alta fiabilidad y comprometemos manualmente los desplazamientos dentro de la lógica de su aplicación para garantizar un procesamiento exactamente una vez.Proporciona control para gestionar compromisos de desplazamiento, permitiendo un mayor control sobre el procesamiento de datos.
  • auto.commit.interval.ms Intervalo en milisegundos en el que se confirman automáticamente los desplazamientos si enable.auto.commit está configurado como true. Modifique basado en el tiempo de procesamiento de su aplicación para evitar la pérdida de datos debido a fallas inesperadas.

Tamaño de búsqueda y Máximo de Registros de Consulta

Esta configuración ayuda a controlar la cantidad de registros recuperados en cada solicitud, configure fetch.min.bytes y max.poll.records. Aumentar este valor puede ayudar a mejorar el rendimiento de sus aplicaciones mientras se reduce el uso de la CPU y se disminuye la cantidad de llamadas realizadas a los brokers.

  • fetch.min.bytes – la cantidad mínima de bytes a recuperar de un broker en una sola solicitud de consulta. Establezca un valor bajo para evitar llamadas de red innecesarias, pero no demasiado bajo para evitar consultas excesivas. Ayuda a optimizar la eficiencia de la red al evitar solicitudes pequeñas y frecuentes.
  • fetch.max.bytes  el máximo número de bytes a recuperar de un broker en una sola solicitud de sondeo. Ajusta según la memoria disponible para evitar sobrecargar los trabajadores consumidores. Esto reduce la cantidad de datos recuperados en un solo sondeo, evitando problemas de memoria.
  • max.poll.interval.ms – el tiempo máximo para esperar a que una solicitud de sondeo devuelva datos antes de que se agote el tiempo. Establece un buen tiempo de espera para evitar bloqueos/retrasos en el consumidor si los datos no están disponibles. Esto ayuda a prevenir que los consumidores se queden atascados esperando mensajes durante demasiado tiempo. (A veces, los pods de k8s pueden reiniciarse si las comprobaciones de vivacidad se ven afectadas).

Asignación de Particiones

Esta es la estrategia utilizada para asignar particiones (partition.assignment.strategy) a los consumidores dentro de un grupo (por ejemplo, range, roundrobin). Usa range para la mayoría de los escenarios para distribuir uniformemente las particiones entre los consumidores. Esto permite una distribución de carga equilibrada entre los consumidores en un grupo.

Aquí hay algunas consideraciones importantes antes de usar Kafka:

  • ComplejidadImplementar Kafka requiere un entendimiento más profundo de conceptos de sistemas distribuidos como la partición y gestión de desplazamiento debido a sus características avanzadas y configuraciones.
  • Monitoreo y gestión. Implementar el monitoreo y la gestión del clúster de Kafka es importante para garantizar alta disponibilidad y rendimiento.
  • SeguridadImplementar prácticas de seguridad sólidas para proteger los datos sensibles que fluyen a través de los temas de Kafka también es importante.

Implementar estas mejores prácticas puede ayudarte a escalar tus aplicaciones basadas en Kafka para manejar millones/miles de millones de eventos. Sin embargo, es importante recordar que la configuración óptima puede variar según los requisitos específicos de tu aplicación.

Source:
https://dzone.com/articles/best-practices-for-scaling-kafka-based-workloads