Apache Kafka: una plataforma distribuida de transmisión de datos

TODOS LOS CONCEPTOS AQUÍ EXPLICADOS ESTÁN REFLEJADOS EN ESTE MONO REPO

Hasta la fecha nunca había tenido la oportunidad de trabajar con ningún sistema de colas y por suerte para mi en Seedtag hacemos un uso intensivo de este tipo de tecnologías.

Para el que no conozca Kafka, es una plataforma para el tratamiento y almacenamiento de datos en tiempo real. Simplificando mucho Kafka es una caja negra donde N productores envían datos para que M consumidores los lean.

Servidores y Clientes

Kafka, que se comporta como un servidor, debe ser ejecutado en un cluster con uno o más servidores, estos pueden estar distribuidos por varios data centers.

Para nuestra prueba vamos a usar Docker Compose y asi simular un entorno bastante parecido a lo que sería un entorno de producción.

A su vez serán necesarios múltiples clientes que serán los encargados de leer y enviar eventos al cluster. En nuestra prueba tendremos un par de microservicios en Node que desempeñarán estas funciones.

Tanto el productor como el consumidor, ambos escritos en Typescript, hacen uso de una libraria llamada node-rdkafka, la cual nos va facilitar mucho la vida de cara a comunicarnos con Kafka.

Productores

Son los clientes que envian eventos a Kafka, un ejemplo básico de productor puede ser el siguiente

const producer = new Kafka.Producer({
 'metadata.broker.list': 'kafka:9092',
})
const topic = 'blog'
const payload = Buffer.from(JSON.stringify(msg), 'utf8')
producer.produce(topic, null, payload, 'kafka-key', Date.now())

Consumidores

Son los clientes que se suscriben a eventos de Kafka, un ejemplo básico de consumidor puede ser el siguiente

const consumer = Kafka.KafkaConsumer.createReadStream(
 {
   'metadata.broker.list': 'kafka:9092',
   'group.id': 'test',
   'socket.keepalive.enable': true,
   'enable.auto.commit': false,
 }, {}, {
   topics: 'blog',
   waitInterval: 0,
   objectMode: false,
 });

 consumer.on('data', (message: Buffer) => {
   const msg: Message = JSON.parse(message.toString())
   console.log(msg)
 });

Eventos

Los eventos son la parte central en torno a la que gira Kafka ya que es la información que fluye por el sistema. Estos eventos están organizados y almacenados por topic, que a su vez están particionados para permitirnos una escalabilidad en el cluster muy alta.

Un topic puede tener un número N productores/consumidores y serán estos los que tendrán que indicar en qué topic escribir/leer.

Caso Real

Para poder asentar un poco toda esta información vamos a construir un par de microservicios que se comunicaran con Kafka para poder ver el flujo de información de un productor a un consumidor.

Pese a que en su propia guia nos recomiendan descargarnos el codigo fuente yo voy a optar por usar una imagen de Docker para después unirlo todo con docker-compose.

Los principales imágenes que vamos a usar serán:

Toda la infra la teneis disponible aquí

Básicamente lo que vamos a levantar con docker-compose va a ser un cluster de Kafka que será atacado por el productor cuando este reciba una petición POST en su API. Cuando Kafka emita un evento el consumidor estará escuchando y lo leerá para mostrarlo por consola.

Vamos a la acción

Primero debemos hacer la builds de las imágenes y levantar nuestro entorno, para ello ejecutar en la terminal dentro de la carpeta del repo:

docker-compose build && docker-compose-up

consumer

Una vez levantado debemos esperar unos segundos a que Kafka esté disponible para recibir eventos, cuando ya esté disponible podremos hacer una petición POST desde la terminal con el siguiente comando:

curl --request POST \
 --url http://localhost:3000/api/messages \
 --header 'Content-Type: application/json' \
 --data '{
 "sender": "producer",
 "receiver": "consumer",
 "message": "KAFKA!"
}'

Instantes después deberiamos ser capaces de ver el mensaje en el lado del consumidor:

consumer