kafka快速开始

点点圈 提交于 2019-11-28 20:11:42

一、kafka介绍

1. kafka基本认识

官网翻译:
介绍
Apache Kafka® is a distributed streaming platform. What exactly does that mean?
Apache Kafka®是一个分布式流平台。这到底是什么意思?

流平台有三个关键功能:

  • 发布和订阅记录流,类似于消息队列或企业消息系统。
  • 以容错、持久的方式存储记录流。
  • 处理流记录,当他们发生时。

卡夫卡通常用于两大类应用:

  • 构建实时流数据管道,在系统或应用程序之间可靠地获取数据
  • 构建对数据流进行转换或响应的实时流应用程序

总结:kafka 既从上游系统接收数据,也会给下游系统输送数据:既提供消息的流转服务,也用于数据的持久化存储。承接上下游子系统 。

1.1 kafka 4个核心API

[推荐]Kafka的API那么多,到底该怎么选?
参考URL: https://baijiahao.baidu.com/s?id=1617641679231240954&wfr=spider&for=pc

  • Producer API: 支持应用将数据流发送到Kafka集群的主题。
    应用程序直接生成数据(如点击流、日志、物联网);

  • Consumer API: API支持应用从Kafka集群的主题中读取数据流。
    Kafka Consumer API: 读取流并以此为依据实时执行动作(如发送电子邮件);

  • Streams API / KSQL: API支持数据流从输入主题转化到输出主题。
    流API允许应用程序充当流处理器,使用来自一个或多个主题的输入流,并将输出流生成到一个或多个输出主题,从而有效地将输入流转换为输出流。

Kafka Streams API / KSQL :从 Kafka 消费并把生成的数据传回 Kafka 的应用程序,也称为流处理。如果你认为你只需要编写类似 SQL 的实时任务,则可以使用 KSQL;如果你认为你需要编写复杂的任务逻辑,则可以使用 Kafka Streams API。

  • Connector API:
    连接器API允许构建和运行可重用的生产者或消费者,将Kafka主题连接到现有的应用程序或数据系统。例如,关系数据库的连接器可能捕获表的每个更改。
  1. Kafka Connect Source API: 应用程序连接我们无法控制的数据存储和 Kafka(如 CDC、Postgres、MongoDB、Twitter、REST API);

**Kafka Connect Source API 是一个构建在 Producer API 之上的完整框架。**它主要是为了让开发人员能够有一个更好的 API:1)用于 Producer 任务分发以进行并行处理,2)提供 Producer 恢复的简单机制。最后一个好处是提供了各种各样的连接器,你现在可以利用它们从大多数源传输数据,而无需编写一行代码。

  1. Kafka Connect Sink API: 读取流,并将其保存到目标存储(如 Kafka 到 S3、Kafka 到 HDFS、Kafka 到 PostgreSQL、Kafka 到 MongoDB 等)。

与 Kafka Connect Source API 类似,Kafka Connect Sink API 允许你利用现有的 Kafka 连接器生态系统来执行流 ETL,而无需编写一行代码。Kafka Connect Sink API 是构建在 Consumer API 之上的,但是看起来和它没有什么不同。

如果你想要进入流处理的世界,即实时读取来自 Kafka 的数据,并在处理之后将其写回 Kafka,那么,如果你把 Kafka Consumer API 和 Kafka Producer API 链接在一起使用的话,你很可能陷入麻烦之中。值得庆幸的是,Kafka 项目现在提供了 Kafka Streams API (可用于 Java 和 Scala),让你可以编写高级 DSL(类似于函数式编程 / Apache Spark 类型的程序)或低级 API(和 Apache Storm 更为相似)。使用 Kafka Streams API 确实需要编写代码,但完全隐藏了维护生产者和消费者的复杂性,使你可以专注于流处理器的逻辑。它还具有连接、聚合和只执行一次处理的特性。

总结: Kafka Connect是一种用于Kafka和其他数据系统之间进行数据传输的工具。Kafka connect有两个概念,一个source,另一个是sink。source是把数据从一个系统拷贝到kafka里,sink是从kafka拷贝到另一个系统里。

在Kafka中,客户机和服务器之间的通信是通过一个简单、高性能、语言无关的TCP协议来完成的。此协议已版本化,并保持与旧版本的向后兼容性。我们为卡夫卡提供Java客户端,但客户端可以用多种语言提供。

2. 各版本变化说明

