No design de sistemas modernos, Arquitetura Orientada a Eventos (EDA) foca na criação, detecção, uso e resposta a eventos dentro de um sistema. Eventos são ocorrências significativas que podem afetar o hardware ou software de um sistema, como ações do usuário, mudanças de estado ou atualizações de dados.

A EDA permite que diferentes partes de uma aplicação interajam de forma desacoplada, permitindo que se comuniquem através de eventos em vez de chamadas diretas. Essa configuração permite que os componentes trabalhem de forma independente, respondam a eventos de forma assíncrona e se ajustem às necessidades de negócios em mudança sem uma reconfiguração significativa do sistema, promovendo agilidade.

Aplicações novas e modernas agora dependem fortemente do processamento de dados em tempo real e da capacidade de resposta. A importância da EDA não pode ser subestimada, pois fornece a estrutura que suporta esses requisitos. Ao usar comunicação assíncrona e interações orientadas a eventos, os sistemas podem lidar eficientemente com altos volumes de transações e manter desempenho sob cargas instáveis. Esses recursos são particularmente valorizados em ambientes onde as mudanças são muito espontâneas, como plataformas de e-commerce ou aplicações de IoT.

Alguns componentes chave da EDA incluem:

  • Fontes de Eventos: Estes são os produtores que geram eventos quando ações significativas ocorrem dentro do sistema. Exemplos incluem interações do usuário ou mudanças de dados.

  • Ouvintes: Estas são entidades que se inscrevem em eventos específicos e respondem quando esses eventos ocorrem. Ouvintes permitem que o sistema reaja dinamicamente às mudanças.

  • Manipuladores: Estes são responsáveis por processar os eventos uma vez que são detectados pelos ouvintes, executando a lógica de negócios necessária ou fluxos de trabalho acionados pelo evento.

Neste artigo, você aprenderá como implementar o processamento de dados orientado a eventos usando Traefik, Kafka e Docker.

Aqui está um aplicativo simples hospedado no GitHub que você pode executar rapidamente para ter uma visão geral do que você estará construindo hoje.

Sumário

Aqui está o que vamos cobrir:

Vamos começar!

Pré-requisitos

Antes de começar:

  • Implante uma instância do Ubuntu 24.04 com pelo menos 4 GB de RAM e um mínimo de 20 GB de espaço em disco livre para acomodar imagens Docker, contêineres e dados do Kafka.

  • Acesse a instância com um usuário não-root com privilégios sudo.

  • Atualize o índice de pacotes.

sudo apt update

Compreendendo as Tecnologias

Apache Kafka

O Apache Kafka é uma plataforma distribuída de streaming de eventos construída para pipelines de dados de alto throughput e aplicações de streaming em tempo real. Ele atua como espinha dorsal para implementar a EDA gerenciando eficientemente grandes volumes de eventos. O Kafka usa um modelo de publicação e subscrição, no qual os produtores enviam eventos para tópicos, e os consumidores se inscrevem nesses tópicos para receber os eventos.

Algumas das principais características do Kafka incluem:

  • Alto Throughput: O Kafka é capaz de lidar com milhões de eventos por segundo com baixa latência, tornando-o adequado para aplicações de alto volume.

  • Tolerância a Falhas: A arquitetura distribuída do Kafka garante a durabilidade e disponibilidade dos dados mesmo diante de falhas de servidores. Ele replica os dados em vários brokers dentro de um cluster.

  • Escalabilidade: O Kafka pode facilmente escalar horizontalmente adicionando mais brokers ao cluster ou partições aos tópicos, atendendo às crescentes necessidades de dados sem reconfiguração significativa.

Traefik

Traefik é um moderno proxy reverso HTTP e balanceador de carga projetado especificamente para arquiteturas de microsserviços. Ele descobre automaticamente os serviços em execução em sua infraestrutura e roteia o tráfego adequadamente. Traefik simplifica o gerenciamento de microsserviços, fornecendo capacidades de roteamento dinâmico com base em metadados de serviço.

Algumas das principais características do Traefik incluem:

  • Configuração Dinâmica: Traefik atualiza automaticamente sua configuração de roteamento à medida que os serviços são adicionados ou removidos, eliminando a intervenção manual.

  • Balanceamento de Carga: Distribui eficientemente as solicitações recebidas entre várias instâncias de serviço, melhorando o desempenho e a confiabilidade.

  • Painel Integrado: O Traefik fornece um painel amigável para monitorar o tráfego e a saúde do serviço em tempo real.

