大数据技术之Kafka

第1章 Kafka概述

1.1 定义

  • Kafka传统定义: Kafka是一个分布式的基于发布/订阅模式消息队列 (MessageQueue),主要应用于大数据实时处理领域。

  • 发布/订阅 :消息的发布者不会将消息直接发送给特定的订阅者,而是将发布的消息分为不同的类别,订阅者只接收感兴趣的消息

  • Kafka最新定义 : Kaka是一个开源的分布式事件流平台 (Event StreamingPlatformm),被数千家公司用于高性能数据管道、流分析、数据集成和关键任务应用

1.2 消息队列

目前企业中比较常见的消息队列产品主要有Kafka、ActiveMQ、RabbitMQ、RocketMQ等。

  • 在大数据场景主要采用Kafka作为消息队列
  • 在JavaEE开发中主要采用ActiveMQ、RabbitMQ、RocketMQ

1.2.1 传统消息队列的应用场景

传统的消费队列的主要应用场景有:缓存/削峰(缓冲)、解耦(少依赖)、异步通信(不必要及时处理)

  • 缓存/削峰(缓冲):有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
  • 解耦:允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
  • 异步通信:允许用户把一个消息放入队列,但并不立即处理它,然后在需要的时候再去处理它们。

1.2.2 消息队列的两种模式

消息队列主要分为两种模式:点对点模式(一个生产者对口一个消费者)和发布/订阅模式(一对多)。
在这里插入图片描述

1.3 Kafka基础架构

在这里插入图片描述
1)Producer :消息生产者,就是向kafka broker发消息的客户端;
2)Consumer :消息消费者,向kafka broker获取消息的客户端;
3)Consumer Group (CG):消费者组,由多个consumer组成。消费者组内每个消费者负责消费不同分区的数据,一个broker可以有多个不同的topic,一个topic下的一个分区只能被一个消费者组内的一个消费者所消费;消费者组之间互不影响。消费者组是逻辑上的一个订阅者。
4)Broker :一台kafka服务器就是一个broker。一个broker可以容纳多个不同topic。
5)Topic :可以理解为一个队列,生产者和消费者面向的都是一个topic;
6)Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列;
7)Replica:副本,为保证集群中的某个节点发生故障时,该节点上的partition数据不丢失,且kafka仍然能够继续工作,kafka提供了副本机制,一个topic的每个分区都有若干个副本,一个leader和若干个follower
8)leader:每个分区副本中的“”,生产者发送数据的对象,以及消费者消费数据的对象都是leader。
9)follower:每个分区副本中的“”,实时与leader副本保持同步,在leader发生故障时,成为新的leader。


第2章 Kafka快速入门

2.1 安装部署

后续更新

2.2 Kafka命令行操作

在这里插入图片描述

2.2.1 主题命令行操作

  1. 查看操作主题命令需要的参数
    [atguigu@hadoop102 kafka]$ bin/kafka-topics.sh

  2. 重要的参数如下
    | 参数 | 描述|
    |–|–|
    | --bootstrap-server | 连接kafka Broker主机名称和端口号 |
    |–topic | 操作的topic名称|
    |–create |创建主题|
    |–delete| 删除主题|
    |–alter| 修改主题|
    |–list |查看所有主题|
    |–describe |查看主题详细描述|
    |–partitions |设置主题分区数|
    |–replication-factor |设置主题分区副本|
    |–config |更新系统默认的配置|

  3. 查看当前服务器中的所有topic
    bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --list

  4. 创建一个主题名为first的topic
    bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --create --replication-factor 3 --partitions 3 --topic first

  5. 查看Topic的详情
    bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --describe --topic first
    Topic: first TopicId: EVV4qHcSR_q0O8YyD32gFg PartitionCount: 1 ReplicationFactor: 3 Configs: segment.bytes=1073741824
    Topic: first Partition: 0 Leader: 102 Replicas: 102,103,104 Isr: 102,103,104

  6. 修改分区数(注意:分区数只能增加,不能减少)
    bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --alter --topic first --partitions 3

  7. 再次查看Topic的详情
    bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --describe --topic first
    Topic: first TopicId: EVV4qHcSR_q0O8YyD32gFg PartitionCount: 3 ReplicationFactor: 3 Configs: segment.bytes=1073741824
    Topic: first Partition: 0 Leader: 102 Replicas: 102,103,104 Isr: 102,103,104
    Topic: first Partition: 1 Leader: 103 Replicas: 103,104,102 Isr: 103,104,102
    Topic: first Partition: 2 Leader: 104 Replicas: 104,102,103 Isr: 104,102,103

  8. 删除topic
    bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --delete --topic first