版 本 功能变化 说 明
0.10.0.x 增加了 Kafka Streams 组件 自 0.10.0 版本开始, K且fka 正式转型成为分布式流式处理平台
1.0.0 优化了 Kafka Streams AP!以及各种监控指标的完善 自 l .0.0 版本开始, Kafka 正式进入到 1.0 稳定版本

2.1 不同 Kafka 版本之间服务器和客户端的适配性

kafka-broker-api-versions 脚本
这个脚本的主要目的是验证不同 Kafka 版本之间服务器和客户端的适配性。

如果你想了解你的客户端版本与服务器端版本的兼容性,那么最好使用这个命令来检验一下。值得注意的是,在 0.10.2.0 之前,Kafka 是单向兼容的,即高版本的 Broker 能够处理低版本 Client 发送的请求,反过来则不行。自 0.10.2.0 版本开始,Kafka 正式支持双向兼容,也就是说,低版本的 Broker 也能处理高版本 Client 的请求了

二、kafka入门

1. kafka基本术语概念

  • topic
    topic 只是一个逻辑概念,代表了一类消息,也可以认为是消息被发送到
    的地方。通常我们可以使用 topic 来区分实际业务,比如业务 A 使用一个 topic,业务 B 使用另外一个 topic 。
  • partition
    Kafka 并不是 topicmessage 的两级结构,而是采用了 topic-partition-message 的三级结构来分散负载。从本质上说 ,每个 Kafka topic 都由若干个 partition 组成。

Kafka 的 partition 是不可修改的有序消息序列,也可以说是
有序的消息日志。每个 partition 有自己专属的 partition 号,通常是从 0 开始的。用户对partition 唯一能做的操作就是在消息序列的尾部追加写入消息。 partition 上的每条消息都会被分配一个唯一的序列号一一按照 Kafka 的术语来讲,该序列号被称为位移( offset ) 该位移值是从 0 开始顺序递增的整数。位移信息可以唯一定位到某 partition 下的一条消息。

Kafka 的 partition 没有太多的业务含义,它的引入就是单纯地为了提升系统的吞吐量,因此在创建 Kafka topic 的时候可以根据集群实际配置设置具体的partition 数, 实现整体性能的最大化 。

  • offset
    topic partition 下的每条消息都被分配一个位移值。实际上 , Kafka 消费者端也有位移( offset)的概念,但一定要注意这两个 offset 属于不同的概念。
    在这里插入图片描述* replica
    partition 是有序消息日志,那么一定不能只保存这一份日志,否则一旦保
    存 partition 的 Kafka 服务器挂掉了,其上保存的消息也就都丢失了。分布式系统必然要实现高可靠性,而目前实现的主要途径还是依靠冗余机制一一简单地说,就是备份多份日志 。 这些备份日志在 Kafka 中被称为副本( replica ),它们存在的唯一目的就是防止数据丢失
  • leader 和 follower

Kafka 的 replica 分为两个角色:领导者( leader)和追随者( follower ) 。 如今
这种角色设定几乎完全取代了过去的主备的提法( Master-Slave )。和传统主备系统(比如MySQL )不同的是,在这类 leader-follower 系统中通常只有 leader 对外提供服务, fo llower 只是被动地追随 leader 的状态,保持与 leader 的同步。 follower 存在的唯一价值就是充当 leader的候补:一旦 leader 挂掉立即就会有一个追随者被选举成为新的 leader 接替它的工作。 Kafka就是这样的设计

**Kafka 保证同 一个 partition 的多个 replica 一定不会分配在同一台 broker 上 。**毕竟如果同一个 broker 上有同一个 partition 的多个 replica,那么将无法实现备份冗余的效果。

假设副本因子是3,Kafka会为每个分区创建3个副本并将它们放置在不同的broker上。

2. kafka消息设计

Kafka 在消息设计时特意避开了繁重的 Java 堆上内存分配,直接使用紧凑二进制字节
数组 ByteBuffer 而不是独立的对象,因此我们至少能够访问多一倍的可用内存。

如果使用 ByteBuffer 来保存同样的消息,只需要 24 字节,比起纯 Java 堆
的实现减少了 40%的空间占用,好处不言而喻。这种设计的好处还包括加入了扩展的可能性。
同时,大量使用页缓存而非堆内存还有一个好处一一当出现 Kafka broker 进程崩溃时,堆内存上的数据也一并消失,但页缓存的数据依然存在。下次 Kafka broker 重启后可以继续提供服务,不需要再单独“热”缓存了。

