深入Kafka

深入Kafka

1、集群成员关系

  1. brocker启动时,通过创建临时节点,把自身ID注册到ZK;
  2. Kafka组件订阅broker在ZK上的注册路径,当有brocker加入集群或退出集群时,Kafka组件就可以获得通知;
  3. broker停机、长时间垃圾回收停顿时,导致会话超时,broker会从ZK上断开连接,此时broker在启动时创建的临时节点会自动从ZK上移除,监听broker列表的Kafka组件会被告知该broker已移除。

2、控制器

  1. 控制器就是一个broker,有额外的任务:负责分区首领的选举(后续了解);
  2. 第一个启动的broker通过在ZK创建一个临时节点:/controller,让自己成为控制器,其他broker再启动时也会尝试创建这个节点,但会收到节点已存在的异常;其他broker在该控制节点创建watch对象,可以收到控制节点的变更通知;
  3. 当控制器发觉一个broker已离开集群,则那些失去首领的分区需要一个新首领(这些分区的首领刚好在这个broker上)。控制器遍历分区,并确定新首领,然后向包含新首领的broker和包含跟随者的broker发送请求,该请求消息包含了谁是新首领以及谁是分区跟随者的信息。随后,新首领开始处理来自生产者和消费者的要求,跟随者从新首领那复制消息。

3、复制

  1. 副本类型

    leader:首领副本,所有生产者、消费者的请求都是经过这个副本;

    follower:跟随者副本,除首领副本以外的副本都是跟随者。跟随者副本不处理来自客户端的请求,唯一任务就是从首领那复制消息,保持与首领一致的状态。如果首领崩溃,其中一个跟随者会被提升为新首领。

  2. follower为了与leader保持同步,会向leader发送获取数据的请求(与消费者为了读取消息而发送的请求是一致的),leader将响应消息发给follower,响应消息包含了跟随者获取的消息的偏移量,这些偏移量是有序的。

  3. follower先请求消息1,收到响应后,接着请求消息2,收到相应后继续请求消息3…在消息响应收到之前不会发送获取下一个消息的请求。通过查看每个follower请求的最新偏移量,leader能够知道每个follower复制的进度,如果follower在规定时间内没有请求最新的数据,那么它会被认为是不同步的;相反,持续请求最新消息的副本被称为同步的副本;

    PS:其实严格一点讲,同步副本应该要满足两个条件:1、与ZK保持心跳;2、在过去一定时间(比如5s,可配置)从首领获取过最新的消息。

  4. AR、ISR、OSR

    1. AR(Assigned Repllicas):分区中的所有副本;
    2. ISR(In-Sync Replicas):所有与leader保持一定同步的副本(包括Leader),ISR集合是AR集合中的一个子集;
    3. OSR(Out-Sync Relipcas):与leader副本同步滞后过多的副本(不包括leader);
    4. AR=ISR+OSR,正常情况下AR=ISR,OSR为空。
  5. HW、LEO
    在这里插入图片描述

    1. LogStartOffset:第一条消息的offset,为0;
    2. HW(High Watermark):俗称高水位,标识了一个特定消息偏移量,消费者只能拉取到这个offset之前的消息;
    3. LEO(Log End Offset):标识当前日志文件中下一条待写入的消息的offset。上图中offset为9的位置即为当前日志文件的 LEO,LEO 的大小相当于当前日志分区中最后一条消息的offset值加1;
    4. 分区 ISR 集合中的每个副本都会维护自身的 LEO ,而 ISR 集合中最小的 LEO 即为分区的 HW,对消费者而言只能消费 HW 之前的消息;
  6. ISR集合与HW、LEO的关系

    1. 假设分区的ISR集合有3个副本,一个leader副本和2个follower副本,此时分区的LEO和HW分别为3。消息3、4从生产者出发后先存入leader副本。

      图一:
      在这里插入图片描述
      图二:
      在这里插入图片描述

    2. 在消息被写入leader之后,follower发送拉取请求来拉取消息3和4,进行消息同步。同步过程中不同副本的效率不同;如下图,在某一时刻follower1完全跟上了leader,而follower2只同步了消息3,此时leader副本的LEO为5,follower1的LEO为5,follower2的LEO为4,因此当前分区的HW取最小值4,此时消费者可以消费offset0至3的消息。
      在这里插入图片描述

    3. 当所有副本成功写入消息3、4之后,分区的HW和所有副本的LEO都变为5,此时消费者可以消费到offset为0至4的消息。
      在这里插入图片描述
      总结:kafka复制机制既不是完全的同步复制,也不是单纯的异步复制。事实上,同步复制要求ISR的所有副本都复制完成,这条消息才算真正成功,才能够被消费;而在异步复制的方式上,follower异步地从leader复制数据。kafka使用这种方式有效权衡了数据可靠性和性能之间的关系。

      :在这种情况下,如果follower副本都还没有复制而落后于leader副本,然后leader副本宕机,则会造成数据丢失。