Ao usar Kafka e Traefik em uma arquitetura orientada a eventos, você pode construir sistemas responsivos que lidam eficientemente com o processamento de dados em tempo real, mantendo alta disponibilidade e escalabilidade.

Como Configurar o Ambiente

Como Instalar o Docker no Ubuntu 24.04

  1. Instale os pacotes necessários.
sudo apt install ca-certificates curl gnupg lsb-release
  1. Adicione a Chave GPG oficial do Docker.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  1. Adicione o repositório do Docker às suas fontes 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
  1. Atualize novamente o índice de pacotes e instale o Docker Engine com o plugin Docker Compose.
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  1. Verifique para confirmar a instalação.
sudo docker run hello-world

Saída 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.

Como Configurar o Docker Compose

O Docker Compose simplifica a gestão de aplicações com múltiplos contêineres, permitindo que você defina e execute serviços em um único arquivo.

  1. Crie um diretório de projeto
mkdir ~/kafka-traefik-setup && cd ~/kafka-traefik-setup
  1. Crie um arquivo docker-compose.yml.
nano docker-compose.yml
  1. Adicione a seguinte configuração ao arquivo para definir seus serviços.
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áfego HTTP
      - "8080:8080"   # Painel do Traefik (inseguro)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Salve suas alterações com ctrl + o, em seguida saia com ctrl + x.

  1. Inicie seus serviços.
docker compose up -d

Saída 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

Como Construir o Sistema Baseado em Eventos

Como Criar Produtores de Eventos

Para produzir eventos no Kafka, você precisará implementar um produtor do Kafka. Abaixo está um exemplo usando Java.

  1. Crie um arquivo kafka-producer.java.
nano kafka-producer.java
  1. Adicione a seguinte configuração para um Produtor do 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 as propriedades do produtor
        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");

        // Criar o produtor
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        try {
            // Enviar uma mensagem para o tópico "meu-tópico"
            ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key1", "Hello, Kafka!");
            RecordMetadata metadata = producer.send(record).get(); // Envio 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 {
            // Fechar o produtor
            producer.close();
        }
    }
}

Salve suas alterações com ctrl + o, em seguida saia com ctrl + x.

No exemplo de configuração acima, o produtor envia uma mensagem com a chave “chave1” e o valor “Olá, Kafka!” para o tópico “meu-tópico”.

Como Configurar Tópicos no Kafka

Antes de produzir ou consumir mensagens, você precisa criar tópicos no Kafka.

  1. Use o script kafka-topics.sh incluído na sua instalação do Kafka para criar um tópico.
kafka-topics.sh --bootstrap-server localhost:9092 --create --topic <TopicName> --partitions <NumberOfPartitions> --replication-factor <ReplicationFactor>

Por exemplo, se você deseja criar um tópico chamado meu-topico com 3 partições e um fator de replicação de 1, execute:

docker exec <Kafka Container ID> /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my-topic --partitions 3 --replication-factor 1

Saída Esperada:

Created topic my-topic.
  1. Verifique para confirmar se o Tópico foi criado com sucesso.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list

Saída Esperada:

my-topic

Como Criar Consumidores de Eventos

Depois de ter criado seus produtores e tópicos, você pode criar consumidores para ler mensagens desses tópicos.

  1. Crie um arquivo kafka-consumer.java.
nano kafka-consumer.java
  1. Adicione a seguinte configuração para um consumidor 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 as propriedades do 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");

        // Criar o consumidor
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // Inscrever-se no tópico
        consumer.subscribe(Collections.singletonList("my-topic"));

        try {
            while (true) {
                // Pesquisar por novos 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 {
            // Fechar o consumidor
            consumer.close();
        }
    }
}

Salve suas alterações com ctrl + o, em seguida, saia com ctrl + x.

Na configuração acima, o consumidor se inscreve em meu-topico e continua a pesquisar por novas mensagens. Quando as mensagens são recebidas, ele imprime suas chaves e valores juntamente com informações de partição e offset.

Como Integrar o Traefik com o Kafka

Configure o Traefik como um Proxy Reverso.

Integrar o Traefik como um proxy reverso para o Kafka permite gerenciar o tráfego de entrada de forma eficiente, enquanto fornece recursos como roteamento dinâmico e terminação SSL.

  1. Atualize o arquivo 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áfego HTTP
      - "8080:8080"    # Painel do Traefik (inseguro)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Nesta configuração, substitua kafka.example.com pelo seu nome de domínio real. Os rótulos definem as regras de roteamento que o Traefik usará para direcionar o tráfego para o serviço Kafka.

  1. Reinicie seus serviços.