2.1 消息压缩

Kafka 是如何压缩消息的呢?要弄清楚这个问题,就要从 Kafka 的消息格式说起了。目前 Kafka 共有两大类消息格式,社区分别称之为 V1 版本和 V2 版本。V2 版本是 Kafka 0.11.0.0 中正式引入的。

V2 版本的做法是对整个消息集合进行压缩。
在 Kafka 中,压缩可能发生在两个地方:生产者端和 Broker 端。

生产者程序中配置 compression.type 参数即表示启用指定类型的压缩算法。

Producer 启动后生产的每个消息集合都是经 GZIP 压缩过的,故而能很好地节省网络传输带宽以及 Kafka Broker 端的磁盘占用。

在一个生产环境中,Kafka 集群中同时保存多种版本的消息格式(V1版本、V2 版本)非常常见。为了兼容老版本的格式,Broker 端会对新版本消息执行向老版本格式的转换。这个过程中会涉及消息的解压缩和重新压缩。一般情况下这种消息格式转换对性能是有很大影响的,除了这里的压缩之外,它还让 Kafka 丧失了引以为豪的 Zero Copy 特性。

在 Kafka 2.1.0 版本之前,Kafka 支持 3 种压缩算法:GZIP、Snappy 和 LZ4。从 2.1.0 开始,Kafka 正式支持 Zstandard 算法(简写为 zstd)。它是 Facebook 开源的一个压缩算法,能够提供超高的压缩比(compression ratio)。

三、kafka connect

基于Kafka Connect的应用实践——打造实时数据集成平台
参考URL: https://cloud.tencent.com/developer/news/217133
kafka connect
参考URL: https://blog.csdn.net/helihongzhizhuo/article/details/80335931

Kafka是一个使用越来越广的消息系统,尤其是在大数据开发中(实时数据处理和分析)。为何集成其他系统和解耦应用,经常使用Producer来发送消息到Broker,并使用Consumer来消费Broker中的消息。Kafka Connect是到0.9版本才提供的并极大的简化了其他系统与Kafka的集成。Kafka Connect运用用户快速定义并实现各种Connector(File,Jdbc,Hdfs等),这些功能让大批量数据导入/导出Kafka很方便。

在这里插入图片描述
(图片来自Confluent官网)

1. Kafka Connect的应用

基于Kafka Connect的应用实践——打造实时数据集成平台
参考URL: https://cloud.tencent.com/developer/news/217133

2. Kafka Connect 组件的启动脚本

connect-standalone 和 connect-distributed 两个脚本。

Kafka Connect 支持单节点的 Standalone 模式,也支持多节点的 Distributed 模式。这两个脚本分别是这两种模式下的启动脚本。

四、 Kafka Streams

Kafka Streams
参考URL: https://www.orchome.com/335

随着 Kafka 的不断演进, Kafka 开发团队日益发现经
Kafka 交由下游数据处理平台做的事情 Kafka 自己也可以做,因此在 Kafka 0.10.0.0 版本正式推出了 Kafka Streams,即流式处理组件 。自 此 Kafka 正式成为了 一个流式处理框架,而不仅仅是消息引擎了。

Kafka Streams是一个客户端程序库,用于处理和分析存储在Kafka中的数据,并将得到的数据写回Kafka或发送到外部系统。Kafka Stream基于一个重要的流处理概念。

Kafka Streams 擅长的是从 Kafka topic 中获取输入数据,然后对这些数据进行转换,最后发送到目标 topic 中。

1. 什么是流式计算

一般流式计算会与批量计算相比较。在流式计算模型中,输入是持续的,可以认为在时间上是无界的,也就意味着,永远拿不到全量数据去做计算。同时,计算结果是持续输出的,也即计算结果在时间上也是无界的。流式计算一般对实时性要求较高,同时一般是先定义目标计算,然后数据到来之后将计算逻辑应用于数据。同时为了提高计算效率,往往尽可能采用增量计算代替全量计算。

批量处理模型中,一般先有全量数据集,然后定义计算逻辑,并将计算应用于全量数据。特点是全量计算,并且计算结果一次性全量输出。
在这里插入图片描述(1) 与批量计算那样慢慢积累数据不同,流式计算将大量数据平摊到每个时间点上,连续地进行小批量的进行传输,数据持续流动,计算完之后就丢弃。

