跳至主要內容

Kafka

张启忻大约 9 分钟使用指南页面配置使用指南

more 注释之前的内容被视为文章摘要。

Kafka的基础架构

kafka的基础架构 (1) Producer :消生产者,就是向kafka中发送消息(写入消息)
(2) consumer: 消费者,向kafka中拉取消息进行消费
(3) Consumer Group (CG):消费者组,由多个consumer组成。消费者组。消费者组中有多个消费者,一般是一个消费者组消费一个topic, 消费者组中的所有的消费者就可以各自消费对应的分区数据就可以了。

一般group中的consumer的个数和Topic的分区数相等。如果group中的consumer大于Topic的分区数,多余的消费者不会工作。 如果group中的consumer小于Topic的分区数,则需要一个consumer去消费多个分区。

(4) broker: kafka的节点,partition数据就是保存在broker上面
(5) Topic(主题) :在工作中一般是一个业务一个主题,好处就是数据分类之后比较好处理。

topic是逻辑上的概念,而partition是物理上的概念,parrtition才是真正存储数据的。

(6) Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition, 每个partition是一个有序的队列。这样做有2个好处(即分区的原因):

  • 实现数据的分布式存储
  • 提高并行度以及吞吐量

(7) Replica:副本,提高partition的数据的高可用。一个topic的每个分区都有若干个副本,其中包含一个leader和若干个follower。
(8) leader:每个分区多个副本的“主”,生产者向partition中写入消息的时候也是向leader写入,消费者消费partition数据的时候是找leader消费。
(9) follower:每个分区多个副本中的“从”,实时从leader中同步数据,保持和leader数据的同步。leader发生故障时,某个follower会成为新的leader。
(10) offset:用来标识消费者上次消费到了partition的哪条数据(每个消费者都有自己的offset)

重要的事情说一遍

自kafka-2.1.x以后offset的存储就移至broker内,存在一个叫做__consumer_offsets的topic内,其记录着consumeGroup和每个topic-partition的offset信息
自kafka-2.8.x以后kafka新增了去除zookeeper的KRaft一致性算法协议,这样就可以不再依赖zookeeper。
查阅源码发现kafkaAdmin的相关操作最好不由代码控制而是通过命令或者工具操作,非得想写代码可以继承KafkaAdminClient或者把代码写在这个类的同包下

  • kafka由于每个topic数据分布在broker的多个目录下,topic-partition对应一个目录,所以它的写入吞吐量超高,但是这点有利有弊,由于多目录那么当集群 中topic过多(其实应该是topic-partition过多)时,由于同时写入这样文件系统需要不断的切换目录,不断磁盘寻址,就会达到性能瓶颈,降低吞吐率
  • kafka broker只支持异步刷盘,主要原因也是由于以上的多目录
  • kafka producer是线程安全的,可以提高线程数来提高写入速度,代价就是需要更多producer实例、对应的更多独立缓冲区
  • kafka consumer默认也是单线程的,也可以使用多线程提高消费速度,但是由于一个partition最多对应一条线程消费,所以当分区数固定后,他的消费线程就是他的极限
  • kafka producer是通过push的方式写入数据
  • kafka consumer是通过pull的方式消费数据

Kafka Topic的创建和删除

  • 其实kafka topic的创建和删除主要操作都是在操作zookeeper. 都是在对应zookeeper目录下创建子节点,然后kafka的controller监控到对应的数据变化, 会把操作放到创建或者删除topic的队列中进行后续操作
  • 创建 - /kafka/config/topics 节点下创建节点,但是不止如此(如果你手动插入topic节点比如:example节点,数据是{"version":1,"config":{}}) 那么不像你预期的那样创建topic,因为没有partition、replica相关的信息
  • 删除 - /kafka/admin/delete_topics 节点下创建节点(这些节点名就是topic名),那么会和你预期的那样把kafka的这个topic删除

Kafka Producer的发送流程

Kafka Producer发送消息时,首先有一条用户主线程,也就是创建Kafka Producer的线程将要发送的消息封装成ProducerRecord实例,然后把这个实例序列化后发送到分区器Partitioner,分区器根据本地元数据信息确定消息的目标分区,一同发送到一块内存缓冲区。Kafka Producer有一条专门线程用于发送叫做sender I/O,它负责从缓冲区取出准备就绪的消息数据封装成一个批次batch,然后发送给对应的broker。
Kafka Producer发送流程

记录一个有趣的现象

理论上说:kafka同一个时刻每个topic-partition只能有一个消费者实例消费。 如果同一个消费者组内要是部分消费者实例提交offset,部分不提交会发生什么样的情况呢?凭空想应该是部分的topic-partition offset得到更新,部分不更新。 前提都在同一个消费者组内,如果第一次有n个消费实例消费,第二次增加了m个就是n+m个消费实例,那么kafka就会发生rebalance的动作。当n个提交offset,m个不提交 offset,就会出现上面的情况,但是整个消费过程都正常吧,n个消费实例和m个消费实例都应该有消费的。 But当Spark Streaming接kafka的时候(这边选择DStream方式)我发现当m个额外非Spark消费实例加入后,下一微批的Stream竟然没有流入到Spark内。也就是说 rebalance后n个消费实例没有消费,或者说Spark Streaming的DStream方式难道是中间断开的?

rebalance 本质上是个协议,规定了consumer group下的所有consumer如何来达成一致性的去订阅消费每个分区

角色: coordinator(协调者)、consumer(消费者) [consumer group(消费者组)] 之前: zookeeper协调,弊端强依赖zk,所有consumer都争抢注册zk没有优雅的协调 之后: 明确coordinator(协调者),如何确定?consumer group位移信息写入__consumers_offsets这个topic,它的分区leader所在的broker节点就是coordinator
所有consumer都和这个协调者通讯,这种通讯包括了5种请求。而consumer group也正好有5种状态,组成了状态机。(kraft协议) 详细参考:Kafka消费者组open in new window

kafka的listeners和advertised.listeners,配置内外网分流

  • listeners 指明 kafka 当前节点监听本机的哪个网卡
  • advertised.listeners 指明客户端通过哪个 ip 可以访问到当前节点

面试题常问

参考40道Kafka大厂高频面试题open in new window

kafka新建的分区会在哪个目录中创建

kafka新建的分区会优先在数据目录较少的kafka broker中创建。这里的数据目录就是对应每一个topic partition。

kafka的分区策略

  1. 轮询 roundrobin
  2. 范围 range

kafka数据的可靠性保证

kafka的数据可靠性是通过返回ack消息来保证,不同等级的ack代表不同的数据持久化机制。

  • ack=0 leader接收到消息后无论消息是否落盘就返回ack消息,这种情况有可能消息丢失,比如当消息落盘失败。
  • ack=1 leader接收消息并且本地持久化,但是不保证follower同步消息后返回ack消息,这种情况也有可能消息丢失,比如当leader收到消息 返回ack后leader挂掉,此时follower并没有同步到消息,而再从follower中选举了新的leader,那么这个消息就会丢失了。
  • ack=-1 leader接收到消息并且本地持久化,并且follower也同步到此消息持久化后再返回ack消息,这种情况有可能会消息重复发送,比如当 leader收到消息持久化,follower也同步到消息持久化,在leader返回ack消息前leader挂了,那么从follower中重新选举了新leader,它不会再次 返回ack消息,这个时候producer会重新发送消息,就会导致消息重复发送。

kafka的 Exactly Once语义

kafka有哪些设计让它有如此高的性能

  1. 顺序写磁盘,kafka的消息写入到log文件中是以追加到文件末尾的方式顺序写文件的。
  2. 应用Pagecache(页面缓存) pagecache是内存,理想情况下consumer直接从页面缓存中读取消息
  3. 操作系统的零拷贝技术(和上面的pagecache结合达到了理想情况,直接写入pagecache直接消费pagecache)
  4. 每个分区partition对应一个文件目录提高了系统的吞吐量

zookeeper在kafka中的作用

kafka中ISR、OSR、AR

kafka中LEO、HW、LSO、LW

kafka中怎么体现消息的顺序性

kafka的分区数可以增加或者减少吗

哪些场景会考虑选择kafka

聊一聊kafka的再均衡

kafka服务器默认一次最大接收的消息大小、默认的消息保存时间

spark如何消费kafka消息