2.2.2 生产者命令行操作

  1. 查看命令行生产者的参数
    [atguigu@hadoop102 kafka]$ bin/kafka-console-producer.sh
  2. 重要的参数如下:
参数 描述
–bootstrap-server 连接kafka Broker主机名称和端口号
–topic 操作的topic名称
  1. 生产消息
    bin/kafka-console-producer.sh --broker-list hadoop102:9092 --topic first

2.2.3 消费者命令行操作

  1. 查看命令行消费者的参数
    bin/kafka-console-consumer.sh
  2. 重要的参数如下:
参数 描述
–bootstrap-server 连接kafka Broker主机名称和端口号
–topic 操作的topic名称
–from-beginning 从头开始消费
–group 指定消费者组名称
  1. 消费消息
    bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic first
  2. 从头开始消费
    bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --from-beginning --topic first

第3章 Kafka生产者

3.1 生产者消息发送流程

3.1.1 发送原理

Kafka的Producer发送消息采用的是异步发送的方式。
在消息发送的过程中,涉及到了两个线程:main线程Sender线程,以及一个线程共享变量: RecordAccumulator
① main线程中创建了一个双端队列RecordAccumulator,将消息发送给RecordAccumulator。
② Sender线程不断从RecordAccumulator中拉取消息发送到Kafka broker。
在这里插入图片描述

  1. Kafka Producer生产者调用main()线程,将外部数据打包成ProducerRecord对象,并通过sand()方法发送给拦截器、序列化器和分区器后,将消息放到线程共享队列中。
  2. 只有数据累积到batch.size(默认16K)或者到达linger.ms(默认0ms)设置的的时间后,sender()线程读取数据到NetworkClient。
  3. sender()线程通过网络将数据发送给相应的Kafka集群的分区后,根据设置的应答acks等级,回复sender线程数据是否发送成功。
  4. 如果发送成功,则将清理NetworkClient和线程共享变量队列的数据。
  • main线程:在客户端将数据放入双端队列里
  • Sender线程:从队列里读取数据发送到kafka集群
  • DQueue:双端队列,每个分区对应一个双端队列。队列中的内容就是ProducerBatch,即DQueue,写入缓存时放入尾部,Sender读取消息时从头部读取。
  • batch.size:只有数据积累到batch.size之后,sender才会取数据发送,默认大小为16k。
  • linger.ms:如果数据迟迟没有到达batch.size,那么sender线程在等待linger.ms设置的实践到达后就会取数据发送。(默认是0,表示不等待)
  • ProducerBatch:就是一个消息批次,包含很多ProducerRecord
  • RecordAccumulator主要用来缓存消息以便 Sender 线程可以批量发送,减少网络传输的资源消耗以提升性能。可通过生产者客户端参数buffer.memory配置,默认大小为32M。当生产者的缓冲区已满,这些方法就会阻塞。在阻塞时间达到max.block.ms时,生产者抛出超时异常。
  • InFlightRequests:缓存已经发出去但还没有收到响应的请求,配置参数为max.in.flight.requests.per.connection,默认值为5,即最多只能缓存5个未收到响应的请求。

拦截器
拦截器可以在消息发送前做一些准备工作,如过滤某些不要的信息、修改消息的内容等等。

序列化器
序列化器(Serializer)用于把对象转换成字节数组能通过网络发送给broker。消费者需要用反序列化器(Deserializer)把从Kafka中收到的字节数组转换成相应的对象。

分区器
主要有以下策略:

  1. 指定partition 如果在创建ProducerRecord的时候,指定了分区号,那么就会存储到这个分区中去。
  2. 指定Key 将key的hash值与topic的分区数取余得到最终的分区号。
  3. 若没有key,也没有分区号,采用默认的RoundRobin轮询分配。(kafka2.4后使用StickyPartitioning Strategy分区)。

ack应答级别
producer发送给broker有以下三种应答级别:

  • 0:生产者发送到服务端即可,不需要等待应答如果服务端接收到消息后突然宕机都就会导致数据丢失 ,此种级别可靠性很差但效率很高。
  • 1:leader收到即可,如果leader还未同步到follower就挂了,那么也会导致丢数问题 ,此种级别可靠性中等效率中等。
  • -1:ISR队列里的所有节点都收到消息后返回 ,此种级别可靠性很高但效率很低。

