目录
Kafka中leader follower 宕机后重连,数据如何同步?
kafka中初始化的时候Leader选举有一定的规律,如何打破这个规律?
kafka中的数据已经消费过的数据,是否可以再次消费?怎么做?
kafka消息发送的流程?
1.创建启动main线程,创建一个producer对象,调用KafkaProducer 的send方法,传输数据。
2.数据到达拦截器Interceptors,并被加工
3.进入序列化器,对key value进行序列化
4.进入分区器,对数据进行分区,一个分区会创建一个队列,所有的分区队列都是在内存中创建的,总称双端队列 RecordAccumulator,大小默认为32m。
5.将消息追加到RecordAccumulator 缓冲区中,一个topic下的partition 对应着一个队列,队列中包含着batch元素。
6.sender 线程遍历所有partition对应的队列,找出准备好的broker ,不断从中拉取数据,数据累加到producebatch的大小(默认16k)就进行发送,或者等到等待时间linger.ms结束拉取数据。
7.数据拉取到过程中是以分区为单位拉到某一个broker上,一个broker最多接受5个拉取数据的请求request
8.selector主要是打通生产者与kafka集群broker这条链路的io流进行数据传输,数据达到对应的broker之后会进行复制备份
9.如果集群收到生产者的数据之后,会进行应答(acks),
主要有 0:生产者发送过来的数据,不需要等数据落盘应答。可靠性差,效率高
1:生产者发送过来的数据,Leader 收到数据后应答。可靠性中等,效率中等
-1(all):生产者发送过来的数据,Leader+和 isr 队列里面的所有节点收齐数据后应答。
可靠性高,效率低
10.生产者收到成功的请求之后,会将对应的传输请求request给取消掉,然后清理掉双端队列 RecordAccumulator里每一个分区中传输成功的数据。
11. 生产者传输失败后,可以进行重试,可以不断发送,直到成功或者21E次。
Kafka 的架构设计?
- Producer消息生产者:向broker发送消息者
- Consumer 消息消费者:从 broker 拉取消息者
- Zk : 集群管理、leader选举、broker注册和发现、topic和partition管理、isr维护
Kafka集群:
-
- Broker : 节点 一个集群容纳多个节点,一个节点容纳多个topic
- Topic:消息主题,可以理解为一个队列
- Partition : 一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。
- Replication :每一个分区都有若干副本
- Leader : 每个partition有多个副本,其中有且仅有一个作为Leader,Leader是当前负责数据的读写的副本。
- Follower : Follower与Leader保持数据同步
Kafka 分区的目的?
负载均衡 、并行处理(水平处理)、 故障容错(高可用性)
- 负载均衡:每个分区可以在不同的Broker上进行复制和存储。这样可以实现数据的负载均衡,避免单个Broker成为性能瓶颈,保证整个集群的稳定运行。
- 并行处理:Kafka的分区机制使得,每个消费者(消费组)可以独立地消费自己所负责的分区。这样可有效地利用多台机器的处理能力,实现数据的水平扩展,提高整个系统的处理能力和吞吐量。
- 故障容错:每个分区都有一个Leader副本和零个或多个Follower副本。Leader负责处理读写请求,而Follower副本与Leader保持同步,以实现数据的备份和冗余存储。当Leader副本不可用时,Follower副本可以接替成为新的Leader,确保数据的可靠性和高可用性。
Kafka如何做到消息的有序性?
前提:kafka默认保证同一个partition分区内的消息是有序的
方案一 topic 只设置一个partition分区
可设置topic只使用一个分区,消息就是全局有序,缺点是只能被consumer group里的一个消费者消费,降低了性能,不适用高并发的情况
方案二 producer将消息发送到指定同一个partition分区
producer可在发送消息时 指定需要保证顺序的几条消息发送到同一个分区,消费者消费时,消息就是有序的。
ISR、OSR、AR 是什么?
ISR:in-sync replica, 与 leader 保持同步的 replica 集合(包括leader),它确保Kafka中已提交成功消息不会丢失
OSR : Out-of-Sync Replica,失步副本,当kafka分区的leader与副本(包括leader)之间出现数据不同步的情况时,该副本就称之为“失步副本”
AR:Assigned Replica ,指已经被分配在Broker上的副本,可以动态变化以适应集群的变化。
Kafka 在什么情况下会出现消息丢失?
生产者丢失消息
- 目前 Kafka Producer 是异步发送消息的,如果Producer 客户端使用了 producer.send(msg) 方法来发送消息,方法会立即返回,但此时并不能代表消息已经发送成功。
- 如果消息在发送的过程中发生网络抖动,那么消息可能没有传递到 Broker,那么消息可能会丢失。
- 如果发送的消息本身不符合,如大小超过了 Broker 的message.max.bytes的值等。
Broker 服务端丢失消息
- Leader Broker 宕机,触发选举过程,集群选举了一个落后 Leader 太多的 Broker 作为 Leader,那么落后的那些消息就会丢失。
- Kafka 为了提升性能,使用页缓存机制,将消息写入页缓存而非直接持久化至磁盘,采用了异步批量刷盘机制,也就是说,按照一定的消息量和时间间隔去刷盘,刷盘的动作由操作系统来调度的,如果刷盘之前,Broker 宕机了,重启后在页缓存的这部分消息则会丢失。
消费者丢失消息
- 先处理消息,后提交偏移量;消费者拉取并处理了消息,但处理消息异常了导致失败,并且提交了偏移量,消费者重启后,会从之前已提交的位移的下一个位置重新开始消费,消费失败的那些消息不会再次处理,即相当于消费者丢失了消息。
- 先提交偏移量,后处理消息;消费者拉取了消息,并提交了消费位移,但是在消息处理结束之前突然发生了宕机等故障,消费者重启后,会从之前已提交的位移的下一个位置重新开始消费,之前未处理完成的消息不会再次处理,即相当于消费者丢失了消息。
如何尽力保证 Kafka 的可靠性
设置ACK应答机制
在定义 Producer 时通过 acks 参数指定
acks = 0
:表示如果生产者能够通过网络把消息发送出去,那么就认为消息已成功写入 Kafka ;可靠性差,效率高;
acks = 1
:
表示
Leader
在收到消息并把它写入到本地磁盘时会返回确认或错误响应
acks = all: 表示
Leader 在返回确认或错误响应之前,会等待所有同步副本都收到消息
设置ISR等待时间
Leader维护了一个动态的in-sync replica set(ISR),即和leader保持同步的follower集合。如果某个follower长时间没有向leader同步数据,则该follower移出ISR,其中这个空闲等待时间可由replica.lag.time.max.ms参数设定。
设置消息同步发送
Producer 发送消息还可以选择同步(默认,通过 producer.type=sync 配置) 或者异步(producer.type=async)模式。如果设置成异步,虽然会极大的提高消息发送的性能,但是这样会增加丢失数据的风险。如果需要确保消息的可靠性,必须将 producer.type 设置为 sync。
Kafka中如何做到数据唯一,即数据去重?
三种消息投递语义
- 至少一次(At Least Once)= ACK= -1 + 分区副本≥2 + ISR里应答的最小副本数量≥于2 可保障数据可靠
- 最多一次(At Most Once)= ACK级别设置为0
- 有且只有一次(Exactly Once)= 幂等性 + 至少一次(ACK=-1 + 分区副本≥2 + ISR里应答的最小副本数量≥2)
具体方案
幂等性 Producer: 保证生产端发送消息幂等。局限性,是只能保证单分区且单会话(重启后就算新会话)
开启参数 enable.idempotence 默认为 true,false 关闭
事务: 保证生产端发送消息幂等。解决幂等 Producer 的局限性。
开启事务,放弃事务,提交事务(与jdbc中的事务较为相似)
// 1 初始化事务
void initTransactions()
// 2 开启事务
void beginTransaction()
// 3 在事务内提交已经消费的偏移量(主要用于消费者)
void sendOffsetsToTransaction(Map<TopicPartition, OffsetAndMetadata> offsets,
String consumerGroupId)
// 4 提交事务
void commitTransaction()
// 5 放弃事务(类似于回滚事务的操作)
void abortTransaction()
简述kafka集群中的Leader选举机制?
每一个Broker启动后会在zk中注册自己的信息(brokerid),kafka集群会选举一个Broker作为Leader作为kafka集群的总控制器Controller(一般由注册较早broker的担任,Epoch值),负责管理整个集群所有分区Partition和副本follower的状态。
Controller会使用zookeeper的watcher机制,监控brokers下面的所有的broker,每个Topic都有一个ISR列表,直接读取ISR列表的第一个replica作为leader。
如果一旦发现某个broker宕机或有其他问题,就会去找到该broker有多少replica是leader并发起对该partition的选举。如果宕机的就是leader,则会选择后面replica作为leader。
选举结果将被通知给其他Broker,它们会更新自己维护的分区元数据信息,确保所有Broker都知道新的Leader是谁。
kafka如何处理数据乱序问题?
1. kafka在1.x版本之前保证数据单分区有序,条件如下: max.in.flight.requests.per.connection = 1(不需要考虑是否开启幂等性)。
表示生产者在发送一条消息后,必须等待Broker的响应(确认)之后才能发送下一条消息。这样可以保证消息的顺序性,但发送速度较慢。
2. kafka在1.x及以后版本保证数据单分区有序,条件如下:
(1)开启幂等性
max.in.flight.requests.per.connection需设置小于等于5。
可保证在同一个连接上同时发送的未确认请求不会太多,以防止出现消息重复或乱序。
(2)未开启幂等性
max.in.flight.requests.per.connection需要设置为1。
确保只有在上一条消息得到确认后才发送下一条消息,避免消息重复或乱序。
kafka中节点如何服役和退役?
服役与退役的本质其实就是,启动或停止一个broker ,在集群中生成相应的负载均衡执行计划,并执行,kafka会按照该计划进行相应的资源分配。
服役:
- 启动新的broker
bin/kafka-server-start.sh -daemon ./config/server.properties
- 以json格式文件的形式,编辑要负载均衡的topic
{"topics":[{"topic": "test"}], "version": 1}
- 预执行该json文件生成执行计划,将要退役的broker加入到计划中
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop11:9092 --topics-to-move-json-file topics-to-move.json --broker-list "0,1,2,3" --generate
- 编辑该json格式的执行计划
{"version":1,"partitions":[{"topic":"test","partition":0,"replicas":[3,2,0],"log_dirs":["any","any","any"]},{"topic":"test","partition":1,"replicas":[0,3,1],"log_dirs":["any","any","any"]},{"topic":"test","partition":2,"replicas":[1,0,2],"log_dirs":["any","any","any"]}]}
- 指定该执行计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop11:9092 --reassignment-json-file increase-replication-factor.json --execute
6.查看该计划的执行
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop11:9092 --reassignment-json-file increase-replication-factor.json --verify
退役:
- 以json格式文件的形式,编辑要负载均衡的topic
- 预执行该json文件生成执行计划,将要退役的broker剔除计划外,与服役的第3步类似
- 编辑该json格式的执行计划
- 指定该执行计划
Kafka中leader follower 宕机后重连,数据如何同步?
Offset: 消息在底层存储中的索引位置, 唯一标识了一条消息,消费者通过(offset,partition,topic)跟踪记录
LEO (Log End Offset) : 每个副本的最后一个offset的后一位 ,即offset + 1;
HW (High Watermark) : 所有副本中最小LEO;
Leader宕机重连
- 当某一parttion的leader宕机后,该partition 会重新选举出一个新的leader
- 当原leader重连后成为follower,并且Follower会将各自的log文件超出HW的部分清除掉,然后从新的leader同步数据,以保证副本之间的数据一致性,但有可能会造成数据丢失或重复。
Follower宕机重连
- 当某一follower宕机后会被移出ISR
- 在其宕机期间其他ISR成员继续接收数据
- 当该Follower重连后,会读取本地磁盘记录的上次的HW,并将其log文件高于HW的部分清除,从HW开始同步数据
- 当该Follower 的LEO ≥该Partition 的HW,即Follower 的数据更新程度追上Leader时,重新加入ISR
kafka中初始化的时候Leader选举有一定的规律,如何打破这个规律?
选举leader时,会将leader均匀分布在各个broker上,避免Leader全部宕机.
- 创建副本存储计划,利用leader总是选举第一个副本为leader的机制,将副本按顺序写入,放在第一位的副本编号每次+1,例如:分区0 的副本是0,1,2,分区1就是1,2,0 ……依次添加,这样得到的各个分区的leader都会是编号为0的
- 执行副本存储计划
- 查看topic情况
kafka如何实现高效读写
1. 稀疏索引
使用稀疏索引,使得存取数据的效率更高
2. 顺序写入磁盘
Kafka的生产者数据,写入到log文件中是追加到文件末尾,顺序写入可达到600m/s ,而随机写只有100k/s。顺序写之所以快,是因为其省去了大量磁头寻址的时间。
3. 页面缓存 pagecache
- 从充分利用了所有空闲内存存放数据(非JVM内存),这样可以减少JVM的GC操作
- 上层写数据时,会将数据写入pagecache,再写入磁盘,也就是等一段时间再落盘,减少磁盘头的移动时间
- 读数据时,会先从pagecache中查找,如未找到,再到磁盘中读取,类似mysql的bufferpool部分机制
4. 零拷贝
这里并非不拷贝,而是减少中间拷贝次数(在IO过程中)
传统的IO 需要1-4次拷贝
- 系统将磁盘文件读取到系统的内核缓冲区
- 文件数据又被拷贝到用户缓冲区(也就是application应用程序的缓冲区)
- 将用户缓冲区中的数据拷贝到socket网络发送缓冲区
- 将socket缓冲区的数据拷贝到网卡 进行传输
而kafka将该过程简化成:
网络数据持久化到磁盘文件 ,再通过网络发送
Producer—> Broker —> consumer
(减少了io次数)
Kafka集群中数据的存储方式?
Topic是一组消息的抽象,是逻辑上的概念,而partition是物理上的概念,每个partition对应于一个log(抽象概念),
为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制,将每个partition也就是log分为多个segment。每个segment包括:“.index”文件、“.log”文件和.timeindex等文件。这些文件位于一个文件夹下。Producer生产的数据会被不断追加(顺序写入)到该.log文件末端。该文件夹的命名规则为:topic 名-分区号
其中,每个LogSegment中的日志数据文件大小均相等(该日志数据文件的大小可以通过在Kafka的config/server.properties配置文件的中的“log.segment.bytes”进行设置,默认为1G大小.
而kafka记录索引采用稀疏索引的方式,大约每往.log文件中写入4KB数据,会向index文件吸入一条索引,(log.index.inerval.bytes),默认4kb。
kafka中如何快速定位到一个offset的?
- 查找时,根据指定的偏移量,使用二分法查询定位出该偏移量对应的消息所在的分段索引文件和日志数据文件。
- 由于index文件名记录的是绝对索引(起始索引),根据目标offset定位到Segment。
- 此时只需要通过二分查找法,查找出小于等于目标offset的最大offset对应的索引项,同时也得出了对应的position(实际物理位置)
- 根据该物理位置,在分段的日志(.log)数据文件中顺序扫描查找偏移量与指定偏移量相等的消息。
这样做的好处:
1. 把topic中一个parition大文件拆分成多个小文件段,易定期清除或删除已消费完文件,节省磁盘空间。
2. 通过索引可快速定位message和确定response的最大大小。
3. 通过index元数据全部映射到memory,可以避免segment file的IO磁盘操作。
4. 通过索引文件稀疏存储,可以大幅降低index文件元数据占用空间大小。
简述kafka中的数据清理策略。
两种策略,清除不必要的数据(删除),合并可能用到的数据(合并)
配置项 | 配置值 | 说明 |
log.cleaner.enable | true(默认) | 开启自动清理日志功能 |
log.cleanup.policy | delete(默认) | 删除日志 |
log.cleanup.policy | compaction | 压缩日志 |
log.cleanup.policy | delete,compact | 同时支持删除、压缩 |
删除策略
默认的数据(就是Segment)保存时间为 7 天
基于时间的删除策略:
log.retention.hours,最低优先级小时,默认 7 天。即168h
log.retention.minutes,分钟。 --如果设置了该值,小时的设置不起作用。
log.retention.ms,最高优先级毫秒。 --如果设置了该值,分钟的设置不起作用。
log.retention.check.interval.ms,负责设置检查周期,默认 5 分钟。
基于大小的删除策略:log.segment.bytes 日志分段文件的最大大小
log.retention.bytes,默认等于-1,表示无穷大。
合并策略
对于相同key的不同value值,只保留最后一个版本。
压缩后的 offset 可能是不连续的,只适合特殊场景,比如消息的 key 是用户 ID , value 是用户的资料,通过这种压缩策略,整个消息 集里就保存了所有用户最新的资料。
消费者组和分区数之间的关系?
1.不同消费者组可以消费同一分区,也就是一个分区可对应多个消费者组,消费者组之间互不影响
2.但同一消费者组内的每一个消费者实例只能消费一个分区,不能重复消费,同一消费者组中的消费者实例数量不应该超过分区的数量,否则会导致某些消费者实例没有分区可分配,从而无法进行消费。通常,为了实现更好的并行性和负载均衡,消费者实例的数量应该接近或略大于分区的数量。
kafka消费者的消费分区策略有哪些,默认什么?
四种主流的分区分配策略
Range、RoundRobin(轮询)、Sticky(粘性)、CooperativeSticky(配合的粘性)。
参数partition.assignment.strategy
默认策略是Range + CooperativeSticky。Kafka可以同时使用多个分区分配策略。
kafka如何了解哪一个消费者消费了哪一个分区?
查看消费者分区策略:主要分为4种:Range、RoundRobin(轮训)、Sticky(粘性)、CooperativeSticky(配合的粘性)。
假设现在有一个topic 分为8个分区,三个消费者去消费
Range
通过partition数量/consumer数量决定该消费者消费多少分区,如有余数,由前面几个消费者均分,
此时,C0 消费的分区为p0,p1,p2
c1消费的分区为p3,p4,p5
C2消费的分区为p6,p7
如果有较多的topic容易导致数据倾斜
RoundRobin
把所有的partition和所有的消费者都列举出来,根据hashcode进行排序,通过轮询算法来分配partition ,通俗点讲,就是拿着partition 挨个塞到消费者手中
C0 消费的分区为p0,p3,p6
C1 消费的分区为 p1,p4,p7
C2消费的分区为 p2,p5
Sticky
带有粘性的分配策略,即在执行一次新的分配之前, 考虑上一次分配的结果,尽量少的调整分配的变动,可以节省大量的开销。这样做的目的是为减少发生重平衡后,消费者组重新组建带来的分区重新分配的次数,降低资源的消耗
通常与其他机制配合使用的效果较好
原:
C0 消费的分区 p0, p1 ,p2
C1 消费的分区 p3,p4,p5
C2 消费的分区 p6 , p7
当c0消费者挂掉后(消费者组需要按照超时时间 45s 来判断它是否退出),可能的分区情况:
C1 消费的分区 p3 p4 p5 p0
C2 消费的分区 p6 , p7 p1 p2
kafka中的消费者的offset偏移量存储位置?
1. Kafka0.9 版本之前, consumer 默认将 offset 保存在 Zookeeper 中。
2. 从 0.9 版本开始, consumer 默认将 offset 保存在 Kafka 一个内置的topic 中,该 topic 为 __consumer_offsets
_consumer_offsets 中采用 k v的方式存储数据 。 key 是 group.id+topic+分区号 , value 就是当前 offset 的值。每隔一段时间, kafka 内部会对这个 topic 进行compact ,就是定时更新offset 。
如何解决kafka中数据堆积的问题?
也即提高吞吐量的问题
积压造成的原因,大致概括为:
1.生产侧问题:上游数据激增,由于业务系统,访问量徒增,如热点事件,热门活动等,导致了大量的数据涌入业务系统,有可能导致消息积压
2.消费侧问题
①消费能力不足
②消费端每次获取数据过少
3.数据倾斜问题
kafka数据倾斜问题: producer 写入数据时候设置的key 发生数据倾斜,导致过度数据写入少量partition。
解决方案
1.生产和消费侧的问题需要扩容消费者,增加消费能力
①若kafka端消费能力不足,可以考虑增加Topic的分区数量,并提升消费组的消费者数量 (消费者数=分区数)
②若消费者端的数据拉取的不及时(拉取数据/处理时间 < 生产速度),可以提高每批拉取的数据量。
2.如果是数据倾斜问题,则要在消息分区时加盐,或者自定义其他合适的分区策略,均匀分发数据
如何处理Kafka漏消费和重复消费的问题?
重复消费问题
- 消费者异常
可能开启了自动提交,每5s提交一次offset,而在提交后的5s内,consumer因为网络波动,在很短的时间内断线后重连,会从上次提交的offset继续消费,导致部分数据重复
- 消费者消费时间过长
消费者max.poll.interval.ms(两次拉取的最大时间间隔,默认5分钟)时间内,无法消费消息,会主动发起离组的请求,然后发生rebanlance,offset会提交失败,再次分配分区后,消费者拉取消息仍从之前提交的offset处拉取消息,这样造成重复消费
解决方案
- 解决消费端异常的问题
将Kafka消费端将消费过程和提交offset 过程做原子绑定。此时需要将offset保存到支持事务的自定义介质(比 如MySQL)
- 解决消费时间过长的问题
在缩短单条消息消费时常的同时,根据实际场景可将max.poll.interval.ms值调大,避免不必要的rebalance,同时适当调减小max.poll.records的值,默认值是500。
漏消息
可能有三部分原因
生产者丢失消息
- 基本上 Producer 都是异步发送消息的,如使用producer.send(msg) 方法来发送消息,方法会立即返回,但这并不能代表消息已发送成功。
- 如果消息在发送的过程中发生网络波动,则消息有可能没有传递到 Broker,造成消息丢失。\
- 果发送的消息格式不符合,如大小超过了 Broker 的承受能力等情况,也会造成消息丢失。
Broker 服务端丢失消息
- 如果发生Leader宕机,触发选举,集群选举了一个落后 Leader 太多的 follower作为 Leader,则相差的消息就会丢失。
- Kafka使用了页缓存机制,将消息先写入页缓存而不直接持久化至磁盘,采用异步批量刷盘机制,如果刷盘前,Broker 宕机,重启后在页缓存的这部分消息则会丢失。
消费者丢失消息
- 消费者拉取并且提交了偏移量,但在处理消息时出现异常导致失败,或者在消息处理结束之前突然发生了宕机等故障,消费者重启后,会从之前已提交的位移的下一个位置重新开始消费,消费失败的那些消息不会再次处理,也就是消费者丢失了那部分消息。
解决方案
生产侧
①尽量不用producer.send(msg)方法,使用producer.send(msg, callback), 带回调通知的 send 方法可对发送失败的消息进行重试处理。设置acks = all,所有lsr成员都接收到消息才算成功
- 设置
retries = 3
,
重试三次
- 设置
retry.backoff.ms = 300
,估算重试时间间隔,避免无效的重试
Broker 端
- 设置unclean.leader.election.enable = false ,禁止不完整的副本成为 leader,避免落后的follower称为leader
- 设置
min.insync.replicas > 1
。消息至少要被写入到多少个副本才算是“已提交”。避免设置为1 - 确保 replication.factor > min.insync.replicas。如果两者相等,则只要有一个副本挂机,整个分区就无法正常工作了。可设置成 replication.factor = min.insync.replicas + 1。
消费端
- 设置
enable.auto.commit = false
,确保消息消费完成再提交,采用手动提交位移的方式。
kafka中的数据已经消费过的数据,是否可以再次消费?怎么做?
可以,只要消息存在(消息存在的规则取决于设置的定期清除数据的策略)
需要指定offset消费
设置 auto.offset.reset = earliest | latest | none 默认是 latest。
(1)earliest:自动将偏移量重置为最早的偏移量,--from-beginning
(2)latest(默认值):自动将偏移量重置为最新偏移量。
(3)none:如果未找到消费者组的先前偏移量,则向消费者抛出异常
使用consumer的 seek(TopicPartition,offset)方法,指定偏移量读取
package com.bigdata.kafka.consumer;
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 org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Set;
public class CustomConsumerSeek {
public static void main(String[] args) {
Properties properties = new Properties();
// 连接kafka
properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop11:9092");
// 字段反序列化 key 和 value
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
StringDeserializer.class.getName());
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
StringDeserializer.class.getName());
// 配置消费者组(组名任意起名) 必须
properties.put(ConsumerConfig.GROUP_ID_CONFIG, "test");
properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,false);
KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<String, String>(properties);
// 2 订阅一个主题
ArrayList<String> topics = new ArrayList<>();
topics.add("first");
kafkaConsumer.subscribe(topics);
// 执行计划
// 此时的消费计划是空的,因为没有时间生成
Set<TopicPartition> assignment = kafkaConsumer.assignment();
while(assignment.size() == 0){
// 这个本身是拉取数据的代码,此处可以帮助快速构建分区方案出来
kafkaConsumer.poll(Duration.ofSeconds(1));
// 一直获取它的分区方案,什么时候有了,就什么时候跳出这个循环
assignment = kafkaConsumer.assignment();
}
for (TopicPartition tp:assignment) {
kafkaConsumer.seek(tp,10);
}
while(true){
//1 秒中向kafka拉取一批数据
ConsumerRecords<String, String> records = kafkaConsumer.poll(Duration.ofSeconds(1));
for (ConsumerRecord<String,String> record :records) {
// 打印一条数据
System.out.println(record);
// 可以打印记录中的很多内容,比如 key value offset topic 等信息
System.out.println(record.value());
}
}
}
}