(2) 批量计算是维护一张表,对表进行实施各种计算逻辑。流式计算相反,是必须先定义好计算逻辑,提交到流失计算系统,这个计算作业逻辑在整个运行期间是不可更改的。

(3) 计算结果上,批量计算对全部数据进行计算后传输结果,流式计算是每次小批量计算后,结果可以立刻投递到在线系统,做到实时化展现。

2. 关键概念

是Kafka Stream提出的最重要的抽象概念:**它表示一个无限的,不断更新的数据集。**流是一个有序的,可重放(反复的使用),不可变的容错序列,数据记录的格式是键值对(key-value)。

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

时间在流中的常见概念如下:

  • 事件时间 - 消息生产时间,CreateTime,producer创建消息的时间
    当一个事件或数据记录发生的时间点,就是最初创建的“源头”。

  • 处理时间 - 消息消费时间,consumer消费消息的时间
    事件或数据消息发生在流处理应用程序处理的时间点。即,记录已被消费。处理时间可能是毫秒,小时,或天等。比原始事件时间要晚。

  • 摄取时间 - 消息保存时间,LogAppendTime,leader broker把消息保存到topic分区(写入到log)的时间

五、kafka环境搭建

  1. 安装启动zookeeper
  2. 官网下载kafka http://kafka.apache.org/downloads.html
    下载的版本已经编译,直接解压到想要的目录就算安装好了
tar -zxvf kafka_2.12-2.3.0.tgz
  1. 配置单结点kafka
vim conf/server.properties

server.properties重要参数说明:

  • broker.id=0//This must be set to a unique integer for each broker
  • advertised.listeners=PLAINTEXT://192.168.0.108:9092:远程连接需要配置下(0.9.0.1版本没有这个问题)
  • log.dirs=/usr/local/kafka_2.11-0.9.0.1/kafka-logs//默认的是不会持久化存储的,这里必须更改下
  • zookeeper.connect=//zookeeper的连接地址:根据实际进行配置
  1. 启动karfka
    bin/kafka-server-start.sh config/server.properties
    后台启动:
    bin/kafka-server-start.sh -daemon config/server.properties
    注释:一个server.properties其实,就可以当做一个broker

六、kafka基本使用

1. kafka常用命令

  1. 启动karfka
bin/kafka-server-start.sh config/server.properties &

后台启动:

bin/kafka-server-start.sh -daemon config/server.properties

注:一个server.properties其实,就可以当做一个broker

  1. 停止karfka
bin/kafka-server-stop.sh
  1. 查看当前服务器中的所有topic
    kafka-topics.sh --list --zookeeper zk服务IP:2181
bin/kafka-topics.sh --zookeeper 127.0.0.1:2181 --list
  1. 创建主题
    /kafka-topics.sh --create --zookeeper zk服务IP:2181 --replication-factor 1 --partitions 1 --topic she
bin/kafka-topics.sh --create --zookeeper 127.0.0.1:2181 --replication-factor 1 --partitions 1 --topic she

–zookeeper 连接zk集群
–create 创建
–replication-factor 副本
–partitions 分区
–topic 主题名
5. 查看topic的详细信息
./kafka-topics.sh -zookeeper zk服务IP:2181 -describe -topic she

bin/kafka-topics.sh -zookeeper 127.0.0.1:2181 -describe -topic she
  1. 删除topic
    kafka-topics.sh --zookeeper zk服务IP:2181 --delete --topic she
    注:不能真正删除topic只是把这个topic标记为删除(marked for deletion)

  2. 发送消息
    Kafka 默认提供了脚本工具可以不断地接收标准输入并将它们发送到 Kafka 的某个 topic 上 。

kafka-console-producer.sh --broker-list kafka服务IP:9092 --topic she

bin/kafka-console-producer.sh --broker-list 127.0.0.1:9092 --topic she

注意: kafka服务IP 为server.properties中配置的监听ip

  1. 接受消息
    Kafka 也提供了一个对应的脚本用于消费某(些) topic 下的消息并打印到标准输
    出 。 这对于我们测试、调试消息消费非常方便 。
bin/kafka-console-consumer.sh --bootstrap-server karfka服务ip:9092 --topic test --from-beginning

2. 命令使用问题总结

1)报错:Error while fetching metadata with correlation id