注意: 数据完全可靠条件 = ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2

3.1.2 生产者重要参数列表

参数名称 描述
bootstrap.servers 生产者连接集群所需的broker地址清单。可以设置1个或者多个,中间用逗号隔开。生产者从给定的broker里查找到其他broker信息。
key.serializer、 value.serializer 指定发送消息的key和value的序列化类型。要写全类名。(反射获取)
buffer.memory RecordAccumulator缓冲区总大小,默认32m。
batch.size 缓冲区一批数据最大值,默认16k。适当增加该值,可以提高吞吐量,但是如果该值设置太大,会导致数据传输延迟增加。
linger.ms 如果数据迟迟未达到batch.size,sender等待linger.time之后就会发送数据。单位ms,默认值是0ms,表示没有延迟。生产环境建议该值大小为5-100ms之间。
acks 0:生产者发送过来的数据,不需要等数据落盘应答。1:生产者发送过来的数据,Leader数据落盘后应答。-1(all):生产者发送过来的数据,Leader和isr队列里面的所有节点数据都落盘后应答。默认值是-1
max.in.flight.requests.per.connection 允许最多没有返回ack的次数,默认为5,开启幂等性要保证该值是 1-5的数字。
Retries (重试) 当消息发送出现错误的时候,系统会重发消息。retries表示重试次数。默认是int最大值,2147483647。如果设置了重试,还想保证消息的有序性,需要设置MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION=1否则在重试此失败消息的时候,其他的消息可能发送成功了。
retry.backoff.ms 两次重试之间的时间间隔,默认是100ms。
enable.idempotence 是否开启幂等性,默认true,开启幂等性。
compression.type 生产者发送的所有数据的压缩方式。默认是none,不压缩。 支持压缩类型:none、gzip、snappy、lz4和zstd。

3.2 生产者分区

3.2.1分区的原因

分区的好处:
1)便于合理使用存储资源,每个Partition在一个Broker上存储,可以把海量的数据按照分区切割成一块一块数据存储在多台Broker上。合理控制分区的任务,可以实现负载均衡的效果。
2)提高并行度,生产者可以以分区为单位发送数据:消费者可以以分区为单位进行消费数据

主要有以下策略:

  1. 若指定partition 如果在创建ProducerRecord的时候,指定了分区号,那么就会存储到这个分区中去。
  2. 若指定Key 将key的hash值与topic的分区数取余得到最终的分区号。
  3. 若既没有key,也没有分区号,采用默认的RoundRobin轮询分配。(kafka2.4后使用StickyPartitioning Strategy分区)。

3.3 生产经验——生产者如何提高吞吐量

3.3.1 吞吐量

  • batch .size :批次大小,默认16k
  • mslinger.ms :等待时间,修改为5-100
  • compression.type: 压缩snappy
  • RecordAccumulator: 缓冲区大小,修改为64m。

3.4 生产经验——数据可靠性

在这里插入图片描述
在这里插入图片描述
可靠性总结:

  • acks=0,生产者发送过来数据就不管了,可靠性差,效率高;
  • acks=1,生产者发送过来数据Leaer应答,可靠性中等,效率中等;
  • acks= -1,生产者发送过来数据Leader和ISR队列里面所有Flwer应答,可靠性高,效率低;
    • 在生产环境中,ack=0很少使用;
    • ack=1,一般用于传输普通日志,允许丢个别数据;
    • ack=-1,一般用于传输和钱相关的数据对可靠性要求比较高的场景。

3.5 生产经验——数据去重

3.5.1 数据传递语义

在这里插入图片描述

3.5.2 幂等性

  1. 幂等性原理:
    在这里插入图片描述
  2. 开启幂等性
    在prudocer的配置对象中,添加参数enable.idempotence,参数值默认为true,设置为false就关闭了。

3.5.3 生产者事务

1. kafka事务原理
在这里插入图片描述

3.6 生产经验——数据有序

单分区内,有序(有条件的,详见下节) ;
多分区,分区与分区间无序:

3.7 生产经验——数据无序在这里插入图片描述


第4章 Kafka Broker

4.1 Kafka Broker 工作流程

  1. Kafka Broker工作流程图示
    在这里插入图片描述

4.1.2 Broker重要参数

