En el diseño de sistemas modernos, la Arquitectura Orientada a Eventos (EDA, por sus siglas en inglés) se centra en crear, detectar, utilizar y responder a eventos dentro de un sistema. Los eventos son sucesos significativos que pueden afectar al hardware o software de un sistema, como acciones de usuario, cambios de estado o actualizaciones de datos.
EDA permite que diferentes partes de una aplicación interactúen de forma desacoplada, permitiéndoles comunicarse a través de eventos en lugar de llamadas directas. Esta configuración permite que los componentes trabajen de forma independiente, respondan a eventos de manera asíncrona y se adapten a las necesidades comerciales cambiantes sin necesidad de reconfiguración del sistema, promoviendo la agilidad.
Las nuevas y modernas aplicaciones ahora dependen en gran medida del procesamiento de datos en tiempo real y la capacidad de respuesta. La importancia de la EDA no puede ser subestimada porque proporciona el marco que respalda esos requisitos. Al utilizar comunicación asíncrona e interacciones orientadas a eventos, los sistemas pueden manejar eficientemente altos volúmenes de transacciones y mantener el rendimiento bajo cargas inestables. Estas características son especialmente apreciadas en entornos donde los cambios son muy espontáneos, como plataformas de comercio electrónico o aplicaciones de IoT.
Algunos componentes clave de la EDA incluyen:
-
Fuentes de Eventos: Estos son los productores que generan eventos cuando ocurren acciones significativas dentro del sistema. Ejemplos incluyen interacciones de usuario o cambios de datos.
-
Escuchas: Estas son entidades que se suscriben a eventos específicos y responden cuando esos eventos ocurren. Las escuchas permiten que el sistema reaccione dinámicamente a los cambios.
-
Manejadores: Estos son responsables de procesar los eventos una vez que son detectados por las escuchas, ejecutando la lógica de negocio necesaria o flujos de trabajo desencadenados por el evento.
En este artículo, aprenderás cómo implementar el procesamiento de datos basado en eventos utilizando Traefik, Kafka y Docker.
Aquí tienes una aplicación simple alojada en GitHub que puedes ejecutar rápidamente para tener una visión general de lo que construirás hoy.
Tabla de Contenidos
Aquí está lo que cubriremos:
¡Comencemos!
Requisitos previos
Antes de comenzar:
-
Despliega una instancia de Ubuntu 24.04 con al menos 4 GB de RAM y un mínimo de 20 GB de espacio libre en disco para alojar imágenes de Docker, contenedores y datos de Kafka.
-
Accede a la instancia con un usuario no root que tenga privilegios de sudo.
-
Actualiza el índice de paquetes.
sudo apt update
Comprendiendo las Tecnologías
Apache Kafka
Apache Kafka es una plataforma de transmisión de eventos distribuida, diseñada para pipelines de datos de alto rendimiento y aplicaciones de transmisión en tiempo real. Actúa como la columna vertebral para implementar EDA al gestionar eficazmente grandes volúmenes de eventos. Kafka utiliza un modelo de publicación-suscripción donde los productores envían eventos a temas, y los consumidores se suscriben a estos temas para recibir los eventos.
Algunas de las características clave de Kafka incluyen:
-
Alto Rendimiento: Kafka es capaz de manejar millones de eventos por segundo con baja latencia, lo que lo hace adecuado para aplicaciones de alto volumen.
-
Tolerancia a fallos: La arquitectura distribuida de Kafka garantiza la durabilidad y disponibilidad de datos incluso ante fallos de servidores. Replica datos en varios brokers dentro de un clúster.
-
Escalabilidad: Kafka puede escalar horizontalmente fácilmente agregando más brokers al clúster o particiones a los temas, satisfaciendo las crecientes necesidades de datos sin una reconfiguración significativa.
Traefik
Traefik es un moderno proxy inverso HTTP y balanceador de carga diseñado específicamente para arquitecturas de microservicios. Descubre automáticamente los servicios que se ejecutan en tu infraestructura y dirige el tráfico en consecuencia. Traefik simplifica la gestión de microservicios al proporcionar capacidades de enrutamiento dinámico basadas en metadatos del servicio.
Algunas de las características clave de Traefik incluyen:
-
Configuración dinámica: Traefik actualiza automáticamente su configuración de enrutamiento a medida que se agregan o eliminan servicios, eliminando la intervención manual.
-
Balanceo de Carga: Distribuye de manera eficiente las solicitudes entrantes entre múltiples instancias de servicio, mejorando el rendimiento y la fiabilidad.
-
Tablero Integrado: Traefik proporciona un tablero fácil de usar para monitorear el tráfico y la salud del servicio en tiempo real.
Al utilizar Kafka y Traefik en una arquitectura impulsada por eventos, puedes construir sistemas receptivos que manejan de manera eficiente el procesamiento de datos en tiempo real mientras mantienen alta disponibilidad y escalabilidad.
Cómo Configurar el Entorno
Cómo Instalar Docker en Ubuntu 24.04
- Instala los paquetes requeridos.
sudo apt install ca-certificates curl gnupg lsb-release
- Agrega la clave GPG oficial de Docker.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
- Agrega el repositorio de Docker a tus fuentes de APT.
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
- Actualiza el índice de paquetes nuevamente e instala Docker Engine con el complemento Docker Compose.
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
- Verifica la instalación.
sudo docker run hello-world
Salida Esperada:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:305243c734571da2d100c8c8b3c3167a098cab6049c9a5b066b6021a60fcb966
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
Cómo Configurar Docker Compose
Docker Compose simplifica la gestión de aplicaciones de múltiples contenedores, permitiéndote definir y ejecutar servicios en un solo archivo.
- Crea un directorio de proyecto
mkdir ~/kafka-traefik-setup && cd ~/kafka-traefik-setup
- Crea un archivo
docker-compose.yml
.
nano docker-compose.yml
- Agrega la siguiente configuración al archivo para definir tus servicios.
version: '3.8'
services:
kafka:
image: wurstmeister/kafka:latest
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9092,OUTSIDE://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
KAFKA_LISTENERS: INSIDE://0.0.0.0:9092,OUTSIDE://0.0.0.0:9092
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
zookeeper:
image: wurstmeister/zookeeper:latest
ports:
- "2181:2181"
traefik:
image: traefik:v2.9
ports:
- "80:80" # Tráfico HTTP
- "8080:8080" # Panel de control de Traefik (no seguro)
command:
- "--api.insecure=true"
- "--providers.docker=true"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
Guarda tus cambios con ctrl + o
, luego sal con ctrl + x
.
- Inicia tus servicios.
docker compose up -d
Salida esperada:
[+] Running 4/4
✔ Network kafka-traefik-setup_default Created 0.2s
✔ Container kafka-traefik-setup-zookeeper-1 Started 1.9s
✔ Container kafka-traefik-setup-traefik-1 Started 1.9s
✔ Container kafka-traefik-setup-kafka-1 Started 1.9s
Cómo construir el sistema de eventos impulsado
Cómo crear productores de eventos
Para producir eventos en Kafka, necesitarás implementar un productor de Kafka. A continuación se muestra un ejemplo usando Java.
- Crea un archivo
kafka-productor.java
.
nano kafka-producer.java
- Agrega la siguiente configuración para un Productor de Kafka.
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import java.util.Properties;
public class SimpleProducer {
public static void main(String[] args) {
// Configurar las propiedades del productor
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// Crear el productor
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
try {
// Enviar un mensaje al tema "mi-tema"
ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key1", "Hello, Kafka!");
RecordMetadata metadata = producer.send(record).get(); // Envío síncrono
System.out.printf("Sent message with key %s to partition %d with offset %d%n",
record.key(), metadata.partition(), metadata.offset());
} catch (Exception e) {
e.printStackTrace();
} finally {
// Cerrar el productor
producer.close();
}
}
}
Guarda tus cambios con ctrl + o
, luego sal con ctrl + x
.
En la configuración anterior, el productor envía un mensaje con la clave “key1” y el valor “¡Hola, Kafka!” al tema “mi-tema”.
Cómo configurar temas de Kafka
Antes de producir o consumir mensajes, necesitas crear temas en Kafka.
- Utilice el script
kafka-topics.sh
incluido en su instalación de Kafka para crear un tema.
kafka-topics.sh --bootstrap-server localhost:9092 --create --topic <TopicName> --partitions <NumberOfPartitions> --replication-factor <ReplicationFactor>
Por ejemplo, si desea crear un tema llamado my-topic
con 3 particiones y un factor de replicación de 1, ejecute:
docker exec <Kafka Container ID> /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my-topic --partitions 3 --replication-factor 1
Salida Esperada:
Created topic my-topic.
- Verifique para confirmar si el tema se creó con éxito.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list
Salida Esperada:
my-topic
Cómo Crear Consumidores de Eventos
Después de haber creado sus productores y temas, puede crear consumidores para leer mensajes de esos temas.
- Cree un archivo
kafka-consumer.java
.
nano kafka-consumer.java
- Agregue la siguiente configuración para un consumidor de Kafka.
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import java.time.Duration;
import java.util.Collections;
import java.util.Properties;
public class SimpleConsumer {
public static void main(String[] args) {
// Configurar las propiedades del consumidor
Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "my-group");
props.put(ConsumerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
// Crear el consumidor
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
// Suscribirse al tema
consumer.subscribe(Collections.singletonList("my-topic"));
try {
while (true) {
// Consultar nuevos registros
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("Consumed message with key %s and value %s from partition %d at offset %d%n",
record.key(), record.value(), record.partition(), record.offset());
}
}
} finally {
// Cerrar el consumidor
consumer.close();
}
}
}
Guarde los cambios con ctrl + o
, luego salga con ctrl + x
.
En la configuración anterior, el consumidor se suscribe a my-topic
y consulta continuamente nuevos mensajes. Cuando se reciben mensajes, imprime sus claves y valores junto con la información de partición y desplazamiento.
Cómo Integrar Traefik con Kafka
Configura Traefik como un Proxy Inverso.
Integrar Traefik como un proxy inverso para Kafka te permite gestionar el tráfico entrante de manera eficiente mientras proporciona características como el enrutamiento dinámico y la terminación SSL.
- Actualiza el archivo
docker-compose.yml
.
version: '3.8'
services:
kafka:
image: wurstmeister/kafka:latest
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9092,OUTSIDE://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
KAFKA_LISTENERS: INSIDE://0.0.0.0:9092,OUTSIDE://0.0.0.0:9092
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
labels:
- "traefik.enable=true"
- "traefik.http.routers.kafka.rule=Host(`kafka.example.com`)"
- "traefik.http.services.kafka.loadbalancer.server.port=9092"
zookeeper:
image: wurstmeister/zookeeper:latest
ports:
- "2181:2181"
traefik:
image: traefik:v2.9
ports:
- "80:80" # Tráfico HTTP
- "8080:8080" # Dashboard de Traefik (inseguro)
command:
- "--api.insecure=true"
- "--providers.docker=true"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
En esta configuración, reemplaza kafka.example.com
con tu nombre de dominio real. Las etiquetas definen las reglas de enrutamiento que Traefik utilizará para dirigir el tráfico al servicio Kafka.
- Reinicia tus servicios.
docker compose up -d
-
Accede a tu dashboard de Traefik ingresando a
http://localhost:8080
en tu navegador web.Balanceo de Carga con Traefik
Traefik proporciona capacidades de balanceo de carga integradas que pueden ayudar a distribuir solicitudes entre múltiples instancias de tus productores y consumidores de Kafka.
Estrategias para el Balanceo de Carga en Microservicios Basados en Eventos
- Round Robin:
Por defecto, Traefik utiliza una estrategia de round-robin para distribuir las solicitudes entrantes de manera uniforme entre todas las instancias disponibles de un servicio. Esto es efectivo para equilibrar la carga cuando se están ejecutando múltiples instancias de productores o consumidores de Kafka.
- Sesiones Pegajosas:
Si necesitas que las solicitudes de un cliente específico siempre vayan a la misma instancia (por ejemplo, para mantener el estado de la sesión), puedes configurar sesiones pegajosas en Traefik utilizando cookies o encabezados.
- Verificaciones de Salud:
Configura verificaciones de salud en Traefik para asegurarte de que el tráfico solo se dirija a instancias saludables de tus servicios de Kafka. Puedes hacer esto agregando parámetros de verificación de salud en las definiciones de servicio dentro de tu archivo docker-compose.yml
:
labels:
- "traefik.http.services.kafka.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.kafka.loadbalancer.healthcheck.interval=10s"
- "traefik.http.services.kafka.loadbalancer.healthcheck.timeout=3s"
Probando la Configuración
Verificando la Producción y Consumo de Eventos
- Kafka proporciona herramientas de línea de comandos integradas para pruebas. Inicia un productor de consola.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic my-topic
Después de ejecutar este comando, puedes escribir mensajes en la terminal, que serán enviados al tema de Kafka especificado.
- Inicie otra sesión de terminal y comience un consumidor de consola.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my-topic --from-beginning
Este comando mostrará todos los mensajes en my-topic
, incluidos aquellos producidos antes de que el consumidor comenzara.
- Para ver qué tan bien sus consumidores están manteniéndose al día con los productores, puede ejecutar el siguiente comando para verificar el retraso de un grupo de consumidores específico.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <your-consumer-group>
Monitoreo y Registro
- Métricas de Kafka:
Kafka expone numerosas métricas que se pueden monitorear utilizando JMX (Java Management Extensions). Puede configurar JMX para exportar estas métricas a sistemas de monitoreo como Prometheus o Grafana. Las métricas clave a monitorear incluyen:
-
Rendimiento de Mensajes: La tasa de mensajes producidos y consumidos.
-
Retraso del Consumidor: La diferencia entre el desplazamiento del último mensaje producido y el desplazamiento del último mensaje consumido.
-
Salud del Broker: Métricas relacionadas con el rendimiento del broker, como tasas de solicitud y tasas de error.
- Integración de Prometheus y Grafana:
Para visualizar las métricas de Kafka, puede configurar Prometheus para recoger métricas de sus brokers de Kafka. Siga estos pasos:
-
Habilita el Exportador JMX en tus brokers de Kafka añadiéndolo como un agente de Java en la configuración de tu broker.
-
Configura Prometheus añadiendo un trabajo de scrapeo en su archivo de configuración (
prometheus.yml
) que apunte a tu punto final del Exportador JMX. -
Usa Grafana para crear paneles que visualicen estas métricas en tiempo real.
Cómo implementar la supervisión para Traefik
- Punto final de métricas de Traefik.
Traefik proporciona soporte incorporado para exportar métricas a través de Prometheus. Para habilitar esta función, añade la siguiente configuración en la definición de servicio de Traefik dentro de docker-compose.yml
:
command:
- "--metrics.prometheus=true"
- "--metrics.prometheus.addservice=true"
- Visualizando métricas de Traefik con Grafana.
Una vez que Prometheus esté scrapeando las métricas de Traefik, puedes visualizarlas usando Grafana:
-
Crea un nuevo panel en Grafana y añade paneles que muestren métricas clave de Traefik como:
-
traefik_entrypoint_requests_total: Número total de solicitudes recibidas.
-
traefik_backend_request_duration_seconds: Tiempos de respuesta de los servicios de backend.
-
traefik_service_requests_total: Total de solicitudes reenviadas a los servicios de backend.
- Configuración de Alertas.
Configura alertas en Prometheus o Grafana basadas en umbrales específicos (por ejemplo, alto retraso del consumidor o aumento de tasas de error).
Conclusión
En esta guía, implementaste con éxito la Arquitectura Orientada a Eventos (EDA) utilizando Kafka y Traefik dentro del entorno de Ubuntu 24.04.
Recursos Adicionales
Para aprender más, puedes visitar:
Source:
https://www.freecodecamp.org/news/how-to-implement-event-driven-data-processing/