Введение в KafkaStreams на Java

Введение в KafkaStreams на Java

1. обзор

В этой статье мы рассмотримKafkaStreams library.

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

KafkaStreams позволяет нам использовать темы Kafka, анализировать или преобразовывать данные и, возможно, отправлять их в другую тему Kafka.

Чтобы продемонстрироватьKafkaStreams,, мы создадим простое приложение, которое читает предложения из темы, считает вхождения слов и печатает количество слов.

Важно отметить, что библиотекаKafkaStreams не является реактивной и не поддерживает асинхронные операции и обработку обратного давления.

2. Maven Dependency

Чтобы начать писать логику обработки потока с использованиемKafkaStreams,, нам нужно добавить зависимость кkafka-streams иkafka-clients:


    org.apache.kafka
    kafka-streams
    1.0.0


    org.apache.kafka
    kafka-clients
    1.0.0

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

Мы можем скачать Kafka и другие необходимые зависимости изthe official website.

3. Настройка ввода KafkaStreams

Первое, что мы сделаем, - это определение темы ввода Kafka.

Мы можем использовать скачанный нами инструментConfluent - он содержит сервер Kafka. Он также содержитkafka-console-producer, которые мы можем использовать для публикации сообщений в Kafka.

Для начала запустим наш кластер Kafka:

./confluent start

После запуска Kafka мы можем определить наш источник данных и имя нашего приложения, используяAPPLICATION_ID_CONFIG:

String inputTopic = "inputTopic";
Properties streamsConfiguration = new Properties();
streamsConfiguration.put(
  StreamsConfig.APPLICATION_ID_CONFIG,
  "wordcount-live-test");

Важнейшим параметром конфигурации являетсяBOOTSTRAP_SERVER_CONFIG.. Это URL-адрес нашего локального экземпляра Kafka, который мы только что запустили:

private String bootstrapServers = "localhost:9092";
streamsConfiguration.put(
  StreamsConfig.BOOTSTRAP_SERVERS_CONFIG,
  bootstrapServers);

Далее нам нужно передать тип ключа и значение сообщений, которые будут использоваться изinputTopic:

streamsConfiguration.put(
  StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG,
  Serdes.String().getClass().getName());
streamsConfiguration.put(
  StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG,
  Serdes.String().getClass().getName());

Stream processing is often stateful. When we want to save intermediate results, we need to specify the STATE_DIR_CONFIG parameter.

В нашем тесте мы используем локальную файловую систему:

streamsConfiguration.put(
  StreamsConfig.STATE_DIR_CONFIG,
  TestUtils.tempDirectory().getAbsolutePath());

4. Построение потоковой топологии

Определив тему ввода, мы можем создать топологию потоковой передачи - это определение того, как события должны обрабатываться и преобразовываться.

В нашем примере мы хотим реализовать счетчик слов. Для каждого предложения, отправленного вinputTopic,, мы хотим разбить его на слова и вычислить вхождение каждого слова.

Мы можем использовать экземпляр классаKStreamsBuilder, чтобы начать построение нашей топологии:

KStreamBuilder builder = new KStreamBuilder();
KStream textLines = builder.stream(inputTopic);
Pattern pattern = Pattern.compile("\\W+", Pattern.UNICODE_CHARACTER_CLASS);

KTable wordCounts = textLines
  .flatMapValues(value -> Arrays.asList(pattern.split(value.toLowerCase())))
  .groupBy((key, word) -> word)
  .count();

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

Метод split возвращает массив. Мы используемflatMapValues(), чтобы его сгладить. В противном случае у нас получился бы список массивов, и писать код с такой структурой было бы неудобно.

Наконец, мы собираем значения для каждого слова и вызываемcount(), который будет вычислять количество вхождений конкретного слова.

5. Обработка результатов

Мы уже рассчитали количество слов наших входных сообщений. Now let’s print the results on the standard output using the foreach() method:с

wordCounts
  .foreach((w, c) -> System.out.println("word: " + w + " -> " + c));

На производстве часто такое потоковое задание может публиковать результаты в другой теме Кафки.

Мы могли бы сделать это с помощьюto() method:

String outputTopic = "outputTopic";
Serde stringSerde = Serdes.String();
Serde longSerde = Serdes.Long();
wordCounts.to(stringSerde, longSerde, outputTopic);

КлассSerde предоставляет нам предварительно сконфигурированные сериализаторы для типов Java, которые будут использоваться для сериализации объектов в массив байтов. Затем массив байтов будет отправлен в тему Kafka.

Мы используемString как ключ к нашей теме иLong как значение для фактического количества. Методto() сохранит полученные данные вoutputTopic.

6. Запуск задания KafkaStream

До этого момента мы строили топологию, которая может быть выполнена. Однако работа еще не началась.

Нам нужно явно начать нашу работу, вызвав методstart() в экземпляреKafkaStreams:

KafkaStreams streams = new KafkaStreams(builder, streamsConfiguration);
streams.start();

Thread.sleep(30000);
streams.close();

Обратите внимание, что мы ждем 30 секунд, чтобы закончить работу. В реальном сценарии эта работа будет выполняться постоянно, обрабатывая события от Кафки по мере их поступления.

Мы можем протестировать нашу работу, опубликовав некоторые события в нашей теме Kafka.

Давайте запустимkafka-console-producer и вручную отправим некоторые события на нашinputTopic:

./kafka-console-producer --topic inputTopic --broker-list localhost:9092
>"this is a pony"
>"this is a horse and pony"

Таким образом, мы опубликовали два события для Кафки. Наше приложение будет использовать эти события и выведет следующий вывод:

word:  -> 1
word: this -> 1
word: is -> 1
word: a -> 1
word: pony -> 1
word:  -> 2
word: this -> 2
word: is -> 2
word: a -> 2
word: horse -> 1
word: and -> 1
word: pony -> 2

Мы видим, что когда пришло первое сообщение, словоpony встречается только один раз. Но когда мы отправили второе сообщение, словоpony появилось во второй раз, напечатав: «word: pony → 2″.

6. Заключение

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

Все эти примеры и фрагменты кода можно найти вGitHub project - это проект Maven, поэтому его должно быть легко импортировать и запускать как есть.