В современном проектировании система Архитектура событий (EDA) сосредотачивается на создании, обнаружении, использовании и реагировании на события в системе. События – это значительные события, которые могут повлиять на аппаратное или программное обеспечение системы, такие как действия пользователей, изменения состояния или обновления данных.

EDA позволяет различным частям приложения взаимодействовать независимо, позволяя им общаться через события, а не напрямую. Такая настройка позволяет компонентам работать независимо, реагировать на события асинхронно и адаптироваться к изменяющимся бизнес-потребностям без крупной переконфигурации системы, способствуя гибкости.

Новые и современные приложения теперь тесно полагаются на обработку данных в реальном времени и отзывчивость. Важность EDA не может быть недооценена, потому что она обеспечивает структуру, которая поддерживает эти требования. Используя асинхронное взаимодействие и событийно-ориентированные взаимодействия, системы могут эффективно обрабатывать большие объемы транзакций и поддерживать производительность при нестабильных нагрузках. Эти функции особенно ценятся в средах, где изменения происходят очень спонтанно, таких как платформы электронной коммерции или приложения интернета вещей.

Некоторые ключевые компоненты EDA включают в себя:

  • Источники событий: Это производители, которые генерируют события, когда в системе происходят значительные действия. Примеры включают в себя взаимодействия пользователей или изменения данных.

  • Прослушиватели: Это сущности, которые подписываются на определенные события и реагируют, когда эти события происходят. Прослушиватели позволяют системе реагировать динамически на изменения.

  • Обработчики: Эти сущности отвечают за обработку событий после их обнаружения прослушивателями, выполнение необходимой бизнес-логики или рабочих процессов, запущенных событием.

В этой статье вы узнаете, как реализовать обработку данных на основе событий с использованием Traefik, Kafka и Docker.

Вот простое приложение, размещенное на GitHub, которое вы можете быстро запустить, чтобы получить обзор того, что вы будете сегодня создавать.

Содержание

Вот, что мы рассмотрим:

Давайте начнем!

Предварительные условия

Прежде чем начать:

  • Разверните экземпляр Ubuntu 24.04 с минимум 4 ГБ оперативной памяти и не менее 20 ГБ свободного места на диске для размещения образов Docker, контейнеров и данных Kafka.

  • Получите доступ к экземпляру от имени пользователя без прав root с привилегиями sudo.

  • Обновите индекс пакетов.

sudo apt update

Понимание технологий

Apache Kafka

Apache Kafka – это распределенная платформа для потоковых событий, созданная для высокопроизводительных конвейеров данных и приложений реального времени. Он является основой для реализации EDA за счет эффективного управления большими объемами событий. Kafka использует модель публикации-подписки, где производители отправляют события в темы, а потребители подписываются на эти темы для получения событий.

Некоторые ключевые особенности Kafka включают:

  • Высокая пропускная способность: Kafka способен обрабатывать миллионы событий в секунду с низкой задержкой, что делает его подходящим для приложений с высоким объемом.

  • Отказоустойчивость: Распределенная архитектура Kafka обеспечивает сохранность данных и доступность даже в случае сбоев серверов. Она реплицирует данные по нескольким брокерам внутри кластера.

  • Масштабируемость: Kafka может легко масштабироваться горизонтально путем добавления большего количества брокеров в кластер или разделов к темам, что позволяет удовлетворить растущие потребности в данных без значительной перенастройки.

Traefik

Traefik – современный HTTP обратный прокси и балансировщик нагрузки, разработанный специально для микросервисных архитектур. Он автоматически обнаруживает службы, работающие в вашей инфраструктуре, и маршрутизирует трафик соответственно. Traefik упрощает управление микросервисами, предоставляя динамические возможности маршрутизации на основе метаданных служб.

Некоторые ключевые особенности Traefik включают:

  • Динамическая конфигурация: Traefik автоматически обновляет свою конфигурацию маршрутизации при добавлении или удалении служб, устраняя необходимость вручного вмешательства.

  • Балансировка нагрузки: она эффективно распределяет входящие запросы между несколькими экземплярами службы, улучшая производительность и надежность.

  • Интегрированная панель управления: Traefik предоставляет удобную панель для мониторинга трафика и состояния службы в реальном времени.

Используя Kafka и Traefik в архитектуре, ориентированной на события, вы можете строить отзывчивые системы, которые эффективно обрабатывают данные в реальном времени, поддерживая высокую доступность и масштабируемость.

