Kafka 应用

1、命令行工具

Kafka 中提供了许多命令行工具(位于$KAFKA_HOME/bin 目录下)用于管理集群的变更。

脚本名称释义
kafka-configs.sh用于配置管理,在4.1.5节和4.3.3节中有所提及
kafka-console-consumer.sh用于消费消息,在1.3节和7.3节中有所提及
kafka-console-producer.sh用于生产消息,在1.3节中有所提及
kafka-consumer-perf-test.sh用于测试消费性能,在4.4.1节中有所提及
kafka-topics.sh用于管理主题,在第4章中有所提及
kafka-dump-log.sh用于查看日志内容,在5.2.5节中有所提及
kafka-server-stop.sh用于关闭Kafka服务, 在6.4.2节中有所提及
kafka-preferred-replica-election.sh用于优先副本的选举,在4.3.1节中有所提及
kafka-server-start.sh用于启动Kafka服务, 在1.2节和10.1节中有所提及
kafka-producer-perf-test.sh用于测试生产性能,在4.4.1节中有所提及
kafka-reassign-partitions.sh用于分区重分配,在4.3.2节中有所提及

2、Kafka Connect

Kafka Connect是一个工具, 它为在Kafka和外部数据存储系统之间移动数据提供了一种可靠的且可伸缩的实现方式。Kafka Connect可以简单快捷地将数据从Kafka中导入或导出, 数据范围涵盖关系型数据库、日志和度量数据、Had oop和数据仓库、No SQL数据存储、搜索索引等。相对于生产者和消费者客户端而言, Kafka Connect省掉了很多开发的工作, 尤其是编码部分,这使得应用开发人员更容易上手。

Kafka Connect有两个核心概念:Source和Sink。参考图9-1, Source负责导入数据到Kafka,
Sink负责从Kafka导出数据, 它们都被称为Connector(连接器)。
在这里插入图片描述

在Kafka Connect中还有两个重要的概念:Task和Worker。Task是Kafka Connect数据模型的主角, 每一个Connector都会协调一系列的Task去执行任务, Connector可以把一项工作分割成许多Task, 然后把Task分发到各个Worker进程中去执行(分布式模式下) , Task不保存自己的状态信息, 而是交给特定的Kafka主题去保存。Connector和Task都是逻辑工作单位, 必须安排在进程中执行, 而在Kafka Connect中, 这些进程就是Worker。
Kafka Connect提供了以下特性。

  • 通用性:规范化其他数据系统与Kafka的集成, 简化了连接器的开发、部署和管理。
  • 支持独立模式(standalone) 和分布式模式(distributed)
  • REST接口:使用REST API提交和管理Connector。
  • 自动位移管理:自动管理位移提交,不需要开发人员干预,降低了开发成本。
  • 分布式和可扩展性:Kafka Connect基于现有的组管理协议来实现扩展Kafka Connect集群。
  • 流式计算/批处理的集成。

2.1、独立模式

Kafka中的connect-standalone.sh脚本用来实现以独立的模式运行Kafka Connect。在独立模式下所有的操作都是在一个进程中完成的,这种模式非常适合测试或功能验证的场景。由于是单进程, 所以独立模式无法充分利用Kafka自身所提供的负载均衡和高容错等特性。

在执行这个脚本时需要指定两个配置文件:一个是用于Worker进程运行的相关配置文件;另一个是指定Source连接器或Sink连接器的配置文件, 可以同时指定多个连接器配置, 每个连接器配置文件对应一个连接器, 因此要保证连接器名称全局唯一, 连接器名称通过name参数指定。

下面我们先来了解一下Source连接器的用法:将文件source.txt中的内容通过Source连接器写入Kafka的主题topic-connect。首先修改用于Worker进程运行的配置文件($KAFKA_HOME/config/connect-standalone.properties) , 内容参考如下:

bootstrap.servers=localhost:9092
key.converter=org.apache.kafka.connect.json.Json.Converter
value.converter=org.apache.kafka.connect.json.Json.Converter
key.converter.schemas.enable=true
value.converter.schemas.enable=true
offset.storage.file.filename=/tmp/connect.offsets
offset.flush.interval.ms= 10000