报错:Error while fetching metadata with correlation id 67 : {alarmHis=LEADER_NOT_AVAILABLE}
参考URL: http://www.mamicode.com/info-detail-2685225.html

报错背景:
单机安装了kafka,创建完成主题,启动生产者的时候产生报错现象。报错时持续不断打印日志信息。
报错原因:
获取相关ID为xx的元数据时出错。
报错解决:
vim server.properties
解决:

#     listeners = PLAINTEXT://your.host.name:9092

去掉注释,将需要监听的ip替换“your.host.name”,重启后恢复正常。

2)消费消息报错zookeeper is not a recognized option

老版本使用 --zookeeper 新版本 使用 --bootstrap-server

查阅资料后发现是kafka的版本问题,低版本的kafka可以使用以上的命令,但是在高版本的kafka中需要使用如下命令才行:

bin/kafka-console-consumer.sh --bootstrap-server karfka服务ip:9092 --topic test --from-beginning

从 Kafka 2.2 版本开始,社区推荐用 --bootstrap-server 参数替换 --zookeeper 参数,并且显式地将后者标记为“已过期”,因此,如果你已经在使用 2.2 版本了,那么创建主题请指定 --bootstrap-server 参数。

为什么改成了–bootstrap-server?
–zookeepe 直接与zookeeper连接,没有安全认证体系约束, --bootstrap-server会走kafka认证相关约束。

比如获取主题列表命令:
如果指定了 --bootstrap-server,那么这条命令就会受到安全认证体系的约束,即对命令发起者进行权限验证,然后返回它能看到的主题。否则,如果指定 --zookeeper 参数,那么默认会返回集群中所有的主题详细数据。基于这些原因,我建议你最好统一使用 --bootstrap-server 连接参数。

注:命令行脚本很多都是通过连接 ZooKeeper 来提供服务的。目前,社区已经越来越不推荐任何工具直连 ZooKeeper 了,因为这会带来一些潜在的问题,比如这可能会绕过 Kafka 的安全设置。

最后,运行这些脚本需要使用 Kafka 内部的类实现,也就是 Kafka服务器端的代码。实际上,社区还是希望用户只使用 Kafka客户端代码,通过现有的请求机制来运维管理集群。这样的话,所有运维操作都能纳入到统一的处理机制下,方便后面的功能演进。

六、关于Kafka Consumer

优雅的使用Kafka Consumer
参考URL: https://www.jianshu.com/p/abbc09ed6703

1. push 还是 pull

Kafka Consumer采用的是主动拉取broker数据进行消费的。一般消息中间件存在推送(server推送数据给consumer)和拉取(consumer主动取服务器取数据)两种方式,这两种方式各有优劣。
如果是选择推送的方式最大的阻碍就是服务器不清楚consumer的消费速度,如果consumer中执行的操作又是比较耗时的,那么consumer可能会不堪重负,甚至会导致系统挂掉。

而采用拉取的方式则可以解决这种情况,consumer根据自己的状态来拉取数据,可以对服务器的数据进行延迟处理。但是这种方式也有一个劣势就是服务器没有数据的时候可能会一直轮询,不过还好Kafka在poll()有参数允许消费者请求在“长轮询”中阻塞,等待数据到达(并且可选地等待直到给定数量的字节可用以确保传输大小)。

2. Kafka重复消费原因

平台搭建—Kafka使用—Kafka重复消费和丢失数据
参考URL: https://blog.csdn.net/qingqing7/article/details/80054281

底层根本原因:已经消费了数据,但是offset没提交。
原因1:强行kill线程,导致消费后的数据,offset没有提交。
原因2:设置offset为自动提交,关闭kafka时,如果在close之前,调用 consumer.unsubscribe() 则有可能部分offset没提交,下次重启会重复消费。例如:
try {
consumer.unsubscribe();
} catch (Exception e) {
}

try {
consumer.close();
} catch (Exception e) {
}

上面代码会导致部分offset没提交,下次启动时会重复消费。

原因3(重复消费最常见的原因):消费后的数据,当offset还没有提交时,partition就断开连接。比如,通常会遇到消费的数据,处理很耗时,导致超过了Kafka的session timeout时间(0.10.x版本默认是30秒),那么就会re-blance重平衡,此时有一定几率offset没提交,会导致重平衡后重复消费。

原因4:当消费者重新分配partition的时候,可能出现从头开始消费的情况,导致重发问题。
原因5:当消费者消费的速度很慢的时候,可能在一个session周期内还未完成,导致心跳机制检测报告出问题。

