浅析Kafka-Stream消息流式处理流程及原理

以下结合案例:统计消息中单词出现次数,来测试并说明kafka消息流式处理的执行流程

Maven依赖

    <dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-streams</artifactId><exclusions><exclusion><artifactId>connect-json</artifactId><groupId>org.apache.kafka</groupId></exclusion><exclusion><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId></dependency></dependencies>

准备工作

首先编写创建三个类,分别作为消息生产者、消息消费者、流式处理者
KafkaStreamProducer:消息生产者

public class KafkaStreamProducer {public static void main(String[] args) throws ExecutionException, InterruptedException {Properties properties = new Properties();//kafka的连接地址properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.246.128:9092");//发送失败,失败的重试次数properties.put(ProducerConfig.RETRIES_CONFIG, 5);//消息key的序列化器properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");//消息value的序列化器properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");KafkaProducer<String, String> producer = new KafkaProducer<>(properties);for (int i = 0; i < 5; i++) {ProducerRecord<String, String> producerRecord = new ProducerRecord<>("kafka-stream-topic-input", "hello kafka");producer.send(producerRecord);}producer.close();}
}

该消息生产者向主题kafka-stream-topic-input发送五次hello kafka
KafkaStreamConsumer:消息消费者

public class KafkaStreamConsumer {public static void main(String[] args) {Properties properties = new Properties();//kafka的连接地址properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.246.128:9092");//消费者组properties.put(ConsumerConfig.GROUP_ID_CONFIG, "group1");//消息的反序列化器properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");//手动提交偏移量properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);//订阅主题consumer.subscribe(Collections.singletonList("kafka-stream-topic-output"));try {while (true) {ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofMillis(1000));for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {System.out.println("consumerRecord.key() = " + consumerRecord.key());System.out.println("consumerRecord.value() = " + consumerRecord.value());}// 异步提交偏移量consumer.commitAsync();}} catch (Exception e) {e.printStackTrace();} finally {// 同步提交偏移量consumer.commitSync();}}
}

KafkaStreamQuickStart:流式处理类

public class KafkaStreamQuickStart {public static void main(String[] args) {Properties properties = new Properties();properties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.246.128:9092");properties.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());properties.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());properties.put(StreamsConfig.APPLICATION_ID_CONFIG, "streams-quickstart");StreamsBuilder streamsBuilder = new StreamsBuilder();//流式计算streamProcessor(streamsBuilder);KafkaStreams kafkaStreams = new KafkaStreams(streamsBuilder.build(), properties);kafkaStreams.start();}/*** 消息格式:hello world hello world* 配置并处理流数据。* 使用StreamsBuilder创建并配置KStream,对输入的主题中的数据进行处理,然后将处理结果发送到输出主题。* 具体处理包括:分割每个消息的值,按值分组,对每个分组在10秒的时间窗口内进行计数,然后将结果转换为KeyValue对并发送到输出主题。** @param streamsBuilder 用于构建KStream对象的StreamsBuilder。*/private static void streamProcessor(StreamsBuilder streamsBuilder) {// 从"kafka-stream-topic-input"主题中读取数据流KStream<String, String> stream = streamsBuilder.stream("kafka-stream-topic-input");System.out.println("stream = " + stream);// 将每个值按空格分割成数组,并将数组转换为列表,以扩展单个消息的值stream.flatMapValues((ValueMapper<String, Iterable<String>>) value -> {String[] valAry = value.split(" ");return Arrays.asList(valAry);})// 按消息的值进行分组,为后续的窗口化计数操作做准备.groupBy((key, value) -> value)// 定义10秒的时间窗口,在每个窗口内对每个分组进行计数.windowedBy(TimeWindows.of(Duration.ofSeconds(10))).count()// 将计数结果转换为流,以便进行进一步的处理和转换.toStream()// 显示键值对的内容,并将键和值转换为字符串格式.map((key, value) -> {System.out.println("key = " + key);System.out.println("value = " + value);return new KeyValue<>(key.key().toString(), value.toString());})// 将处理后的流数据发送到"kafka-stream-topic-output"主题.to("kafka-stream-topic-output");}}

该处理类首先从主题kafka-stream-topic-input中获取消息数据,经处理后发送到主题kafka-stream-topic-output中,再由消息消费者KafkaStreamConsumer进行消费

执行结果

在这里插入图片描述
在这里插入图片描述

流式处理流程及原理说明

初始阶段

当从输入主题kafka-stream-topic-input读取数据流时,每个消息都是一个键值对。假设输入消息的键是null或一个特定的字符串,这取决于消息是如何被发送到输入主题的。

KStream<String, String> stream = streamsBuilder.stream("kafka-stream-topic-input");

分割消息值

使用flatMapValues方法分割消息的值,但这个操作不会改变消息的键。如果输入消息的键是null,那么在这个阶段消息的键仍然是null

stream.flatMapValues((ValueMapper<String, Iterable<String>>) value -> {String[] valAry = value.split(" ");return Arrays.asList(valAry);
})

按消息的值进行分组

在 Kafka Streams 中,当使用groupBy方法对流进行分组时,实际上是在指定一个新的键,这个键将用于后续的窗口化操作和聚合操作。在这个案例中groupBy方法被用来按消息的值进行分组:

.groupBy((key, value) -> value)

这意味着在分组操作之后,流中的每个消息的键被设置为消息的值。因此,当你在后续的map方法中看到key参数时,这个key实际上是消息的原始值,因为在groupBy之后,消息的值已经变成了键。

定义时间窗口并计数

在这个阶段,消息被窗口化并计数,但是键保持不变。

.windowedBy(TimeWindows.of(Duration.ofSeconds(10)))
.count()

将计数结果转换为流

当将计数结果转换为流时,键仍然是之前分组时的键

.toStream()

处理和转换结果

map方法中,你看到的key参数实际上是分组后的键,也就是消息的原始值:

.map((key, value) -> {System.out.println("key = " + key);System.out.println("value = " + value);return new KeyValue<>(key.key().toString(), value.toString());
})

map方法中的key.key().toString()是为了获取键的字符串表示,而value.toString()是为了将计数值转换为字符串。

将处理后的数据发送到输出主题

.to("kafka-stream-topic-output");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/374949.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【密码学】大整数分解问题和离散对数问题

公钥密码体制的主要思想是通过一种非对称性&#xff0c;即正向计算简单&#xff0c;逆向计算复杂的加密算法设计&#xff0c;来解决安全通信。本文介绍两种在密码学领域内最为人所熟知、应用最为广泛的数学难题——大整数分解问题与离散对数问题 一、大整数分解问题 &#xf…

thinkphp 生成邀请推广二维码,保存到服务器并接口返回给前端

根据每个人生成自己的二维码图片,接口返回二维码图片地址 生成在服务器的二维码图片 控制器 public function createUserQRcode(){$uid = input(uid);if

传言称 iPhone 16 Pro 将支持 40W 快速充电和 20W MagSafe

目前&#xff0c;iPhone 15 和 iPhone 15 Pro 机型使用合适的 USB-C 电源适配器可实现高达 27W 的峰值充电速度&#xff0c;而 Apple 和授权第三方的官方 MagSafe 充电器可以高达 15W 的功率为 iPhone 15 机型进行无线充电。所有四款 iPhone 15 机型均可使用 20W 或更高功率的电…

FPGA学习笔记(一) FPGA最小系统

文章目录 前言一、FPGA最小系统总结 前言 今天学习下FPGA的最小系统一、FPGA最小系统 FPGA最小系统与STM32最小系统类似&#xff0c;由供电电源&#xff0c;时钟电路晶振&#xff0c;复位和调试接口JTAG以及FLASH配置芯片组成&#xff0c;其与STM32最大的不同之处就是必须要有…

Appium自动化测试系列: 2. 使用Appium启动APP(真机)

历史文章&#xff1a;Appium自动化测试系列: 1. Mac安装配置Appium_mac安装appium-CSDN博客 一、准备工作 1. 安卓测试机打开调试模式&#xff0c;然后使用可以传输数据的数据线连接上你的电脑。注意&#xff1a;你的数据线一定要支持传输数据&#xff0c;有的数据线只支持充…

《数据结构:C语言实现顺序表》

文章目录 一、顺序表1、静态顺序表2、动态顺序表 二、动态顺序表实现1、创建自定义类型2、完成顺序表的创建&#xff0c;测试功能需求3、完成顺序表的初始化和销毁功能4、顺序表插入数据和打印数据5、删除数据 三、顺序表完成最终的代码test.c文件中的代码&#xff1a;用来测试…

新手教学系列——MongoDB聚合查询的进阶用法

引言 MongoDB的聚合查询是其最强大的功能之一。无论是汇总、平均值、计数等标准操作,还是处理复杂的数据集合,MongoDB的聚合框架都能提供高效且灵活的解决方案。本文将通过几个实例,详细讲解如何在实际项目中使用MongoDB进行聚合查询。 标准应用:汇总、平均值、计数等 在…

k8s集群部署mysql8主备

一、搜索mysql8版本 # helm search repo mysql# helm pull bitnami/mysql --version:11.1.2# tar -zxf mysql-11.1.2.tgz# cd mysql 二、修改value.ysqml文件 动态存储类自己提前搭建。 # helm install mysql8 -n mysql-cluster ./ -f values.yaml NAME: mysql8 LAST DEPLOYED…

Neo4j安装

下载地址&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 1.安装jdk&#xff0c;Neo4j 3.0需要jdk8&#xff0c;2.3.0之前的版本建议jdk7。Neo4j最新版本5.21.2&#xff0c;对应jdk版本17 2.将下载的zip文件解压到合适路径。 3.设置环境变量NEO4J_H…

【机器学习】朴素贝叶斯算法详解与实战扩展

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 引言 朴素贝叶斯算法是一种基于概率统计的分类方法&#xff0c;它利用贝叶斯定理和特征条件独立假设来预测样本的类别。尽管其假设特征之间相互独立在现实中往往不成立&#xff0c;但朴素贝叶斯分类器因其计算…

卤味江湖中,周黑鸭究竟该抓住什么赛点?

近年来&#xff0c;卤味江湖的决斗从未停止。 随着休闲卤味、佐餐卤味等细分赛道逐渐形成&#xff0c;“卤味三巨头”&#xff08;周黑鸭、绝味食品、煌上煌&#xff09;的牌桌上有了更多新对手&#xff0c;赛道变挤了&#xff0c;“周黑鸭们”也到了转型关键期。 这个夏天&a…

linux系统操作/基本命令/vim/权限修改/用户建立

Linux的目录结构&#xff1a; 一&#xff1a;在Linux系统中&#xff0c;路径之间的层级关系&#xff0c;使用:/来表示 注意:1、开头的/表示根目录 2、后面的/表示层级关系 二&#xff1a;在windows系统中&#xff0c;路径之间的层级关系&#xff0c;使用:\来表示 注意:1、D:表示…

【web前端HTML+CSS+JS】--- JS学习笔记03

一、JS介绍 可以在前端页面上进行逻辑处理&#xff0c;来解决表单的验证等问题&#xff0c;提升效率&#xff0c;直接在前端提示问题&#xff0c;减少服务器压力 应用1&#xff1a;可以做静态验证和动态验证&#xff08;进行异步请求&#xff09; 应用2&#xff1a;可以解析后…

Postgresql - 用户权限数据库

1、综述 在实际的软件项目开发过程中&#xff0c;用户权限控制可以说是所有运营系统中必不可少的一个重点功能&#xff0c;根据业务的复杂度&#xff0c;设计的时候可深可浅&#xff0c;但无论怎么变化&#xff0c;设计的思路基本都是围绕着用户、部门、角色、菜单这几个部分展…

电脑数据恢复篇:如何从电脑中恢复已删除的照片

按下 Shift Delete 后后悔了&#xff1f;想要恢复已删除的照片&#xff1f;好吧&#xff0c;如果是这样的话&#xff0c;你来对地方了。在本文中&#xff0c;我们将讨论如何从 PC 中恢复已删除的文件。 自从摄影的概念被提出以来&#xff0c;人们就对它着迷。以前&#xff0c…

【SQL】DML、DDL、ROLLBACK 、COMMIT详解

DML DML&#xff08;Data Manipulation Language&#xff09;数据操作语言&#xff0c;是用于对数据库中的数据进行基本操作的一种编程语言。DML是数据库管理系统&#xff08;DBMS&#xff09;中的一个重要部分&#xff0c;它允许用户或应用程序对数据库中的数据进行增、删、改…

【鸿蒙学习笔记】文件管理

官方文档&#xff1a;Core File Kit简介 目录标题 文件分类什么是应用沙箱&#xff1f; 文件分类 应用文件&#xff0c;比如应用的安装包&#xff0c;自己的资源文件等。用户文件&#xff0c;比如用户自己的照片&#xff0c;录制的音视频等。 什么是应用沙箱&#xff1f; 应…

Socks5代理为何比HTTP代理快?

在网络世界中&#xff0c;代理服务器扮演着重要的角色&#xff0c;它们能够帮助我们访问被限制的网站、提高网络安全性以及优化网络性能。其中&#xff0c;Socks5代理和HTTP代理是两种常见的代理类型。然而&#xff0c;很多用户发现&#xff0c;相较于HTTP代理&#xff0c;Sock…

ctfshow-web入门-文件上传(web164、web165)图片二次渲染绕过

web164 和 web165 的利用点都是二次渲染&#xff0c;一个是 png&#xff0c;一个是 jpg 目录 1、web164 2、web165 二次渲染&#xff1a; 网站服务器会对上传的图片进行二次处理&#xff0c;对文件内容进行替换更新&#xff0c;根据原有图片生成一个新的图片&#xff0c;这样…

3D互动+AR试戴,赋能珠宝品牌线上营销!

随着电商浪潮的汹涌而至&#xff0c;珠宝这一传统上依赖实体店铺销售的行业&#xff0c;正积极拥抱线上转型的浪潮。然而&#xff0c;面对珠宝商品高客单价及消费者对于亲身体验的强烈需求&#xff0c;线上销售面临诸多挑战&#xff0c;尤其是图片展示难以全面展现珠宝魅力&…