bootstrap.servers参数用来配置与Kafka集群连接的地址。key.converter和value.converter参数指定Kafka消息中key和value的格式转化类, 本例中使用JsonConverter来将每一条消息的key和value都转化成JSON格式。key.converter.schemas.enable和value.converter.schemas.enable参数用来指定JSON消息中是否可以包含schema。offset.storage.file.filename参数用于指定保存偏移量的文件路径。offset.flush.interval.ms参数用于设定提交偏移量的频率。

接下来修改Source连接器的配置文件($KAFKA_HOME/confg/connect-file-source.properties) ,内容参考如下:

name=local-file-source
connector.class=FileStream Source
tasks.max=1
file=/opt/kafka 2.11-2.0.0/source.txt
topic=topic-connect

name参数用来配置连接器的名称。connector.class用来设置连接器类的全限定名称,有时候设置为类名也是可以的, Kafka Connect会在classpath中自动搜索这个类并加载。Kafka中默认只提供了与文件相关的连接器,如果要实现与其他数据存储系统相连接,那么可以参考文件连接器的具体实现来自定义一套连接器, 或者搜寻开源的实现, 比如Confluent公司提供的一些产品:
kafka-connect-elasticsearch(https://github.com/confluentinc/kafka-connect-elasticsearch) ;
kafka-connect-jdbc(https://github.com/confluentinc/kafka-connect-jdbc) ;
kafka-connect-hdfs(https://github.com/confluentinc/kafka-connect-hdfs) ;
kafka-connect-storage-cloud(https://github.com/confluentinc/kafka-connect-storage-cloud) 。

task.max参数指定了Task的数量。file参数指定该连接器数据源文件路径, 这里指定了Kafka根目录下的source.txt文件, 在启动连接器前需要先创建好它。topic参数设置连接器把数据导入哪个主题,如果该主题不存在,则连接器会自动创建,不过建议最好还是提前手工创建该主题。比如, 对本例中的主题topic-connect而言, 可以事先创建, 它的详细信息如下:

bin/kafka-topics.sh --zookeeper localhost:2181/kafka200 --create --topic topic-connect --replication-factor 1 --partitions 1
bin/kafka-topics.sh --zookeeper localhost:2181/kafka200 --describe --toppic topic-connect

接下来就可以启动Source连接器了, 示例如下:

bin/connect-standalone.sh config/connect-standalone.properties config/connect-file-source.properties

连接器启动之后, 向source.txt文件中输入两条句子:

echo ”hello kafka connect” > source.txt
echo ”hello kafka streams” > source.txt

之后可以观察主题topic-connect中是否包含这两条消息。对于这个示例, 我们既可以使用kafka-console-consumer.sh脚本, 也可以使用kafka-dump-log.sh脚本来查看内容。这里再来回顾一下kafka-dump-log.sh脚本的用法:

bin/kafka-dump-log.sh --files /tmp/kafka-logs/topic-connect-000000000000000000000.log --print-data-log

在这里插入图片描述
可以看到主题topic-connect中的消息格式为JSON字符串并且带有对应的schema信息, 这一点和在config/connect-standalone.properties配置的内容一一对应。

我们再来看一下Sink连接器的用法:将主题topic-connect中的内容通过Sink连接器写入文件sink.txt。这里对config/connect-standalone.properties文件稍做修改, 参考如下:

bootstrap.servers=localhost:9092
key.converter=org.apache.kafka.connect.storage.String Converter
value.converter=org.apache.kafka.connect.storage.String Converter
key.converter.schemas.enable=true
value.converter.schemas.enable=true
offset.storage.file.filename=/tmp/connect.offsets
offset.flush.interval.ms=10000

这里将Kafka消息中的key和value的格式转化类指定为StringConverter。
紧接着我们再配置Sink连接器的配置文件($KAFKA_HOME/config/sink.properties) , 内容参考如下(注意与Source连接器配置的区别)

name=local-file-sink
connector.class=FileStreamSink
tasks.max= 1
file=/opt/kafka_2.11-2.0.0/sink.txt
topics=topic-connect

接下来就可以启动Sink连接器了, 示例如下:

bin/connect-standalone.sh config/connect-standalone.properties config/connect-file-sink.properties

我们往主题topic-connect中发送一条消息:

bin/kafka-console-producer.sh --broker-list localhost:9092 --topic topic-connect
>hello kafka 
>

进而就可以在 ink.txt 文件中看到这条消息:

#cat sink.txt
hello kafka

2.2、 REST API

我们可以通过Kafka Connect提供的基于REST风格的API接口来管理连接器, 默认端口号为8083, 可以通过Worker进程的配置文件中的rest.port参数来修改端口号。Kafka Connect REST API接口如表9-2所示。
表9-2 Kafka Connect REST API接口

REST API释义
GET /查看Kafka集群版本信息
GET /connectors查看当前活跃的连接器列表,显示连接器的名字
POST /connectors根据指定配置,创建一个新的连接器
GET /connectors/{name}查看指定连接器的信息
GET /connectors/{name}/config查看指定连接器的配置信息
PUT /connectors/{name}/config修改指定连接器的配置信息
GET /connectors/{name}/statue查看指定连接器的状态
POST /connectors/{name}/restart重启指定的连接器
PUT /connectors/{name}/pause暂停指定的连接器
GET /connectors/{name}/tasks查看指定连接器正在运行的Task
POST /connectors/{name}/tasks修改Task的配置
GET /connectors/{name}/tasks/{taskId} /status查看指定连接器中指定Task的状态
POST /connectors/{name}/tasks/{tasked}/restart重启指定连接器中指定的Task
DELETE /connectors/{name}删除指定的连接器

2.3、分布式模式

与独立模式不同, 分布式模式天然地结合了Kafka提供的负载均衡和故障转移功能, 能够自动在多个节点机器上平衡负载。不过,以分布式模式启动的连接器并不支持在启动时通过加载连接器配置文件来创建一个连接器, 只能通过访问REST API来创建连接器。

在运行分布式模式的连接器前, 同样要修改Worker进程的相关配置文件($KAFKA_HOME/config/connect-distributed.properties) , 内容参考如下:

bootstrap.servers=localhost1:9092,localhost2:9092,localhost3:9092
group.id=connect-cluster
key.converter=org.apache.kafka.connect.json.JsonConverter
value.converter=org.apache.kafka.connect.json.JsonConverter
(....省略若干)

之后启动分布式模式, 这里的运行脚本也变成了对应的connect-distributed.sh, 示例如下:

bin/connect-distributed.sh config/connect-distributed.properties

接下来创建一个Source连接器, 此前先要设定好这个连接器的相关配置, 内容如下:

{
    "name":"local-file-distribute-source",
    "config":{
        "topic":"topic-distribute-source",
        "connector.class":"FileStreamSource",
        "key.converter":"org.apache.kafka.connect.storage.StringConverter",
        "value.converter":"org.apache.kafka.connect.storage.StringConverter",
        "converter.internal.key.converter":"org.apache.kafka.connect.storage.StringConverter",
        "converter.internal.value.converter":"org.apache.kafka.connect.storage.StringConverter",
        "file":"/opt/kafka_2.11-2.0.0/distribute-source.txt"
    }
}

这个连接器从distribute-source.txt文件中读取内容进而传输到主题topic-distribute-source中,
在创建连接器前确保distribute-source.txt文件和主题topic-distribute-source都已创建完毕。接下
来调用POST /connectors接口来创建指定的连接器, 示例如下:
在这里插入图片描述
接下来就可以向 distribut-source.txt 文件中写入内容,然后订阅消费主题 topic-distribute-source 中的消息来验证是否成功。在使用完毕之后,我们可以调用 DELETE /connectors/
{name}接口来删除对应的连接器

curl - i -X DELETE http://localht:8083/connectors/local-file-distribute-source

在向Kafka写入数据或从Kafka读取数据时, 要么使用普通的生产者和消费者客户端, 要么使用Kafka Connect, 那么在不同场景下到底使用哪一种呢?Kafka客户端需要内嵌到业务应用程序里, 应用程序需要经常修改以便灵活地将数据推送到Kafka或从Kafka中消费消息, 适用于开发人员。如果要将Kafka连接到数据存储系统中, 可以使用Kafka Connect, 因为在这种场景下往往也不需要修改对应的代码,适用于非开发人员,他们可以通过配置连接器的方式实现相应的功能。

3、Kafka Mirror Maker

Kafka Mirror Maker是用于在两个集群之间同步数据的一个工具, 其实现原理是通过从源集群中消费消息,然后将消息生产到目标集群中,也就是普通的生产和消费消息。如果了解Rabbit MQ, 那么会发现这个工具和Rabbit MQ中的数据迁移插件Federation/Shovel的实现原理如出一辙。用户只需要在启动Kafka Mirror Maker时指定一些简单的消费端和生产端配置就可以实现准实时的数据同步。

如图9-2所示, 我们需要将集群Cluster 1中的消息同步到集群Cluster 2中。通过Kafka Mirror Maker做一个中间的周转站, 我们就可以很容易地实现跨集群的数据同步。

在9.2节中, 我们了解了Kafka Connect的相关用法, 它和Kafka Mirror Maker的区别在于:
Kafka Connect用于其他数据存储系统与Kafka之间的数据复制, 而不是Kafka与Kafka之间的数据复制。在4.3.2节中, 分区重分配可以实现Kafka与Kafka之间的数据复制, 它与Kafka Mirror
Maker的区别在于它是单个集群内部的数据复制, 而不是跨集群之间的数据复制。
在这里插入图片描述
Kafka Mirror Maker可以在两个不同的数据中心(两个集群位于不同的数据中心) 中同步(镜像)数据。我们可以在两个不同的数据中心中部署一个集群,各个数据中心持有集群中的部分broker节点, 通过将副本分散到不同的数据中心来实现不同数据中心的数据同步。但这样有一个严重的问题, 即高延迟, 这个问题会严重影响Kafka和ZooKeeper的性能, 还有可能引发严重的异常。

下面我们来了解一下Kafka Mirror Maker的用法, 它具体对应Kafka中的kafka-mirror-maker.sh脚本。参考图9-2, 我们演示从Cluster 1中将主题topic-mirror的数据同步到Cluster 2中, 首先
创建并配置两个配置文件,参考如下:
#consumer.properties的配置
bootstrap.servers=cluster1:9092
group.id=groupId Mirror
client.id=source Mirror
partition.assignment. strategy=org.apache.kafka.clients.consumer.RoundRobinAssignor

#producer.properties的配置
bootstrap.servers=cluster2:9092
client.id=sink Mirror

consumer.properties和producer.properties这两个配置文件中的配置对应消费者客户端和生产者客户端的配置,具体可以参考第2章和第3章的内容。
下面就可以启动Kafka Mirror Maker了, 参考如下:

bin/kafka-mirror-maker.sh --consumer.config consumer.properties --producer.config producer.properties --whitelist 'topic-mirror'

kafka-mirror-maker.sh脚本中有多个可配置的参数, 如表9-3所示。
表9-3 kafka-mirror-maker.sh脚本的参数列表

参数释义
abort.on.send.failure默认为true
consumer.config用于指定消费者的配置文件, 配置文件里有两个必填的参数:boostrap.servers和group.id
consumer.rebalance.listener指定再均衡监听器,可以参考3.2.8节再均衡
help打印帮助信息
message.handler指定消息的处理器。这个处理器会在消费者消费到消息之后且在生产者发送消息之前被调用
message.handler.args指定消息处理器的参数, 同message.handler一起使用
num.streams指定消费线程的数量
offset.commit.interval.ms指定消费位移提交间隔
producer.config用于指定生产者的配置文件, 配置文件里唯一必填的参数是bootstrap.servers
rebalance.listener.args指定再均衡监听器的参数, 同consumer.rebalance.listener一起使用
whitelist指定需要复制的源集群中的主题。这个参数可以指定一个正则表达式,比如a

注意, 不要在单个集群的内部使用Kafka Mirror Maker, 否则会循环复制。如果在配置文件consumer.properties中配置的bootstrap.servers和在配置文件producer.properties中配置的bootstrap.servers的broker节点地址列表属于同一个集群, 启动Kafka Mirror Maker之后,只要往主题topic-mirror中输入一条数据, 那么这条数据会在这个主题内部无限循环复制, 直至Kafka Mirror Maker关闭。

由于kafka-mirror-maker.sh脚本是启动一个生生产者和一个消费者进行数据同步操作的,因此数据同步完成后,该命令依然在等待新的数据进行同步,也就是需要用户自己查看数据是否同步完成,在保证数据同步完成后手动关闭该命令。同时,用户可以在目标集群中创建主题,主题的分区数及副本因子可以与源集群中该主题对应的分区数及副本因子不一致。可以将目标集群中的auto.create.topics.enable参数配置为true, 以确保在同步操作时有对应的主题,不过建议在同步之前先确认是否有相关的主题,如果没有则手工创建,或者采用自定义的元数据同步工具进行创建。

源集群和目标集群是两个完全独立的实体。对每个主题而言,两个集群之间的分区数可能不同;就算分区数相同,那么经过消费再生产之后消息所规划到的分区号也有可能不同;就算分区数相同,消息所规划到的分区号也相同,那么消息所对应的offset也有可能不相同。参考图9-3,源集群中由于执行了某次日志清理操作,某个分区的logStartOffset值变为10,而目标集群中对应分区的logStartOffset还是0,那么从源集群中原封不动地复制到目标集群时,同一条消息的offset也不会相同。如果要实现客户端生产消费的迁移(将通信链路从源集群中切换到目标集群中),在数据同步完成之后,也不可能不做任何改变就能实现完美的切换。不过,如果能够做到源集群中的消息除offset外都在目标集群中一致(比如消息的分区号相同, 主题的分区数相同) , 那么可以试着通过kafka-consumer-group.sh脚本重置消费位移(参考9.1.2节)来实现合理的客户端迁移切换。或者先将生产者的链路切换到目标集群,然后等待消费者消费完源集群中的消息之后再将它的链路切换到目标集群。
在这里插入图片描述
kafka-mirror-maker.sh脚本对应的实现类是kafka.tools.MirrorMaker,它只有500多行代码,很多时候我们会把它与同类产品u Replicator进行对比, 笔者觉得这样有失稳妥, 前者的定位只是一个工具,而后者是一个完备的工程项目,它们都有各自的适用场景。不过话又说回来,uReplicator底层也是基于Mirror Maker进行构建的, 并针对Mirror Maker做了大量的调优及工程化改造,具体的内容可以参考官网介绍:http://eng.uber.com/ureplicator/。

4、Kafka Streams

Kafka一直被认为是一个强大的消息中间件, 它实现了高吞吐、高可用和低延时的消息传输能力, 这让它成为流式处理系统中完美的数据来源。目前通用的一些流式处理框架如Apache Spark、Apache F link、Apache Storm等都可以将Kafka作为可靠的数据来源。但遗憾的是, 在0.10.x版本之前, Kafka还并不具备任何数据处理的能力, 但在此之后, Kafka Streams应运而生。

Kafka Streams是一个用于处理和分析数据的客户端库。它先把存储在Kafka中的数据进行处理和分析, 然后将最终所得的数据结果回写到Kafka或发送到外部系统。它建立在一些非常重要的流式处理概念之上,例如适当区分事件时间和处理时间、窗口支持,以及应用程序状态的简单(高效) 管理。同时, 它也基于Kafka中的许多概念, 例如通过划分主题进行扩展。此外,由于这个原因,它作为一个轻量级的库可以集成到应用程序中。这个应用程序可以根据需要独立运行、在应用程序服务器中运行、作为Docker容器, 或者通过资源管理器(如Mesos)进行操作。

Kafka Streams直接解决了流式处理中的很多问题:

  • 毫秒级延迟的逐个事件处理。
  • 有状态的处理, 包括连接(join) 和聚合类操作。
  • 提供了必要的流处理原语, 包括高级流处理DSL和低级处理器API。高级流处理DSL提供了常用流处理变换操作, 低级处理器API支持客户端自定义处理器并与状态仓库交互。
  • 使用类似DataFlow的模型对无序数据进行窗口化处理。
  • 具有快速故障切换的分布式处理和容错能力。
  • 无停机滚动部署。

单词统计是流式处理领域中最常见的示例, 这里我们同样使用它来演示一下Kafka Streams的用法。在Kafka的代码中就包含了一个单词统计的示例程序, 即org.apache.kafka.streams.examples.wordcount.WordCountDemo, 这个示例中以硬编码的形式用到了两个主题:streams-plaintext input和streams-wordcount-output。为了能够使示例程序正常运行, 我们需要预先准备好这两个主题,这两个主题的详细信息如下:
在这里插入图片描述
之后我们就可以运行 WordCountDemo 这个示例了:

bin/kafka-run-class.sh org.apache.kafka.streams.examples.wordcount.WordCountDemo

这个示例程序将从主题 streams aintext-input 中读取消息,然后对读取的消息执行单词统
计,并将结果持续 入主题 streams-wordcount-output。

之后打开一个 shell 终端,井启动一个生产者来为主题 streams-plaintext-input 输入一些单词,
示例如下:

bin/kafka-console-producer.sh --broker-list localhost:9092 --topic streams-plaintext-input 
>

之后再打开另一个 shell 终端 并启动一个消费者来消费主题 streams-wordcount-output中的
消息,示例如下:

bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic streams-wordcount-output --property print.key=true --property value.deserializer=org.apache.kafka.common.seralizationLogDeserializer

现在我们往主题 streams-plaintext-input 中输入 hello kafka streams:

bin/kafka-console-producer.sh --broker-list localhost:9092 --topic streams-plaintext-input 
>hello kafka streams

通过 WordCountDemo 处理之后会在消费端看到如下的结果:

bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic streams- wordcount-output --property print.key=true --property value.deserializer=org.apache.kafka.common.serialization.LongDeserializer
hello 1 
kafka 1 
streams 1

输出结果中的第一列是消息的key, 这里表示被计数的单词, 第二列是消息的value, 这里表示该单词的最新计数。

现在继续往主题streams-plaintext-input中输入I love kafka streams,然后会在消费端看到有新的消息输出:
I l
love 1
kafka 2
streams 2

最后2行打印的kafka 2和streams 2表示计数已经从1递增到2。每当向输入主题(streams-plaintext-input) 中写入更多的单词时, 将观察到新的消息被添加到输出主题(streams-wordcount-output) 中, 表示由WordCount应程序用程序计算出的最新计数。

下面我们通过WordCountDemo程序来了解一下Kafka Streams的开发方式, WordCountDemo如代码清单9-2所示, 对应的Maven依赖如下所示。

<dependency>
	<groupId>org.apache.kafka</groupId>
	<artifactId>kafka-streams</artifactId>
	<version>2.0.0</version>
</dependency>

代码清单9-2单词统计示例
在这里插入图片描述
第①行用于 Kafka Stream 的配置,每个 Kafka Streams 应用程序必须要有一个application.id(StreamsConfig.APPLICATION_ID_CONFIG) , 这个applicationId用于协调应用实例, 也用于命名内部的本地存储和相关主题。在整个Kafka集群中, applicationId必须是唯一的。bootstrap.servers参数配置的是Kafka集群的地址, 这个参数也是必需的。default.key.serde和default.value.serde分别用来设置消息的key和value的序列化器。

第②行创建了一个KStreamBuilder实例, 在第③行中通过调用KStreamBuilder实例的stream()方法创建了一个KStream实例, 并设定了输入主题streams-plaintext-input。

之后在第④行中执行具体的单词统计逻辑。注意这里引入了K Stream和K Table的概念, 它们是KafkaStreams的两种基本抽象。两者的区别在于:KStream是一个由键值对构成的抽象记录流, 每个键值对是一个独立单元, 即使相同的key也不会被覆盖, 类似数据库的插入操作;KTable可以理解成一个基于表主键的日志更新流, 相同key的每条记录只保存最新的一条记录,类似数据库中基于主键的更新。

无论记录流(用KStream定义) , 还是更新日志流(用KTable定义) , 都可以从一个或多个Kafka主题数据源来创建。一个K Stream可以与另一个K Stream或K Table进行Join操作,或者聚合成一个KTable。同样,一个KTable也可以转换成一个KStream。KStream和KTable都提供了一系列转换操作, 每个转换操作都可以转化为一个K Stream或K Table对象, 将这些转换操作连接在一起就构成了一个处理器拓扑。

第⑤行中调用toStream() .to() 来将单词统计的结果写入输出主题streams-wordcount-output。注意计算结果中的消息的key是String类型, 而value是Long类型, 这一点在代码中有所呈现。

最终在第⑥和第⑧行中基于拓扑和配置来订阅一个KafkaStreams对象, 并启动KafkaStreams引擎。整体上而言, KafkaStreams的程序简单易用, 用户只需关心流处理转换的具体逻辑而不需要关心底层的存储等细节内容。

本节只是简单地介绍一下KafkaStreams, 让读者对KafkaStreams有一个大致的概念。目前流式处理领域还是Apache Spark和Apache F link的天下, 其中Apache Spark的市场份额占有率最大, 在第12章中我们会详细介绍Apache Spark(包括Spark Streaming和Structured Streaming) ,以及它和Kafka的整合应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值