2.1 kafka重复消费解决方案

1.关闭spring-kafka的自动提交
2.延长session-time-out,权衡max.poll.records减少poll()中返回的批次的最大大小来解决此问题,//一次从kafka中poll出来的数据条数
3.权衡自动提交的时间点,ps最好不要使用这种方式,无法尽量避免重复
4.完美解决的话,只有每次都判断消息是否重复消费过了,不过此方式性能开销比较大,严重影响QPS,根据场景取舍

2.2 具体案例

  1. 场景描述
    onsumer消费一条数据平均需要200ms的时间,并且在某个时刻,producer会在短时间内产生大量的数据丢进kafka的broker里面(假设平均1s中内丢入了5w条需要消费的消息,这个情况会持续几分钟)。

对于这种情况,kafka的consumer的行为会是:

  1. kafka的consumer会从broker里面取出一批数据,给消费线程进行消费。
    由于取出的一批消息数量太大,consumer在session.timeout.ms时间之内没有消费完成
  2. consumer coordinator 会由于没有接受到心跳而挂掉,并且出现一些日志
    日志的意思大概是coordinator挂掉了,然后自动提交offset失败,然后重新分配partition给客户端
  3. 由于自动提交offset失败,导致重新分配了partition的客户端又重新消费之前的一批数据
  4. 接着consumer重新消费,又出现了消费超时,无限循环下去。
  1. 解决方案
    方法一:
  • 提高了partition的数量,从而提高了consumer的并行能力,从而提高数据的消费能力
  • 对于单partition的消费线程,增加了一个固定长度的阻塞队列和工作线程池进一步提高并行消费的能力
  • 由于使用了spring-kafka,则把kafka-client的enable.auto.commit设置成了false,表示禁止kafka-client自动提交offset,因为就是之前的自动提交失败,导致offset永远没更新,从而转向使用spring-kafka的offset提交机制。并且spring-kafka提供了多种提交策略:
    这些策略保证了在一批消息没有完成消费的情况下,也能提交offset,从而避免了完全提交不上而导致永远重复消费的问题。

方法二

  • 可以根据消费者的消费速度对session.timeout.ms的时间进行设置,适当延长
  • 或者减少每次从partition里面捞取的数据分片的大小,提高消费者的消费速度。

七、关于Kafka 拦截器

Kafka 拦截器分为生产者拦截器和消费者拦截器。

  1. 生产者拦截器允许你在发送消息前以及消息提交成功后植入你的拦截器逻辑。
  2. 消费者拦截器支持在消费消息前以及提交位移后编写特定逻辑。

这两种拦截器都支持链的方式,即你可以将一组拦截器串连成一个大的拦截器,Kafka 会按照添加顺序依次执行拦截器逻辑。

1. 生产者拦截器

Properties props = new Properties();
List<String> interceptors = new ArrayList<>();
interceptors.add("com.yourcompany.kafkaproject.interceptors.AddTimestampInterceptor"); // 拦截器 1
interceptors.add("com.yourcompany.kafkaproject.interceptors.UpdateCounterInterceptor"); // 拦截器 2
props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, interceptors);
……

你自己编写的所有 Producer 端拦截器实现类都要继承 org.apache.kafka.clients.producer.ProducerInterceptor 接口。
覆写方法:

  • onSend:该方法会在消息发送之前被调用。
  • onAcknowledgement:该方法会在消息成功提交或发送失败之后被调用。
    onAcknowledgement 的调用要早于生成程序发送消息的 callback 的调用。 值得注意的是,这个方法和 onSend 不是在同一个线程中被调用的,因此如果你在这两个方法中调用了某个共享可变对象,一定要保证线程安全哦。还有一点很重要,这个方法处在 Producer 发送的主路径中,所以最好别放一些太重的逻辑进去,否则你会发现你的 Producer TPS 直线下降。

2. 消费者拦截器

具体的实现类要实现 org.apache.kafka.clients.consumer.ConsumerInterceptor 接口,这里面也有两个核心方法。

  • onConsume:该方法在消息返回给 Consumer 程序之前调用。也就是说在开始正式处理消息之前,拦截器会先拦截,交给你处理。
  • onCommit:Consumer 在提交位移之后调用该方法。通常你可以在该方法中做一些记账类的动作,比如打日志等。

八、常见问题整理

1. 消息丢失问题