参数名称 描述
replica.lag.time.max.ms ISR中的Follower超过该事件阈值(默认30s)未向Leader发送同步数据,则该Follower将被踢出ISR。
auto.leader.rebalance.enable 默认是true。 自动Leader Partition 平衡。
leader.imbalance.per.broker.percentage 默认是10%。每个broker允许的不平衡的leader的比率。如果每个broker超过了这个值,控制器会触发leader的平衡。
leader.imbalance.check.interval.seconds 默认值300秒。检查leader负载是否平衡的间隔时间。
log.segment.bytes Kafka中log日志是分成一块块存储的,此配置是指log日志划分 成块的大小,默认值1G。
log.index.interval.bytes 默认4kb,kafka里面每当写入了4kb大小的日志(.log),然后就往index文件里面记录一个索引。
log.retention.hours
log.retention.minutes Kafka中数据保存的时间,分钟级别,默认关闭。
log.retention.ms Kafka中数据保存的时间,毫秒级别,默认关闭。(优先级最高)
log.retention.check.interval.ms 检查数据是否保存超时的间隔,默认是5分钟。
log.retention.bytes 默认等于-1,表示无穷大。超过设置的所有日志总大小,删除最早的segment。
log.cleanup.policy 默认是delete,表示所有数据启用删除策略;如果设置值为compact,表示所有数据启用压缩策略。
num.io.threads 默认是8。负责写磁盘的线程数。整个参数值要占总核数的50%。
num.replica.fetchers 副本拉取线程数,这个参数占总核数的50%的1/3
num.network.threads 默认是3。数据传输线程数,这个参数占总核数的50%的2/3 。
log.flush.interval.messages 强制页缓存刷写到磁盘的条数,默认是Max(long) (9223372036854775807)。一般交给系统管理。
log.flush.interval.ms 每隔多久,刷数据到磁盘,默认是null。一般不建议修改,交给系统自己管理。

4.2 Kafka 副本

4.2.1 kafka 副本的基本信息

kafka副本作用 提高数据可靠性
kafka副本个数 默认1个,生产环境中一般配置为2个,保证数据可靠性;但是过多的副本会增加磁盘存储空间、增加网络数据传输、降低kafka效率。
kafka副本角色 副本角色分为Leader和Follower。kafka生产者只会把数据发送到Leader,follower会主动从Leader上同步数据。
kafka中的AR 是所有副本的统称(Assigned Repllicas), AR = ISR + OSR;ISR:表示和Leader保持同步(默认30s)的follower集合。OSR:表示Follower与Leader副本同步时,延迟过多的副本。

4.2.2 Leader选举过程

  1. kafka controller:
    kafka集群中有一个broker的Controller会被选举为Controller Leader负责管理集群broker的上下线、所有的topic的分区副本分配Leader选举等工作Controller的信息同步工作是依赖于Zookeeper的。

4.2.3 leader和 follower故障处理细节

1. follower故障处理细节**(被踢-重连-追上Hw-连接成功)**

在这里插入图片描述
LEO(Log End Offset):每个副本的最后一个offset,LEO其实就是最新的offset + 1。
HW(High Watermark):所有副本中最小的LEO 。

1)Follower故障:
(1) Follower发生故障后会被临时踢出ISR
(2) 这个期间Leader和Follower继续接收数据
(3)待该Follower恢复后,Follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向Leader进行同步。
4)等该Follower的LEO大于等于该Partition的HW,即Follower追上Leader之后,就可以重新加入ISR了。

2. leader故障处理细节(从ISR队列选取ar中靠前的节点选为leader,新leader短则follower“剪”,反之则向leader同步)

1) Leader故障
(1) Leader发生故障之后,会从ISR中选出一个新的Leader
(2) 为保证多个副本之间的数据一致性,其余的Follower会先将各自的log文件高于HW的部分截掉,然后从新的Leader同步数据。

4.3 文件存储

4.3.1 文件存储机制

在这里插入图片描述

4.3.2 文件清理策略

  1. kafka数据文件保存时间:默认是7天
  2. kafka数据文件保存可通过如下参数修改
    ① log.retention.hours:最低优先级小时, 默认7天(168小时)
    ② log.retention.minutes:分钟
    ③ log.retention.ms:最高优先级毫秒
    ④ log.retention.check.interval.ms:负责设置检查周期,默认5分钟。
  3. 那么一旦超过了设置的时间就会采取清理策略,清理策略有两种:delete和compact

