Kafka在目前Java程序员的技术栈中还是处于非常重要的地位,先根据搜集到的文档,视频等资料,对Kafka的学习进行现阶段总结,本文中的代码片段图片来自于《Kafka权威指南》电子版截图。
1. 单机版Kafka架构模型图如下:
名词解释:
broker:一个独立的MQ服务器被称为broker。多个MQ服务器可组成broker集群。
producer:生产者,生成数据后把数据发送给消息队列的应用程序。
consumer:消费者,从消息队列中获取producer生成的消息。
consumer group:消费组,一个或多个消费者可选择组成一个消费组。在Kafka中,一个消费组里的消费者数量不能超过要消费的topic的分区个数,这会导致多出来的消费者不能获取到消息。
topic:主题,MQ存储消息时对消息的分类命名。不同的消费组可以同时消费同一个topic。
partition:分区,把一个主题分成多份,每一份就是一个分区。Kafka被称为分布式集群的主要原因是因为它指定topic下的数据并不是只在一个broker里,通过分区分布在集群各个broker里。
2. 生产者如何给Kafka发数据?
说明:
(1) 在生产者发送数据的时候,必须要指定topic,但是消息要发送的分区信息或者消息所属的key值,根据业务场景选择性的指定。例如,在Kafka中,partition里的所有消息都是顺序的。
对某些业务场景,要求消息必须是顺序被处理,那么在生产的时候,按照顺序生产,并为此类消息设置key值,那么相同key值的消息就会顺序的存储在Kafka的某个partition中。
(2)生产者发送消息有3种方式,代码图片如下:
发送并忘记,也是最简单的消息发送
同步发送:
异步发送。
(3)发送消息时部分相关配置参数:
acks。等于0,表示不等待服务器响应;等于1,表示等待leader节点收到消息并响应;等于all,表示等待leader + follow-copy节点都收到消息并响应。
retries。遇到异常时重试次数。
batch.size。生产者在把消息发送给分区时,会先把消息放在一个批次里,此表示一个批次的内存大小。
linger.ms。此为生产者把消息发送给分区时,等待更多消息加入到批次的时间。
max.request.size。表示一个批次里消息的最大值。有可能一条消息就达到了最大值,然后就不等待其他消息加入到批次,直接发送到Kafka。
3. 消费者是怎么从Kafka里消费消息的?
由最初始第一张图可以看到,消费Kafka消息的客户端是以消费组为单位的,消费组里会包含至少1个,最多有当前topic下partition个数的实际消费者。每个消费者应在自己的线程里去消费数据。
(1)消息轮询是消费者的核心。
(2)消费数据时部分相关配置参数:
fetch.min.bytes。消费者从服务器获取记录的最小字节数。
fetch.max.wait.ms。指定broker等待时间,满足此配置或fench.min.bytes,Kafka就会返回消息。
max.partition.fetch.bytes。从每个分区返回给消费者的最大字节数。
auto.offset.reset。默认值为latest,在偏移量无效时,意味从最新消息开始返回。earliest,在偏移量无效时,意味从起始位置读取记录。
max.poll.records。单次调用call()方法能返回的消息数量。
(3)偏移量:消息在Kafka分区里的位置。
把更新分区当前位置的操作,称为提交。
自动提交偏移量:enable.auto.commit被设置为true就是自动提交偏移量,它默认每隔5秒提交一次,时间间隔由配置项auto.commit.interval,ms控制。
提交当前偏移量:将enable.auto.commit设置为false。使用commitSync()提交,代码片段如下:
异步提交偏移量:避免手动提交带来的阻塞问题。将enable.auto.commit设置为false,使用commitAsync()提交。
(4)使用没有群组的消费者
一个消费者可以加入到消费者群组去订阅主题消费数据,或者为自己分配要消费的分区,但是不能同时做这两件事。
4. Kafka 集群
如上图所示,
此kafka集群有三个broker(节点,Kafka服务器),
某个topic被设置有三个分区partition,这三个分区会被均匀分在这三个节点。
每个分区的复制系数是3,所以每个分区除了leader副本之外,还会有2个跟随副本。
生产请求:如果acks=1,leader副本搜到消息就认为写入成功;如果acks=all,那么需要所有副本都收到消息才算写入成功。
获取请求:向broker请求topic,分区里具有特定偏移量的消息。如果偏移量存在,broker将按照客户端指定的数量上限从分区里读取消息,再把消息返回给客户端。如果偏移量不存在,就返回错误。
生产请求和获取请求都必须发送给分区的leader副本,如果broker收到的请求针对的特定分区的leader在另一个broker上,就会给客户端返回一个“非分区首领”的错误响应,然后客户端就会采用重试机制,负责把生产请求和获取请求发送到正确的broker上。
kafka为每个分区维护了一个索引,通过索引可以映射到片段文件和偏移量在文件的位置。
kafka会根据设置的清理条件,把超过时效的旧数据删掉。默认是1G数据或7天。
5. Kafka的复制机制:
所有事件(数据写入和获取)都是针对首领副本的,其他副本只需要与首领保持同步,并及时复制最新事件。当首领副本挂掉后,使用配置项 unclean.leader.election.enable = true 可以从剩下副本中选择一个成为新的首领(也就是“不完全的选举”),也可设置为false等待原先的首领重新上线。
配置项min.insync.replicas意味最少同步副本数。这个数值要稍微大一点,例如在有3个同步副本时,将它设置为2,表示在至少有2个同步副本可用的情况下才能向分区发送消息。如果存活的副本数小于2,生产者就会得到异常NotEnoughReplicasException异常。当它剩余1个同步副本时,就变成只读了,这是为了避免在发生不完全选举时数据的写入和读取出现非预期的行为。