消息丢失可以总结为以下两个方面:

  1. 生产者程序丢失数据

Producer 永远要使用带有回调通知的发送 API,也就是说不要使用 producer.send(msg),而要使用 producer.send(msg, callback)
它能准确地告诉你消息是否真的提交成功了,你就可以有针对性地进行处理。

  1. 消费者程序丢失数据

消费者程序需要先消费消息,再更新位移的顺序。这样就能保证消息不丢失。
Consumer 程序不要开启自动提交位移,而是要应用程序手动提交位移。

2. kafka如何建立tcp连接

2.1 生产者代码是什么时候创建 TCP 连接的?

是在创建KfkaProducer实例时创建的连接还是在调该对象send方法时建立TCP连接?

答案:在创建 KafkaProducer 实例时,生产者应用会在后台创建并启动一个名为 Sender 的线程,该 Sender 线程开始运行时首先会创建与 Broker 的连接。
TCP 连接是在创建 KafkaProducer 实例时建立连接。但也有其他情况,如:
如果 Producer 端发送消息到某台 Broker 时发现没有与该 Broker 的 TCP 连接,那么也会立即创建连接。

如果不调用 send 方法,这个 Producer 都不知道给哪个主题发消息,它又怎么能知道连接哪个 Broker 呢?难不成它会连接 bootstrap.servers 参数指定的所有 Broker 吗?嗯,是的,Java Producer 目前还真是这样设计的。

在实际使用过程中,我并不建议把集群中所有的 Broker 信息都配置到 bootstrap.servers 中,通常你指定 3~4 台就足以了。因为 Producer 一旦连接到集群中的任一台 Broker,就能拿到整个集群的 Broker 信息,故没必要为 bootstrap.servers 指定所有的 Broker。

2.2 生产者何时关闭 TCP 连接?

Producer 端关闭 TCP 连接的方式有两种:
一种是用户主动关闭;一种是 Kafka 自动关闭

  1. producer.close() 方法来关闭
  2. Kafka 帮你关闭
    这与 Producer 端参数 connections.max.idle.ms 的值有关。默认情况下该参数值是 9 分钟,即如果在 9 分钟内没有任何请求“流过”某个 TCP 连接,那么 Kafka 会主动帮你把该 TCP 连接关闭。用户可以在 Producer 端设置 connections.max.idle.ms=-1 禁掉这种机制。一旦被设置成 -1,TCP 连接将成为永久长连接。当然这只是软件层面的“长连接”机制,由于 Kafka 创建的这些 Socket 连接都开启了 keepalive,因此 keepalive 探活机制还是会遵守的。

2.3 消费者代码是什么时候创建 TCP 连接的?

和生产者不同的是,构建 KafkaConsumer 实例时是不会创建任何 TCP 连接的。
,也就是说,当你执行完 new KafkaConsumer(properties) 语句后,你会发现,没有 Socket 连接被创建出来。这一点和 Java 生产者是有区别的,主要原因就是生产者入口类 KafkaProducer 在构建实例的时候,会在后台默默地启动一个 Sender 线程,这个 Sender 线程负责 Socket 连接的创建。

如果 Socket 不是在构造函数中创建的,那么是在 KafkaConsumer.subscribe 或 KafkaConsumer.assign 方法中创建的吗?严格来说也不是。TCP 连接是在调用 KafkaConsumer.poll 方法时被创建的。

2.4 消费者代码何时关闭 TCP 连接?

和生产者类似,消费者关闭 Socket 也分为主动关闭和Kafka 自动关闭。

  • Kafka 自动关闭
    消费者端参数 connection.max.idle.ms控制的,该参数现在的默认值是 9 分钟,即如果某个 Socket 连接上连续 9 分钟都没有任何请求“过境”的话,那么消费者会强行“杀掉”这个 Socket 连接。

不过,和生产者有些不同的是,如果在编写消费者程序时,你使用了循环的方式来调用 poll 方法消费消息,那么上面提到的所有请求都会被定期发送到 Broker,因此这些 Socket 连接上总是能保证有请求在发送,从而也就实现了“长连接”的效果。

参考

《KAFKA官方文档》5.2 APIs
参考URL: http://ifeve.com/kafka-apis/
什么是流式计算 | 另一个世界系列
参考URL: https://www.sohu.com/a/214248082_294584
为什么说,大数据是从流式计算开始切入的?
参考URL: http://www.dostor.com/p/54907.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!