1)delete策略
delete日志删除:将过期数据删除。
配置:log.cleanup.policy=delete
基于时间:默认打开,以segment中所有记录中的最大时间戳作为文件时间戳
基于大小:默认关闭,超过设置的所有日志大小,删除最早的segment。
log.retention.bytes,默认等于-1,表示无穷大。

2)compact日志策略
compact日志策略:对于相同的key的不同value值,只保留最后一个版本。

4.4 高效读写数据

1.Kafka本身是分布式集群,可以采用分区技术,并行度高
2.读数据采用稀疏索引,可以快速定位要消费的数据
3.顺序写磁盘
Kafka的producer生产数据,要写入到log文件中,写的过程是一直追加到文件末端,为顺序写。官网有数据表明,同样的磁盘,顺序写能到600M/s,而随机写只有100K/s。这与磁盘的机械机构有关,顺序写之所以快,是因为其省去了大量磁头寻址的时间
4. 页缓存+零拷贝技术:
在这里插入图片描述

第5章 Kafka消费者

5.1 Kafka消费方式

Kafka的consumer采用pull(拉)模式从broker中读取数据。

push(推)模式 很难适应消费速率不同的消费者,因为消息发送速率是由broker决定的。它的目标是尽可能以最快速度传递消息,但是这样很容易造成consumer来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。
pull 模式 可以根据consumer的消费能力以适当的速率消费消息。不足之处是,如果kafka没有数据,消费者可能会陷入循环中,一直返回空数据。针对这一点,Kafka的消费者在消费数据时会传入一个时长参数timeout,如果当前没有数据可供消费,consumer会等待一段时间之后再返回,这段时长即为timeout。

5.2 Kakfa消费者工作流程

5.2.1 消费者总体工作流程

在这里插入图片描述

5.2.2 消费者组原理

在这里插入图片描述

Consumer Group(CG):消费者组,由多个consumer组成。形成一个消费者组的条件,是所有消费者的groupid相同。

  • 消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费。
  • 消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。

消费者组初始化流程:
在这里插入图片描述

消费者组详细消费流程:
在这里插入图片描述

5.3 生产经验——分区分配策略及再平衡

1、一个consumer group中有多个consumer组成,一个 topic有多个partition组成,现在的问题是,到底由哪个consumer来消费哪个partition的数据。
2、Kafka有四种主流的分区分配策略: RangeRoundRobinStickyCooperativeSticky
可以通过配置参数partition.assignment.strategy,修改分区的分配策略。默认策略是Range + CooperativeSticky。Kafka可以同时使用多个分区分配策略。

  1. Range分区策略原理:===> 容易造成数据倾斜
    在这里插入图片描述

  2. RoundRobin分区分配策略原理
    在这里插入图片描述

  3. Sticky分区分配策略原理
    1.粘性分区定义:
    可以理解为分配的结果带有“粘性的”。即在执行一次新的分配之前,考虑上一次分配的结果,尽量少的调整分配的变动,可以节省大量的开销。粘性分区是Kafka从0.11.x版本开始引入这种分配策略,首先会尽量均衡的放置分区到消费者上面,在出现同一消费者组内消费者出现问题的时候,会尽量保持原有分配的分区不变化。

5.5 offset位移

5.5.1 offset的默认维护位置

由于consumer在消费过程中可能会出现断电宕机等故障,consumer恢复后,需要从故障前的位置的继续消费,所以consumer需要实时记录自己消费到了哪个offset,以便故障恢复后继续消费。
Kafka 0.9版本之前,consumer默认将offset保存在Zookeeper中,从0.9版本开始,consumer默认将offset保存在Kafka一个内置的topic中,该topic为**__consumer_offsets**。
在__consumer_offsets主题里面采用key+value的方式存储数据。key是groupId+topic+分区号,value是当前offset的值。每隔一段时间,kafka内部就会对这个topic进行compact(压实),即每个groupId+topic+分区号就保留最新的数据。

5.5.2 自动提交offset

1. 自动提交offset图示
在这里插入图片描述
2)消费者自动提交offset

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Arrays;
import java.util.Properties;
 
public class CustomConsumer {
    
    
    public static void main(String[] args) {
    
    
        // 1. 创建kafka消费者配置类
        Properties properties = new Properties();
        // 2. 添加配置参数
        // 添加连接
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "hadoop102:9092");
        // 配置序列化 必须
        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.GROUP_ID_CONFIG, "test");
        // 是否自动提交offset
        properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");
        // 提交offset的时间周期,默认5s,
        properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");

        // 3. 创建kafka消费者
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);

        // 4. 设置消费主题  形参是列表
        consumer.subscribe(Arrays.asList("first"));

        // 5. 消费数据
        while (true){
    
    
            // 6. 读取消息
            ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofSeconds(1));

            // 7. 输出消息
            for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
    
    
                System.out.println(consumerRecord.value());
            }
        }
    }
}

5.5.3 手动提交offset

1. 手动提交offset图示:
在这里插入图片描述
1)同步提交offset
由于同步提交offset有失败重试机制,故更加可靠,以下为同步提交offset的示例。

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Arrays;
import java.util.Properties;

public class CustomConsumerByHand {
    
    
    public static void main(String[] args) {
    
    
        // 1. 创建kafka消费者配置类
        Properties properties = new Properties();
        // 2. 添加配置参数
        // 添加连接
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "hadoop102:9092");
        // 配置序列化 必须
        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.GROUP_ID_CONFIG, "test");
        // 是否自动提交offset
        properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
        // 提交offset的时间周期
        properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");

        // 3. 创建kafka消费者
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);

        // 4. 设置消费主题  形参是列表
        consumer.subscribe(Arrays.asList("first"));

        // 5. 消费数据
        while (true){
    
    
            // 6. 读取消息
            ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofSeconds(1));

            // 7. 输出消息
            for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
    
    
                System.out.println(consumerRecord.value());
            }
// 同步提交offset
            consumer.commitSync();
        }

    }
}

2)异步提交offset
虽然同步提交offset更可靠一些,但是由于其会阻塞当前线程,直到提交成功。因此吞吐量会受到很大的影响。因此更多的情况下,会选用异步提交offset的方式。
以下为异步提交offset的示例:

import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;

public class CustomConsumerByHand {
    
    
    public static void main(String[] args) {
    
    
         // 1. 创建kafka消费者配置类
        Properties properties = new Properties();
        // 2. 添加配置参数
        // 添加连接
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "hadoop102:9092");
        // 配置序列化 必须
        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.GROUP_ID_CONFIG, "test");
        // 是否自动提交offset
        properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
        // 提交offset的时间周期
        properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");

        // 3. 创建kafka消费者
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);

        // 4. 设置消费主题  形参是列表
        consumer.subscribe(Arrays.asList("first"));

        // 5. 消费数据
        while (true){
    
    
            // 6. 读取消息
            ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofSeconds(1));

            // 7. 输出消息
            for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
    
    
                System.out.println(consumerRecord.value());
            }

            // 异步提交offset
            consumer.commitAsync(new OffsetCommitCallback() {
    
    
                /**
                 * 回调函数输出
                 * @param offsets   offset信息
                 * @param exception 异常
                 */
                @Override
                public void onComplete(Map<TopicPartition, OffsetAndMetadata> offsets, Exception exception) {
    
    
                    // 如果出现异常打印
                    if (exception != null ){
    
    
                        System.err.println("Commit failed for " + offsets);
                    }
                }
            });
        }

    }
}

5.5.4 指定Offset消费

auto.offset.reset = earliest | latest | none |

当Kafka中没有初始偏移量(消费者组第一次消费)或服务器上不再存在当前偏移量时(例如该数据已被删除),该怎么办?
(1)earliest:自动将偏移量重置为最早的偏移量
(2)latest(默认值):自动将偏移量重置为最新偏移量
(3)none:如果未找到消费者组的先前偏移量,则向消费者抛出异常

5.5.5 数据漏消费和重复消费分析

  1. 问题:无论是同步提交还是异步提交offset,都有可能会造成数据的漏消费或者重复消费
  2. 漏消费:先提交offset后消费,有可能造成数据的漏消费;
  3. 重复消费:而先消费后提交offset,有可能会造成数据的重复消费。
    在这里插入图片描述

5.6 生产经验之Consumer事务

1. 消费者事务
在这里插入图片描述

5.7 生产经验——数据积压(消费者如何提高吞吐量)

在这里插入图片描述

第6章 Kafka-Eagle监控

Kafka-Eagle框架可以监控Kafka集群的整体运行情况,在生产环境中经常使用。
后期更新

猜你喜欢

转载自blog.csdn.net/m0_57126939/article/details/129856287