Apache Kafka es una plataforma de streaming de eventos de alto rendimiento y altamente escalable. Para desbloquear todo el potencial de Kafka, es necesario considerar cuidadosamente el diseño de la aplicación. Es muy fácil escribir aplicaciones Kafka que funcionen mal o que finalmente se topen con un muro de escalabilidad. Desde 2015, IBM ha proporcionado el servicio IBM Event Streams, que es un servicio Apache Kafka totalmente gestionado que se ejecuta en IBM Cloud. Desde entonces, el servicio ha ayudado a muchos clientes, así como a equipos dentro de IBM, a resolver problemas de escalabilidad y rendimiento con las aplicaciones Kafka que han escrito.
Este artículo describe algunos de los problemas comunes de Apache Kafka y ofrece algunas recomendaciones sobre cómo evitar problemas de escalabilidad en sus aplicaciones.
Ciertas operaciones de Kafka funcionan porque el cliente envía datos al broker y espera una respuesta. Un viaje de ida y vuelta completo puede tardar 10 milisegundos, lo que suena rápido, pero lo limita a un máximo de 100 operaciones por segundo. Por este motivo, se recomienda que intente evitar este tipo de operaciones siempre que sea posible. Afortunadamente, los clientes de Kafka le brindan formas de evitar esperar en estos tiempos de ida y vuelta. Solo necesita asegurarse de que los está aprovechando.
Consejos para maximizar el rendimiento:
Si leyó lo anterior y pensó: "¿eso no hará que mi aplicación sea más compleja?", la respuesta es sí, probablemente eso pasará. Existe una compensación entre el rendimiento y la complejidad de las aplicaciones. Lo que hace que el tiempo de ida y vuelta de la red sea un obstáculo particularmente insidioso es que una vez que alcanza este límite, puede requerir cambios extensos en las aplicaciones para lograr mejoras adicionales en el rendimiento.
Una característica útil de Kafka es que monitorea la "actividad" de las aplicaciones que consumen y desconecta cualquiera que pueda haber fallado. Esto funciona haciendo que el broker realice un seguimiento de la última vez que cada cliente consumidor llamó a un "sondeo" (terminología de Kafka para pedir más mensajes). Si un cliente no realiza un sondeo con suficiente frecuencia, el broker al que está conectado concluye que debe fallar y lo desconecta. Esto está diseñado para permitir que los clientes que no están experimentando problemas intervengan y retomen el trabajo del cliente fallido.
Desafortunadamente, con este esquema, el agente de Kafka no puede distinguir entre un cliente que tarda mucho tiempo en procesar los mensajes que recibió y un cliente que realmente falló. Considere una aplicación de consumo que realiza un bucle: 1) llama a un sondeo y obtiene un lote de mensajes; o 2) procesa cada mensaje del lote, tardando 1 segundo en procesar cada mensaje.
Si este consumidor recibe lotes de 10 mensajes, pasarán aproximadamente 10 segundos entre llamadas y sondeos. De forma predeterminada, Kafka permitirá hasta 300 segundos (5 minutos) entre encuestas antes de desconectar el cliente, por lo que todo funcionaría bien en este escenario. Pero, ¿qué sucede en un día realmente ocupado cuando comienzan a acumularse mensajes sobre el tema del que consume la aplicación? En lugar de solo recibir 10 mensajes de cada llamada de sondeo, su aplicación recibe 500 mensajes (de forma predeterminada, este es el número máximo de registros que puede devolver una llamada a sondeo). Eso daría como resultado suficiente tiempo de procesamiento para que Kafka decida que la instancia de la aplicación ha fallado y la desconecte. Esto es una mala noticia.
Le encantará saber que esto puede empeorar. Es posible que ocurra una especie de bucle de feedback. A medida que Kafka comienza a desconectar a los clientes porque no llaman al sondeo con la frecuencia suficiente, hay menos instancias de la aplicación para procesar mensajes. La probabilidad de que haya una gran acumulación de mensajes sobre el tema aumenta, lo que incrementa la probabilidad de que más clientes reciban grandes lotes de mensajes y tarden demasiado en procesarlos. Eventualmente, todas las instancias de la aplicación consumidora entran en un bucle de reinicio y no se realiza ningún trabajo útil.
¿Qué medida puede tomar para evitar que esto ocurra?
Volveremos al tema de las fallas de los consumidores más adelante en este artículo, cuando veamos cómo pueden desencadenar el reequilibrio del grupo de consumidores y el efecto disruptivo que esto puede tener.
Tras bambalinas, el protocolo utilizado por el consumidor de Kafka para recibir mensajes funciona enviando una solicitud de “obtención” a un broker de Kafka. Como parte de esta solicitud, el cliente indica qué debe hacer el broker si no hay ningún mensaje para devolver, incluido cuánto tiempo debe esperar el broker antes de enviar una respuesta vacía. De forma predeterminada, los consumidores de Kafka indican a los agentes que esperen hasta 500 milisegundos (controlados por la configuración del consumidor “fetch.max.wait.ms”) para que al menos 1 byte de datos del mensaje esté disponible (controlado con la configuración “fetch.min.bytes”) .
Esperar 500 milisegundos no parece descabellado, pero si su aplicación tiene consumidores que están mayormente inactivos y se escala a, digamos, 5000 instancias, eso supone potencialmente 2500 solicitudes por segundo que no hacen absolutamente nada. Cada una de estas solicitudes requiere tiempo de CPU en el broker para procesarse y, en el extremo, puede afectar el rendimiento y la estabilidad de los clientes de Kafka que desean hacer un trabajo útil.
Normalmente, el enfoque de Kafka para escalar es agregar más agentes y luego reequilibrar uniformemente las particiones de temas en todos los agentes, tanto antiguos como nuevos. Desafortunadamente, este enfoque podría no ser útil si sus clientes están bombardeando Kafka con solicitudes de recuperación innecesarias. Cada cliente enviará solicitudes de obtención a cada agente que lidere una partición temática de la que el cliente está consumiendo mensajes. Así que es posible que, incluso luego de escalar el clúster Kafka y redistribuir particiones, la mayoría de sus clientes estén enviando peticiones de obtención a la mayoría de los brokers.
Entonces, ¿qué puede hacer?
Si llega a Kafka con experiencia en otros sistemas de publicación y suscripción (por ejemplo, Message Queuing Telemetry Transport, o MQTT para abreviar), entonces puede esperar que los temas de Kafka sean muy ligeros, casi efímeros. Pero no lo son. Kafka se siente mucho más cómodo con una serie de temas que se miden en miles. También se espera que los temas de Kafka sean relativamente duraderos. Prácticas como crear un tema para recibir un único mensaje de respuesta y luego eliminar el tema son poco comunes con Kafka y no aprovechan las fortalezas de Kafka.
En su lugar, planifica temas que tengan una larga vigencia. Quizás compartan la vida útil de una aplicación o una actividad. También trate de limitar el número de temas a cientos o quizás miles. Esto podría requerir adoptar una perspectiva diferente sobre qué mensajes se intercalan sobre un tema en particular.
Una pregunta relacionada que surge a menudo es: "¿Cuántas particiones debe tener mi tema?". Tradicionalmente, se recomienda sobreestimar, ya que agregar particiones después de crear un tema no cambia la partición de los datos existentes almacenados en el tema (y, por lo tanto, puede afectar a los consumidores que dependen de la partición para ofrecer el orden de los mensajes dentro de una partición). Este es un buen consejo; sin embargo, nos gustaría sugerir algunas consideraciones adicionales:
La mayoría de las aplicaciones de Kafka que consumen mensajes usan las capacidades del grupo de consumidores de Kafka para coordinar qué clientes consumen de qué particiones de tema. Si su recuerdo de los grupos de consumidores es un poco confuso, aquí hay un repaso rápido de los puntos clave:
A medida que Kafka ha madurado, se han ideado algoritmos de reequilibrio cada vez más sofisticados, y seguirá ocurriendo. En las primeras versiones de Kafka, cuando un grupo de consumidores se reequilibraba, todos los clientes del grupo tenían que dejar de consumir, las particiones de tema se redistribuían entre los nuevos miembros del grupo y todos los clientes comenzaban a consumir de nuevo. Este enfoque tiene dos inconvenientes (no se preocupe, estos se han mejorado desde entonces):
Los algoritmos de reequilibrio más recientes han realizado mejoras significativas, para usar la terminología de Kafka, agregando "adherencia" y "cooperación":
A pesar de estas mejoras en los algoritmos de reequilibrio más recientes, si sus aplicaciones están sujetas con frecuencia a reequilibrios de grupos de consumidores, seguirá viendo un impacto en el rendimiento general de la mensajería y desperdiciando ancho de banda de red a medida que los clientes descartan y recuperan datos de mensajes almacenados en búfer. Estas son algunas sugerencias sobre lo que puede hacer:
Boletín de la industria
Manténgase al día sobre las tendencias más importantes e intrigantes de la industria sobre IA, automatización, datos y más con el boletín Think. Consulte la Declaración de privacidad de IBM.
Su suscripción se entregará en inglés. En cada boletín, encontrará un enlace para darse de baja. Puede gestionar sus suscripciones o darse de baja aquí. Consulte nuestra Declaración de privacidad de IBM para obtener más información.
Ahora ya es un experto en escalar aplicaciones Kafka. Le invitamos a poner en práctica estos puntos y probar la oferta de Kafka totalmente gestionada en IBM Cloud. Si tiene algún problema con la configuración, consulte la Guía de inicio y las preguntas frecuentes.
IBM® Event Streams es un software de transmisión de eventos construido sobre Apache Kafka de código abierto. Está disponible como servicio totalmente gestionado en IBM® Cloud o para autohospedaje.
Desbloquee el potencial empresarial con las soluciones de integración de IBM, y conecte aplicaciones y sistemas para acceder a datos críticos de forma rápida y segura.
Desbloquee nuevas capacidades e impulse la agilidad empresarial con los servicios de asesoramiento en la nube de IBM.