docker compose up -d
  1. Acesse o painel do Traefik acessando http://localhost:8080 no seu navegador web.

    Balanceamento de Carga com Traefik

    O Traefik fornece capacidades de balanceamento de carga integradas que podem ajudar a distribuir as solicitações entre várias instâncias de seus produtores e consumidores Kafka.

    Estratégias para Balanceamento de Carga de Microserviços Orientados a Eventos

    1. Round Robin:

Por padrão, o Traefik utiliza uma estratégia de round-robin para distribuir solicitações de entrada de forma equitativa entre todas as instâncias disponíveis de um serviço. Isso é eficaz para balancear a carga quando várias instâncias de produtores ou consumidores do Kafka estão em execução.

  1. Sticky Sessions:

Se você precisa que solicitações de um cliente específico sempre vão para a mesma instância (por exemplo, manter o estado da sessão), você pode configurar sessões aderentes no Traefik usando cookies ou headers.

  1. Health Checks:

Configure verificações de saúde no Traefik para garantir que o tráfego seja roteado apenas para instâncias saudáveis de seus serviços do Kafka. Você pode fazer isso adicionando parâmetros de verificação de saúde nas definições de serviço dentro do seu arquivo 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"

Testando a Configuração

Verificando a Produção e Consumo de Eventos

  1. O Kafka fornece ferramentas de linha de comando integradas para teste. Inicie um produtor de Console.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic my-topic

Após executar este comando, você pode digitar mensagens no terminal, que serão enviadas para o tópico Kafka especificado.

  1. Inicie outra sessão de terminal e inicie um consumidor de console.
    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 exibirá todas as mensagens em my-topic, incluindo aquelas produzidas antes do início do consumidor.

  1. Para ver como seus consumidores estão acompanhando os produtores, você pode executar o seguinte comando para verificar o atraso de um grupo específico de consumidores.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <your-consumer-group>

Monitoramento e Registro

  1. Métricas do Kafka:

O Kafka expõe inúmeras métricas que podem ser monitoradas usando JMX (Java Management Extensions). Você pode configurar o JMX para exportar essas métricas para sistemas de monitoramento como Prometheus ou Grafana. As principais métricas a serem monitoradas incluem:

  • Taxa de Mensagens: A taxa de mensagens produzidas e consumidas.

  • Atraso do Consumidor: A diferença entre o último deslocamento da mensagem produzida e o último deslocamento da mensagem consumida.

  • Saúde do Broker: Métricas relacionadas ao desempenho do broker, como taxas de solicitação e taxas de erro.

  1. Integração com Prometheus e Grafana:

Para visualizar as métricas do Kafka, você pode configurar o Prometheus para coletar métricas dos seus brokers Kafka. Siga estes passos:

  • Ative o JMX Exporter em seus brokers Kafka adicionando-o como um agente Java em sua configuração de broker.

  • Configure o Prometheus adicionando um trabalho de coleta em seu arquivo de configuração (prometheus.yml) que aponta para o endpoint do seu JMX Exporter.

  • Use o Grafana para criar painéis que visualizam essas métricas em tempo real.

Como Implementar o Monitoramento para o Traefik

  1. Endpoint de Métricas do Traefik.

O Traefik oferece suporte integrado para exportar métricas via Prometheus. Para ativar esse recurso, adicione a seguinte configuração na definição de serviço do Traefik dentro do arquivo docker-compose.yml:

    command:
      - "--metrics.prometheus=true"
      - "--metrics.prometheus.addservice=true"
  1. Visualizando as Métricas do Traefik com o Grafana.

Uma vez que o Prometheus está coletando as métricas do Traefik, você pode visualizá-las usando o Grafana:

  • Crie um novo painel no Grafana e adicione painéis que exibam métricas-chave do Traefik, como:

  • traefik_entrypoint_requests_total: Número total de solicitações recebidas.

  • traefik_backend_request_duration_seconds: Tempos de resposta dos serviços backend.

  • traefik_service_requests_total: Total de solicitações encaminhadas para os serviços backend.

  1. Configurando Alertas.

Configure alertas no Prometheus ou Grafana com base em limiares específicos (por exemplo, alta latência do consumidor ou aumento nas taxas de erro).

Conclusão

Neste guia, você implementou com sucesso a Arquitetura Orientada a Eventos (EDA) usando Kafka e Traefik no ambiente Ubuntu 24.04.

Recursos Adicionais

Para saber mais, você pode visitar: