当前位置:   article > 正文

六、Kafka Stream的介绍与使用

kafka stream

本篇内容可以很好的帮助和理解Kafka stream的原理,这便于我们更好的使用它,内含一个搭建Kafka stream的实例,便于我们更好的掌握使用

一、Kafka Stream 介绍

1 、概述

Kafka Streams是一个客户端程序库,用于处理和分析存储在Kafka中的数据,并将得到的数据写回Kafka或发送到外部系统。Kafka Stream基于一个重要的流处理概念。如正确的区分事件时间和处理时间,窗口支持,以及简单而有效的应用程序状态管理。Kafka Streams的入口门槛很低: 你可以快速的编写和在单台机器上运行一个小规模的概念证明(proof-of-concept);而你只需要运行你的应用程序部署到多台机器上,以扩展高容量的生产负载。Kafka Stream利用kafka的并行模型来透明的处理相同的应用程序作负载平衡。

Kafka Stream 的亮点:

  • 设计一个简单的、轻量级的客户端库,可以很容易地嵌入在任何java应用程序与任何现有应用程序封装集成。
  • Apache Kafka本身作为内部消息层,没有外部系统的依赖,还有,它使用kafka的分区模型水平扩展处理,并同时保证有序。
  • 支持本地状态容错,非常快速、高效的状态操作(如join和窗口的聚合)。
  • 采用 one-recored-at-a-time(一次一个消息) 处理以实现低延迟,并支持基于事件时间(event-time)的窗口操作。
  • 提供必要的流处理原语(primitive),以及一个 高级别的Steram DSL 和 低级别的Processor API。

2 、核心概念

我们首先总结Kafka Streams的关键概念。

Stream处理拓扑

  • 流是Kafka Stream提出的最重要的抽象概念:它表示一个无限的,不断更新的数据集。流是一个有序的,可重放(反复的使用),不可变的容错序列,数据记录的格式是键值对(key-value)。
  • 通过Kafka Streams编写一个或多个的计算逻辑的处理器拓扑。其中处理器拓扑是一个由流(边缘)连接的流处理(节点)的图。
  • 流处理器是处理器拓扑中的一个节点;它表示一个处理的步骤,用来转换流中的数据(从拓扑中的上游处理器一次接受一个输入消息,并且随后产生一个或多个输出消息到其下游处理器中)。

在拓扑中有两个特别的处理器:

  • 源处理器(Source Processor):源处理器是一个没有任何上游处理器的特殊类型的流处理器。它从一个或多个kafka主题生成输入流。通过消费这些主题的消息并将它们转发到下游处理器。
  • Sink处理器:sink处理器是一个没有下游流处理器的特殊类型的流处理器。它接收上游流处理器的消息发送到一个指定的Kafka主题。

Kafka streams提供2种方式来定义流处理器拓扑:Kafka Streams DSL提供了更常用的数据转换操作,如map和filter;低级别Processor API允许开发者定义和连接自定义的处理器,以及和状态仓库交互。

处理器拓扑仅仅是流处理代码的逻辑抽象。

3、使用示例

注意:如果是搭建的集群的话,需要把各个broker都启动起来

3.1 启动相关配置

启动各个zookerper、broker、producer

创建所需要的topic

3.2 引入项目依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.4.5</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com</groupId>
  12. <artifactId>KafkaTest02</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>KafkaTest02</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.kafka</groupId>
  22. <artifactId>spring-kafka</artifactId>
  23. <version>2.4.0.RELEASE</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.apache.kafka</groupId>
  27. <artifactId>kafka-streams</artifactId>
  28. <version>2.5.0</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter</artifactId>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-starter-test</artifactId>
  37. <scope>test</scope>
  38. </dependency>
  39. </dependencies>
  40. <build>
  41. <plugins>
  42. <plugin>
  43. <groupId>org.springframework.boot</groupId>
  44. <artifactId>spring-boot-maven-plugin</artifactId>
  45. </plugin>
  46. </plugins>
  47. </build>
  48. </project>

3.3 创建一个测试类

这个类用于将输入到主题中的字段进行整理再输入到另一个主题中

  1. package com.kafkatest02;
  2. import org.apache.kafka.clients.consumer.ConsumerConfig;
  3. import org.apache.kafka.common.serialization.Serdes;
  4. import org.apache.kafka.streams.KafkaStreams;
  5. import org.apache.kafka.streams.StreamsBuilder;
  6. import org.apache.kafka.streams.StreamsConfig;
  7. import org.apache.kafka.streams.kstream.KStream;
  8. import org.apache.kafka.streams.kstream.KTable;
  9. import org.apache.kafka.streams.kstream.Produced;
  10. import java.util.Arrays;
  11. import java.util.Locale;
  12. import java.util.Properties;
  13. import java.util.concurrent.CountDownLatch;
  14. public class StreamSample {
  15. //定义数据来源的topic和输出到的topic
  16. //注意这两个主题需要提前创建
  17. public static final String INPUT_TOPIC = "countin";
  18. public static final String OUTPUT_TOPIC = "countout";
  19. //创建一个配置对象
  20. static Properties getStreamsConfig() {
  21. final Properties props = new Properties();
  22. //新建一个Kafka消费者组
  23. props.put(StreamsConfig.APPLICATION_ID_CONFIG, "streams-wordcount");
  24. //监听broker的端口地址
  25. props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
  26. props.put(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG, 0);
  27. props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
  28. props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
  29. // setting offset reset to earliest so that we can re-run the demo code with the same pre-loaded data
  30. // Note: To re-run the demo, you need to use the offset reset tool:
  31. // https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Streams+Application+Reset+Tool
  32. //获取topic中最早的消息
  33. props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
  34. return props;
  35. }
  36. static void createWordCountStream(final StreamsBuilder builder) {
  37. final KStream<String, String> source = builder.stream(INPUT_TOPIC);
  38. final KTable<String, Long> counts = source
  39. .flatMapValues(value -> Arrays.asList(value.toLowerCase(Locale.getDefault()).split(" ")))
  40. .groupBy((key, value) -> value)
  41. .count();
  42. // need to override value serde to Long type
  43. counts.toStream().to(OUTPUT_TOPIC, Produced.with(Serdes.String(), Serdes.Long()));
  44. }
  45. public static void main(final String[] args) {
  46. final Properties props = getStreamsConfig();
  47. final StreamsBuilder builder = new StreamsBuilder();
  48. createWordCountStream(builder);
  49. final KafkaStreams streams = new KafkaStreams(builder.build(), props);
  50. final CountDownLatch latch = new CountDownLatch(1);
  51. // attach shutdown handler to catch control-c
  52. Runtime.getRuntime().addShutdownHook(new Thread("streams-wordcount-shutdown-hook") {
  53. @Override
  54. public void run() {
  55. streams.close();
  56. latch.countDown();
  57. }
  58. });
  59. try {
  60. streams.start();
  61. latch.await();
  62. } catch (final Throwable e) {
  63. System.exit(1);
  64. }
  65. System.exit(0);
  66. }
  67. }

3.4编写消费者类

用于输出整理后输入到主题中的字段数据

  1. package com.kafkatest02;
  2. import org.apache.kafka.clients.consumer.ConsumerRecord;
  3. import org.apache.kafka.clients.consumer.ConsumerRecords;
  4. import org.apache.kafka.clients.consumer.KafkaConsumer;
  5. import org.apache.kafka.common.TopicPartition;
  6. import org.springframework.kafka.annotation.KafkaListener;
  7. import java.util.Arrays;
  8. import java.util.Properties;
  9. public class UserLogConsumer {
  10. @KafkaListener(topics = {"countout"})
  11. public void consumer(){
  12. Properties props = new Properties();
  13. props.setProperty("bootstrap.servers", "localhost:9091");
  14. props.setProperty("group.id", "group01"); //注意这里是重新创建个分组,如果已存在则会报错
  15. props.setProperty("enable.auto.commit", "false");
  16. props.setProperty("auto.commit.interval.ms", "3000");
  17. props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
  18. props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
  19. KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
  20. consumer.assign(Arrays.asList(new TopicPartition("countout", 0)));
  21. consumer.seek(new TopicPartition("countout", 0), 0);//不改变当前offset
  22. while (true) {
  23. ConsumerRecords<String, String> records = consumer.poll(100);
  24. for (ConsumerRecord<String, String> record : records){
  25. System.out.println(record.value()+"~~~~~~~~~~~~~~~~~~~~~~~~~~~"+record.key());
  26. }
  27. consumer.commitAsync();
  28. }
  29. }
  30. public static void main(String[] args) {
  31. UserLogConsumer userLogConsumer=new UserLogConsumer();
  32. userLogConsumer.consumer();
  33. }
  34. }

3.5编写消息生产者类

  1. package com.kafkatest02.kafka_Stream;
  2. import org.apache.kafka.clients.producer.KafkaProducer;
  3. import org.apache.kafka.clients.producer.Producer;
  4. import org.apache.kafka.clients.producer.ProducerRecord;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.kafka.core.KafkaTemplate;
  7. import org.springframework.stereotype.Component;
  8. import java.util.Properties;
  9. import java.util.Scanner;
  10. @Component
  11. public class UserLogProducer {
  12. @Autowired
  13. private KafkaTemplate kafkaTemplate;
  14. /**
  15. * 发送数据
  16. * @param topic
  17. */
  18. public void sendLog(String topic,String msg){
  19. Properties props = new Properties();
  20. props.put("bootstrap.servers", "localhost:9092");
  21. props.put("acks", "all");
  22. props.put("retries", 0);
  23. props.put("batch.size", 16384);
  24. props.put("linger.ms", 1);
  25. props.put("buffer.memory", 33554432);
  26. props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
  27. props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
  28. Producer<String, String> producer = new KafkaProducer<>(props);
  29. producer.send(new ProducerRecord<String, String>(topic, msg));
  30. producer.close();
  31. }
  32. public static void main(String[] args) {
  33. Scanner sc=new Scanner(System.in);
  34. UserLogProducer producer=new UserLogProducer();
  35. String s="";
  36. do {
  37. s=sc.nextLine();
  38. producer.sendLog("countin",s);
  39. }while(s!="n"||"n".equals(s));
  40. }
  41. }

3.6 启动三个类,并启动Kafka管理工具进行查看效果

在UserLogProducer的控制台中输入消息,在Kafka管理工具上进行查看效果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/590914
推荐阅读
相关标签
  

闽ICP备14008679号