本文借鉴:再过半小时,你就能明白kafka的工作原理了(特此感谢!)

一、发送数据

PS:Producer在写入数据的时候永远的找leader,不会直接将数据写入follower

1、follower的同步流程:

kafaka 写入mongodb kafka写入流程_kafaka 写入mongodb

PS:消息写入leader后,follower是主动的去leader进行同步的!

PS:producer采用push模式将数据发布到broker,每条消息追加到分区中,顺序写入磁盘,所以保证同一分区内的数据是有序的

PS:不存在的topic写数据,kafka会自动创建topic,分区和副本的数量根据默认配置都是1。

2、分区

主要目的:

方便扩展。因为一个topic可以有多个partition,所以我们可以通过扩展机器去轻松的应对日益增长的数据量。
提高并发。以partition为读写单位,可以多个消费者同时消费数据,提高了消息的处理效率。

分发策略:

1、 partition在写入的时候可以指定需要写入的partition,如果有指定,则写入对应的partition。
  2、 如果没有指定partition,但是设置了数据的key,则会根据key的值hash出一个partition。
  3、

3、ACK应答机制

在生产者向队列写入数据的时候可以设置参数来确定是否确认kafka接收到数据,这个参数可设置的值为0、1、all。(保证消息不丢失)

0:代表producer往集群发送数据不需要等到集群的返回,不确保消息发送成功。安全性最低但是效率最高。
  1:代表producer往集群发送数据只要leader应答就可以发送下一条,只确保leader发送成功。
  all:代表producer往集群发送数据需要所有的follower都完成从leader的同步才会发送下一条,确保leader发送成功和所有的副本都完成备份。安全性最高,但是效率最低。

二、保存数据

Kafka初始会单独开辟一块磁盘空间,顺序写入数据(效率比随机写入高),将数据保存在磁盘。

1、Partition 结构

log文件就实际是存储message的地方,而index和timeindex文件为索引文件,用于检索消息

kafaka 写入mongodb kafka写入流程_kafka_02

每个log文件的大小是一样的,但是存储的message数量是不一定相等的(每条的message大小不一致)。文件的命名是以该segment最小offset来命名的,如000.index存储offset为0~368795的消息,kafka就是利用分段+索引的方式来解决查找效率的问题

2、Message结构

log文件就实际是存储message的地方,我们在producer往kafka写入的也是一条一条的message,message主要包含消息体、消息大小、offset、压缩类型……等等

offset:offset是一个占8byte的有序id号,它可以唯一确定每条消息在parition内的位置!
消息大小:消息大小占用4byte,用于描述消息的大小。
消息体:消息体存放的是实际的消息数据(被压缩过),占用的空间根据具体的消息而不一样。

3、存储策略

存在磁盘)。那对于旧数据有什么删除策略呢?
    基于时间,默认配置是168小时(7天)。
    基于大小,默认配置是1073741824。
  需要注意的是,kafka读取特定消息的时间复杂度是O(1),所以这里删除过期的文件并不会提高kafka的性能

三、消费数据

Kafka采用的是点对点的模式,消费者主动的去kafka集群拉取消息,与producer相同的是,消费者在拉取消息的时候也是找leader去拉取

  • 多个消费者可以组成一个消费者组(consumer group),每个消费者组都有一个组id。
  • 同一个消费组的消费者可以消费同一topic不同分区的数据,但是不会组内多个消费者消费同一分区的数据!!!
  • 消费者数少于分区:会出现某个消费者消费多个partition数据的情况(此时消费的速度不及只处理一个partition的消费者的处理速度)
  • 消费者数多于分区:多出来的消费者不消费任何partition的数据。
  • 建议消费者组的consumer的数量与partition的数量一致!

四、搜索数据

1、搜索数据样例解析

假如现在需要查找一个offset为368801的message是什么样的过程呢?用一个例子来解释一下搜索过程

 

kafaka 写入mongodb kafka写入流程_大数据_03

  1、 先找到offset的368801message所在的segment文件(利用二分法查找),这里找到的就是在第二个segment文件。

  2、打开找到的segment中的.index文件(也就是368796.index文件,该文件起始偏移量为368796+1,我们要查找的offset为368801的message在该index内的偏移量为368796+5=368801,所以这里要查找的相对offset为5)。由于该文件采用的是稀疏索引的方式存储着相对offset及对应message物理偏移量的关系,所以直接找相对offset为5的索引找不到,这里同样利用二分法查找相对offset小于或者等于指定的相对offset的索引条目中最大的那个相对offset,所以找到的是相对offset为4的这个索引。

  3、根据找到的相对offset为4的索引确定message存储的物理偏移位置为256。打开数据文件,从位置为256的那个地方开始顺序扫描直到找到offset为368801的那条Message。

  小结:这套机制是建立在offset为有序的基础上,利用segment+有序offset+稀疏索引+二分查找+顺序查找等多种手段来高效的查找数据!至此,消费者就能拿到需要处理的数据进行处理了。

2、消费者记录位置的方式:

早期的版本:消费者将消费到的offset维护zookeeper中,consumer每间隔一段时间上报一次,这里容易导致重复消费,且高并发时和ZK频繁交互,性能不好!

新的版本:消费者消费到的offset已经直接维护在kafk集群的__consumer_offsets这个topic中!