原理至关重要,面试的时候不可能问你命令的,都是问原理,懂了原理线上如果应用kafka出了问题才可能疾速定位,而不是一脸蒙圈。必须要明确原理,如果不说原理间接实战,就真成搬砖了。

Topic

创立一个TopicA的主题,3个分区别离存储在不同的服务器,留神Topic是一个逻辑上的概念。

Partition & Partition正本

Kafka的topic能够划分成一个或多个partition,Partition 是物理上的概念。如果一个topic的正本数设为3,那么每个partition对应还会有3个雷同的正本。下图咱们对TopicA的分区0,1,2别离设置了3个正本,再别离存储在broker0,1,2。

日志分段存储

因为生产者生产的音讯会一直追加到 log 文件开端,为避免 log 文件过大导致数据定位效率低下,Kafka 采取了分片和索引机制。

它将每个 Partition 分为多个 Segment,每个 Segment 对应两个文件:“.index” 索引文件和 “.log” 数据文件。

Leader & Follow

而且每个正本都是有角色之分的,它们会选举一个正本作为leader,其余的为follower。生产者在发送数据的时候,是间接发送到 leader partition,而后follower partition自行去leader进行数据同步,消费者生产数据的时候,也是从leader中生产数据。(下图在TopicA-partition-0在broker0是leader,同理其余TopicA-partition-N也有leader)

Consumer & Consumer group

一个生产组由一个或多个消费者实例组成,便于扩容与容错。一个分区不会让同一个消费者组外面的多个消费者去生产,一个消费者是能够去生产多个分区的数据的。

Kafka的网络设计

  1. 客户端将申请发送给Acceptor,broker里有3个processor的线程(默认是3),Acceptor不会对客户端的申请做任何的解决,而是封装成socketChannel,而后发送给3个processor线程,造成一个队列。发送的形式是轮询,就是发送给第一个processor,而后是第二个,第三个...
  2. 消费者线程会以request申请去生产这些socketChannel;
  3. 线程池外面默认有8个ReaderThreadPool线程,这些线程是用来解决request的,解析申请,返回响应后果response;
  4. processor会从response中读取响应数据,而后再返回给客户端。

所以如果咱们须要对kafka进行加强调优,减少processor并减少线程池外面的解决线程,就能够达到成果。request和response那一块局部其实就是起到了一个缓存的成果,是思考到processor们生成申请太快,线程数不够不能及时处理的问题。
所以这就是一个加强版的reactor网络线程模型。

Kafka零拷贝

传统IO:

//读取文件,再用socket发送进来buffer = File.read Socket.send(buffer)

1、第一次:将磁盘文件,读取到操作系统内核缓冲区;
2、第二次:将内核缓冲区的数据,copy到application应用程序的buffer;
3、第三步:将application应用程序buffer中的数据,copy到socket网络发送缓冲区(属于操作系统内核的缓冲区);
4、第四次:将socket buffer的数据,copy到网卡,由网卡进行网络传输。

传统形式,读取磁盘文件并进行网络发送,通过的四次数据copy是十分繁琐的。理论IO读写,须要进行IO中断,须要CPU响应中断(带来上下文切换),只管起初引入DMA来接管CPU的中断请求,但四次copy是存在“不必要的拷贝”的。

零拷贝:

Kafka应用的zero-copy的应用程序要求内核间接将数据从磁盘文件拷贝到套接字,而无需通过应用程序。零拷贝不仅大大地进步了应用程序的性能,而且还缩小了内核与用户模式间的上下文切换。

zookeeper在kafka集群中的作用

1、Broker注册

Broker是分布式部署并且互相独立,然而须要有一个注册零碎可能将整个集群中的Broker治理起来,此时就应用到了Zookeeper。在Zookeeper上会有一个专门用来进行Broker服务器列表记录的节点:/brokers/ids

每个Broker在启动时,都会到Zookeeper上进行注册,即到/brokers/ids下创立属于本人的节点,如/brokers/ids/[0...N]。

