深入理解Kafka:核心设计与实践原理

2020-02-04  本文已影响0人  一蓬蒿人

第一章 初始Kafka

基本概念

第二章 生产者

客户端参数

消息发送

客户端架构

元数据是指 Kafka 集群的元数据,这些元数据具体记录了集群中有哪些主题,这些主题有 哪些分区,每个分区的 lead巳r副本分配在哪个节点上, follower副本分配在哪些节点上,哪些副 本在 AR、 ISR 等集合中,集群中有哪些节点,控制器节点又是哪一个等信息。

重要参数

  1. acks:用来指定分区中必须要有多少个副本收到这条消息,之后生产者才会认为这条消 息是成功写入的
    • acks=1:默认值,生产者发送消息之后,只要分区的 leader副本成功写入消 息,那么它就会收到来自服务端的成功响应;
    • acks=0:生产者发送消 息之后不需要等待任何服务端的响应;
    • acks=-1或all:生产者在消息发送之后,需要等待ISR中的所有副本都成功写入消息之后才能够收到来自服务端的成功响应。
  2. max.request.size:用来限制生产者客户端能发送的消息的最大值,默认值为 1048576B,即1MB
  3. retries和retry.backoff.ms
    • retries:重试次数
    • retry.backoff.ms:两次重试之间的时间间隔,默认100

第三章 消费者

消费者和消费组

消费者( Consumer)负责订阅 Kafka 中的主题( Topic),并且从订阅的主题上拉取消息。 与其他一些消息中间件不同的是:在 Kafka 的消费理念中还有一层消费组( Consumer Group) 的概念,每个消费者都有 一个对应的消费组。当消息发布到主题后,只会被投递给订阅它的每 个消费组中的一个消费者 。


客户端开发

消费逻辑步骤:

  1. 配置消费者客户端参数及创建相应的消费者实例;
  2. 订阅主题;
  3. 拉取消息并消费;
  4. 提交消费位移;
  5. 关闭消费者实例。

订阅方式

消息消费

位移提交

在旧消费者客户端中,消费位移是存储在 ZooKeeper 中的。而在新消费者客户端中,消费位移存储在Kafka内部的主题_consumer_offsets中。这里把将消费位移存储起来(持久化)的 动作称为“提交”,消费者在消费完消息之后需要执行消费位移的提交。



不过需要非常明确的是,当前消费者需要提交的消费位移并不是 x,而是 x+l,对应于图中的position,它表示下一条需要拉取的消息的位置。
提交参数:

指定消费位移

seek()方法为我们提供了从特定位置读取消息的能力,我们可以通过这个方法来向前跳过若 干消息,也可以通过这个方法来 向后回溯若干消息,这样为消息的消费提供了很大的灵活性。 seek()方法也为我们提供了将消费位移保存在外部存储介质中的能力 , 还可以配合再均衡监听器 来提供更加精准的消费能力。

再均衡

指分区的所属权从一个消费者转移到另一消费者的行为,它为消费组具备高可用
性和伸缩性提供保障,可安全地在消费组中删除或添加消费者。不过在再均衡发生期间,消费组会变得不可用。

多线程实现

第四章 主题与分区

主题管理

主题和分区都是提供给上层用户 的抽象,而在副本层面或更加确切地说是Log层面才有实际物理上的存在。同一个分区中的多个副本必须分布在不同的 broker 中。


分区管理

优先副本选举

优先副本是指在AR集合列表中的第一个副本。

分区重分配

  1. 首先创建需要一 个包含主题清单的 JSON 文件;
  2. 其次根据主题清单和broker节点清单生成一份重分配方案;
  3. 最后根据这份方案执行具体的重分配动作。
    分区重分配本质在于数据复制,先增加新的副本,然后进行数据同步,最后删除旧的副本来达到最终的目的。

第五章 日志存储

Log和LogSegnient 也不是纯粹物理意义上的概念,Log在物理上只以文件夹的形式存储,而每个LogSegment 对应于磁盘上的一个日志文件和两个索引文件,以及可能的其他文件。



为了便于消息的检索,每个 LogSegment 中的日志文件(以“ .log”为文件后缀)都有对应的两个索引文件:

日志格式

日志索引

偏移量索引

时间戳索引

日志清理

日志删除

日志压缩

Log Compaction执行前后,日志分段中的每条消息的偏移量和写入时的偏移量保持一致。Log Compaction会生成新的日志分段文件,日志分段中每条消息的物理位置会重新按照新文件 来组织。Log Compaction 执行过后的偏移量不再是连续的,不过这并不影响日志的查询。

磁盘存储

页缓存

操作系统实现的一种主要的磁盘缓存,以此用来减少对磁盘 I/O 的操作。

I/O流程


I/O调度策略:

零拷贝

将数据直接从磁盘文件复制到网卡设备中,而不需要经过应用程序,减少了内核和用户模式之间的上下文切换。对Linux操作系统而言,零拷贝技术依赖于底层的 sendfile()方法实现。对应于Java语言,FileChannal.transferTo()方法的底层实现就是sendfile()方法。




零拷贝技术通过DMA(Direct Memory Access)技术将文件内容复制到内核模式下的Read Buffer中。不过没有数据被复制到Socket Buffer,相反只有包含数据的位置和长度的信息的文件描述符被加到Socket Buffer中。DMA引擎直接将数据从内核模式中传递到网卡设备(协议引擎)。这里数据只经历了2次复制就从磁盘中传送出去了,并且上下文切换也变成了2次。零拷贝是针对内核模式而言的,数据在内核模式下实现了零拷贝。

第六章 深入服务端

时间轮


Kafka中的时间轮( TimingWheel)是一个存储定时任务的环形队列,底层采用数组实现,数组中的每个元素可以存放一个定时任务列表( TimerTaskList)。TimerTaskList是一个环形的双向链表,链表中的每一项表示的都是定时任务项( TimerTaskEntry),其中封装了真正的定时任务 (TimerTask) 。



用TimjngWheel做最擅长的任务添加和删除操作,而用DelayQueue做最擅长的 时间推进工作。

控制器

控制器选举

第七章 深入客户端

分区分配策略

事务

消息中间件的消息传输保障有 3个层级:

幂等

对接口的多次调用所产生的结果和调用一次是一致的。Kafka使用幂等解决生产者在进行重试的时候有可能会重复写入消息问题。

事务

事务可以保证对多个分区写入操作的原子性。Kafka 中的事务可以使应用程序将消费消息、生产消息 、 提交消费位移当作原子操作来处理,同时成功或失败,即使该生产或消费会跨多个分区 。

第八章 可靠性探究

副本剖析

失效副本

ISR伸缩

LEO和HW

Leader Epoch

解决基 于HW的同步机制可能会出现的数据丢失或leader副本和follower副本数据不一致的问题。
在需要截断数据的时候使用leader epoch作为参考依据而不是原本的HW。leader epoch代表leader的纪元信息( epoch),初始值为0。每当leader变更一次, leader epoch的值就会加1,相当于为leader增设了一个版本号。与此同时,每个副本中还会增设一个矢量<LeaderEpoch=> StartOffset>,其中StartOffset表示当前LeaderEpoch下写入的第一条消息的偏移量。

上一篇下一篇

猜你喜欢

热点阅读