4、处理请求

  1. broker的大部分工作是处理客户端、分区副本、控制器发送给分区首领的请求。Kafka提供了一个基于TCP的二进制协议,所有请求消息都包含一个标准消息头:

    Request type:请求类型,即:API key;

    Request version:客户端的版本号;

    Correlation ID:一个具有唯一性的数字,标识请求消息,也会出现在响应消息和错误日志里;

    Client ID:标识发送请求的客户端;

  2. 请求流程:

    1. Kafka的broker会在监听的每个端口上运行一个Acceptor线程,该线程创建连接然后交给Processor线程去处理;
    2. Processor线程读取消息解析后放入请求队列,线程池中的KafkaRequestHandler从请求队列中获取连接,根据头部信息获取对应的KafkaApi进行相关处理;
    3. 通过回调,将处理后的结果通过RequestChannel写到Processor对应的响应队列,等待Processor线程将响应队列的消息发送回客户端。
      在这里插入图片描述
  3. 生产者请求和获取请求都必须发送给分区的首领副本,如果broker收到一个针对特定分区的请求,而该分区的首领在另一个broker上,那么会给请求的客户端返回一个“非分区首领”的错误响应。Kafka客户端要负责把生产请求和获取请求发送到正确的broker上。

  4. 客户端如何知道该往哪里发送请求?

    客户端使用元数据请求,获取主题相关信息,信息里指明了主题包含的分区、每个分区有哪些副本,以及哪个是首领副本,元数据请求可以发送给任意一个broker,因为所有的broker都缓存了这些元数据信息。

    一般情况下客户端会缓存这些元数据,并按照metadata.max.age.ms参数配置的时间间隔去刷新这些信息,如果客户端收到“非首领”报错,也会触发这个刷新请求;
    在这里插入图片描述

生产请求
  1. 之前提到过acks参数;

    1. acks=1,只要首领收到消息就给客户端反馈写入成功;

      :这是kafka的默认设置;

      如果分区leader刚接收到消息并反馈客户端,follower还未同步,结果leader所在的broker宕机了,则该条消息会被丢失,因为客户端认为发送成功了。

    2. acks=all 或者 -1,需要所有同步副本收到消息才反馈写入成功;同步期间,请求被保存在一个叫炼狱的缓冲区(purgatory),直到所有同步副本收到消息,响应才被返回给客户端;

      :如果分区只有一个副本,即leader副本,那么acks=all/-1,也不能代表数据不会丢失。

    3. acks=0,客户端不需要等待broker响应,直接认为消息发送成功;

      如果消息在发送路上,leader所在的broker宕机,则消息丢失。

  2. 包含首领副本的broker收到生产请求时,会对请求做一些验证:

    发送数据的用户是否有主题写入权限;

    请求包里的acks值是否有效(只允许出现0、1、-1、all);

    如果acks=all, 是否有足够多的同步副本保证消息已经被安全写入,如果同步副本数量不足,broker可以拒绝处理新的消息;(此处我的理解是:对于先前的消息是否有足够多的同步副本完成复制。)

获取请求
  1. 客户端发送请求,向broker请求主题分区里具有特定偏移量的消息,比如:请求把主题Test分区0偏移量从50开始的消息及主题Test分区3偏移量从63开始的消息发给我

  2. 分区首领所在broker收到请求会检查请求是否有效,比如:

    偏移量是否存在?数据是否已被删除?校验失败的话会返回错误。

  3. 客户端可以设置broker单次返回数据量的上下限:

    1. 上限设定是为了防止数据量过大导致客户端内存不足;
    2. 下限设定可以让主体消息累积到一定量之后再返回;适合数据量小且对数据实时性要求不高的情况;当然,该场景下不会让客户端一直等待broker累积数据,在等待一段时间后(客户端可定义时间),就可以拿到数据。
  4. 大部分客户端只能读取已经被写入所有同步副本的消息,因为没有被完全同步的消息是“不安全”的,如果首领宕机,另一个副本成为新首领,那么这些消息便丢失了。会破环一致性:消费者A读取并处理了消息X,消费者B去读取时,X却不存在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值