Как настроить окружение

Как установить Docker на Ubuntu 24.04

  1. Установите необходимые пакеты.
sudo apt install ca-certificates curl gnupg lsb-release
  1. Добавьте официальный GPG-ключ Docker.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  1. Добавьте репозиторий Docker в ваши источники 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. Обновите индекс пакетов и установите Docker Engine с плагином Docker Compose.
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  1. Проверьте, чтобы подтвердить установку.
sudo docker run hello-world

Ожидаемый вывод:

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.

Как настроить Docker Compose

Docker Compose упрощает управление многоконтейнерными приложениями, позволяя вам определять и запускать службы в одном файле.

  1. Создайте каталог проекта
mkdir ~/kafka-traefik-setup && cd ~/kafka-traefik-setup
  1. Создайте файл docker-compose.yml.
nano docker-compose.yml
  1. Добавьте следующую конфигурацию в файл, чтобы определить ваши службы.
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"       # Трафик HTTP
      - "8080:8080"   # Панель управления Traefik (небезопасная)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Сохраните ваши изменения с помощью ctrl + o, затем выйдите с помощью ctrl + x.

  1. Запустите ваши службы.
docker compose up -d

Ожидаемый результат:

[+] 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

Как построить событийную систему

Как создать производителей событий

Для создания событий в Kafka вам потребуется реализовать производителя Kafka. Ниже приведен пример с использованием Java.

  1. Создайте файл kafka-producer.java.
nano kafka-producer.java
  1. Добавьте следующую конфигурацию для производителя 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) {
        // Настройка свойств производителя
        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");

        // Создание производителя
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        try {
            // Отправка сообщения в тему "my-topic"
            ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key1", "Hello, Kafka!");
            RecordMetadata metadata = producer.send(record).get(); // Синхронная отправка
            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 {
            // Закрытие производителя
            producer.close();
        }
    }
}

Сохраните ваши изменения с помощью ctrl + o, затем выйдите с помощью ctrl + x.

В приведенной выше конфигурации производитель отправляет сообщение с ключом “key1” и значением “Привет, Kafka!” в тему “my-topic”.

Как настроить темы Kafka

Прежде чем производить или потреблять сообщения, вам необходимо создать темы в Kafka.

  1. Используйте скрипт kafka-topics.sh, включенный в вашу установку Kafka, чтобы создать тему.
kafka-topics.sh --bootstrap-server localhost:9092 --create --topic <TopicName> --partitions <NumberOfPartitions> --replication-factor <ReplicationFactor>

Например, если вы хотите создать тему с именем my-topic с 3 разделами и фактором репликации 1, выполните:

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

Ожидаемый вывод:

Created topic my-topic.
  1. Проверьте, была ли тема успешно создана.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list

Ожидаемый вывод:

my-topic

Как создать потребителей событий

После того как вы создали своих производителей и темы, вы можете создать потребителей для чтения сообщений из этих тем.

  1. Создайте файл kafka-consumer.java.
