共计 3647 个字符,预计需要花费 10 分钟才能阅读完成。
原理至关重要,面试的时候不可能问你命令的,都是问原理,懂了原理线上如果应用 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 的网络设计
- 客户端将申请发送给 Acceptor,broker 里有 3 个 processor 的线程(默认是 3),Acceptor 不会对客户端的申请做任何的解决,而是封装成 socketChannel,而后发送给 3 个 processor 线程,造成一个队列。发送的形式是轮询,就是发送给第一个 processor,而后是第二个,第三个 …
- 消费者线程会以 request 申请去生产这些 socketChannel;
- 线程池外面默认有 8 个 ReaderThreadPool 线程,这些线程是用来解决 request 的,解析申请,返回响应后果 response;
- 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 服务器上接管音讯。