Kafka应用了全局惟一的数字ID来指代每个Broker服务器,创立完节点后,每个Broker就会将本人的IP地址和端口信息记录到该节点中去。其中,Broker创立的节点类型是长期节点,一旦Broker宕机,则对应的长期节点也会被主动删除。

2、Topic注册

在Kafka中,Topic的音讯分区与Broker的对应关系也都是由Zookeeper在保护,由专门的节点来记录,如:/borkers/topics

Kafka中每个Topic都会以/brokers/topics/[topic]的模式被记录,如 /brokers/topics/login 和 /brokers/topics/search 等。Broker服务器启动后,会到对应Topic节点(/brokers/topics)上注册本人的Broker ID,并写入该Topic的分区总数,如/brokers/topics/login/3->2,这示意Broker ID为3的节点对"login"这个Topic提供了2个分区进行音讯存储。同样,这个分区节点也是长期节点。

3、消费者注册

①、注册节点到消费者分组。每个消费者服务器启动时,都会到Zookeeper的指定节点下创立一个属于本人的消费者节点,例如/consumers/[group_id]/ids/[consumer_id],实现节点的创立后,消费者就会将本人订阅的Topic信息写入该长期节点。

②、对消费者分组中的消费者的变动注册监听。每个 消费者都须要关注所属消费者分组 其余消费者服务器的变动状况,即对/consumers/[group_id]/ids节点注册子节点变动的Watcher监听,一旦发现消费者新增或缩小,就触发消费者的负载平衡。

4、分区 与 消费者 的关系

在Kafka中,规定了每个音讯分区只能被同组的一个消费者进行生产,因而,须要在 Zookeeper 上记录 音讯分区 与 Consumer 之间的关系,每个消费者一旦确定了对一个音讯分区的生产势力,须要将其Consumer ID 写入到 Zookeeper 对应音讯分区的长期节点上,例如:

/consumers/[group_id]/owners/[topic]/[broker_id-partition_id]

其中,[broker_id-partition_id]就是一个 音讯分区 的标识,节点内容就是该 音讯分区 上 消费者的Consumer ID。

5、音讯生产进度Offset 记录

在消费者对指定音讯分区进行生产中,须要定时地将分区音讯的生产进度Offset记录到Zookeeper上,以便在该消费者进行重启或者其余消费者从新接管该音讯分区的音讯生产后,可能从之前的进度开始持续进行音讯生产。Offset在Zookeeper中由一个专门节点进行记录,其节点门路为:

/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]

节点内容就是Offset的值。

6、生产者负载平衡

因为同一个Topic音讯会被分区,并被散布在多个Broker上,因而,生产者须要将音讯正当地发送到这些分布式的Broker上,那么如何实现生产者的负载平衡,Kafka反对传统的四层负载平衡,也反对Zookeeper形式实现负载平衡。

(1) 四层负载平衡,通常,一个生产者只会对应单个Broker,而后该生产者产生的音讯都发往该Broker。这种形式逻辑简略,每个生产者不须要同其余零碎建设额定的TCP连贯,只须要和Broker保护单个TCP连贯即可。然而,其无奈做到真正的负载平衡,因为理论零碎中的每个生产者产生的音讯量及每个Broker的音讯存储量都是不一样的,如果有些生产者产生的音讯远多于其余生产者的话,那么会导致不同的Broker接管到的音讯总数差别微小,同时,生产者也无奈实时感知到Broker的新增和删除。

(2) 应用Zookeeper进行负载平衡,因为每个Broker启动时,都会实现Broker注册过程,生产者会通过该节点的变动来动静地感知到Broker服务器列表的变更,这样就能够实现动静的负载平衡机制。

7、消费者负载平衡

与生产者相似,Kafka中的消费者同样须要进行负载平衡来实现多个消费者正当地从对应的Broker服务器上接管音讯。