nano kafka-consumer.java
  1. Добавьте следующую конфигурацию для потребителя 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) {
        // Настройка свойств потребителя
        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");

        // Создание потребителя
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // Подписка на тему
        consumer.subscribe(Collections.singletonList("my-topic"));

        try {
            while (true) {
                // Опрос новых записей
                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 {
            // Закрытие потребителя
            consumer.close();
        }
    }
}

Сохраните ваши изменения с помощью ctrl + o, затем выйдите с помощью ctrl + x.

В приведенной выше конфигурации потребитель подписывается на my-topic и непрерывно запрашивает новые сообщения. Когда сообщения получены, он выводит их ключи и значения вместе с информацией о разделе и смещении.

Как интегрировать Traefik с Kafka

Настройка Traefik в качестве обратного прокси.

Интеграция Traefik в качестве обратного прокси для Kafka позволяет эффективно управлять входящим трафиком, обеспечивая функции, такие как динамическая маршрутизация и завершение SSL.

  1. Обновите файл 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"        # Трафик HTTP
      - "8080:8080"    # Панель управления Traefik (небезопасная)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

В этой конфигурации замените kafka.example.com на свое фактическое доменное имя. Метки определяют правила маршрутизации, которые Traefik будет использовать для направления трафика на службу Kafka.

  1. Перезапустите ваши службы.
docker compose up -d
  1. Получите доступ к панели управления Traefik, открыв http://localhost:8080 в вашем веб-браузере.

    Балансировка нагрузки с помощью Traefik

    Traefik обеспечивает встроенные возможности балансировки нагрузки, которые могут помочь распределять запросы между несколькими экземплярами ваших производителей и потребителей Kafka.

    Стратегии балансировки нагрузки микросервисов, ориентированных на события

    1. По кругу:

По умолчанию Traefik использует стратегию по кругу для равномерного распределения входящих запросов между всеми доступными экземплярами службы. Это эффективно для балансировки нагрузки при работе нескольких экземпляров производителей или потребителей Kafka.

  1. Клиентские сессии:

Если вам нужно, чтобы запросы от определенного клиента всегда отправлялись на один и тот же экземпляр (например, для сохранения состояния сеанса), вы можете настроить клиентские сессии в Traefik с использованием файлов cookie или заголовков.

  1. Проверка состояния:

Настройте проверку состояния в Traefik, чтобы гарантировать, что трафик направляется только к здоровым экземплярам вашего сервиса Kafka. Для этого добавьте параметры проверки состояния в определения служб в вашем файле 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"

Тестирование настройки

Проверка производства и потребления событий

  1. Kafka предоставляет встроенные инструменты командной строки для тестирования. Запустите консольного производителя.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic my-topic

После выполнения этой команды вы можете вводить сообщения в терминал, которые будут отправлены в указанную тему Kafka.

  1. Начните новую сессию терминала и запустите консольного потребителя.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my-topic --from-beginning

Эта команда отобразит все сообщения в my-topic, включая те, которые были созданы до начала работы потребителя.

  1. Чтобы увидеть, насколько хорошо ваши потребители справляются с производителями, вы можете выполнить следующую команду, чтобы проверить отставание для конкретной группы потребителей.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <your-consumer-group>

Мониторинг и ведение журналов

  1. Метрики Kafka:

Kafka предоставляет множество метрик, которые можно мониторить с помощью JMX (Java Management Extensions). Вы можете настроить JMX для экспорта этих метрик в системы мониторинга, такие как Prometheus или Grafana. Ключевые метрики для мониторинга включают:

  • Пропускная способность сообщений: Скорость производства и потребления сообщений.

  • Отставание потребителя: Разница между смещением последнего произведенного сообщения и смещением последнего потребленного сообщения.

  • Здоровье брокера: Метрики, связанные с производительностью брокера, такие как скорость запросов и уровень ошибок.

  1. Интеграция с Prometheus и Grafana:

Чтобы визуализировать метрики Kafka, вы можете настроить Prometheus для сбора метрик с ваших брокеров Kafka. Следуйте этим шагам:

  • Включите JMX Exporter на ваших брокерах Kafka, добавив его в качестве Java-агента в конфигурацию брокера.

  • Настройте Prometheus, добавив задачу сканирования в его конфигурационный файл (prometheus.yml), которая указывает на точку доступа вашего JMX Exporter.

  • Используйте Grafana для создания панелей мониторинга, которые визуализируют эти метрики в реальном времени.

Как реализовать мониторинг для Traefik

  1. Конечная точка метрик Traefik.

Traefik имеет встроенную поддержку экспорта метрик через Prometheus. Чтобы включить эту функцию, добавьте следующую конфигурацию в определение службы Traefik в вашем файле docker-compose.yml:

    command:
      - "--metrics.prometheus=true"
      - "--metrics.prometheus.addservice=true"
  1. Визуализация метрик Traefik с помощью Grafana.

Как только Prometheus сканирует метрики Traefik, вы можете визуализировать их с помощью Grafana:

  • Создайте новую панель в Grafana и добавьте панели, отображающие ключевые метрики Traefik, такие как:

  • traefik_entrypoint_requests_total: Общее количество полученных запросов.

  • traefik_backend_request_duration_seconds: Время ответа от backend-сервисов.

  • traefik_service_requests_total: Всего запросов, перенаправленных на backend-сервисы.

  1. Настройка оповещений.

Настройте оповещения в Prometheus или Grafana на основе определенных порогов (например, высокая задержка у потребителя или увеличение уровня ошибок).

Заключение

В этом руководстве вы успешно реализовали архитектуру, основанную на событиях (EDA), используя Kafka и Traefik в среде Ubuntu 24.04.

Дополнительные ресурсы

Чтобы узнать больше, вы можете посетить: