zoukankan      html  css  js  c++  java
  • Kafka技术内幕 读书笔记之(四) 新消费者——消费者提交偏移量

      消费组发生再平衡时分区会被分配给新的消费者,为了保证新消费者能够从分区的上次消费位置继续拉取并处理消息,每个消费者需要将分
    区的消费进度,定时地同步给消费组对应的协调者节点 。新AP I为客户端提供了两种提交偏移盐的方式:异步模式和同步模式 
      另外,如果消费者客户端设置了向动提交( enable . auto . commit=true ,默认开启)的选项,会在客户端的轮询操作中调度定时任务,
    定时任务也属于异步模式提交偏移量的种运用场景

    自动提交任务

      如果消费者开启自动提交 消费者会通过“消费者的协调者”对象的向动提交任务( AutoCommitTask )定时将分区的拉取偏移量( position 
    保存到服务端,然后更新分区状态的“提交偏移量:( commited 。 自动提交任务定义的  run ()方法只会执行次,在每次任务完成后,
    也要像发送心跳请求样创建下次的延迟任务 

      另外,创建第个延迟任务也非常关键,在心跳任务中也提到了:如果没有创建第个延迟任务,就永远不会有定时任务产生 。 
    只有创建了第延迟任务并放入队列,当延迟任务超时后,会从队列弹出这个超时任务并执行;任务执行完毕后会创建
    个新的延迟任务放入队列 通过这种方式,队列中只会存在个延迟任务,并且确保直有个延迟任务 心跳任务是在
    消费者连接上协调者或者消费者加入消费组后,调用心跳任务的重置方法创建第一个延迟任务。 自动提交任务也是在
    消费者加入消费组后,调用自动提交任务的enable ()方法创建第个延迟的自动提交任务  

    如下图 所示,假设定时提交任务的时间间隔为5秒,消费者轮询的时间为 1但并不是说消费者发送心跳的时间点是 : 0秒、5秒、10
     次定时任务的调度时间点,要根据上次定时任务完成时的时间来决定 。 比如第次定时任务第8秒完成,下次定时任务的时间点就第 13秒,
     体步骤如下 
    (1) 开启定时任务,第个延迟任务的时间=当前时间+时间间隔 0秒+ 5秒 5秒
    (2) 前面几次轮询都不会弹出延迟任务,第五次轮询弹出延迟任务,执行异步的提交偏移业任务
    (3) 异步提交任务在第 8秒完成,新延迟任务的时间=当前时间 时间间隔 8秒 5秒 13秒

      自动提交任务运行时,调用 commitOffsetsAsync ()方法,采用异步模式提交偏移消费者发送OFFSET_COMMIT请求给协调者,
    “提交偏移量请求”定义的响应处理回调器( OffsetCommitResponseHandler)实现了 CoordlnatorResponseHandler抽象父类 
     提交偏移量的逻辑定义了多个回调方法,在回调方法的不同阶段都会处理不同的业务逻辑

    (1)消费者收到“提交偏移量请求”的响应结果,更新分区状态的“提交偏移量"变量
    (2)组合模式异步请求对象的监听器回调方法中,调用 OffsetCommitCallback的回调方法
    (3)偏移量提交的最后一个回调方法,会创建新的延迟任务

      异步发送请求,没有使用阻塞式的client.poll(future )轮询, 是使的client . quickPoll () 。由于向动提交任务不需要关心结果,
    不会通过future.value ()异步请求结果 但发送完请求后不关心结果,并不代表着不处理结果,客户端请求一定有对应客户端应结果 

      客户端提交偏移量后,如果没有响应结果返,或者客户端不应结果么仅仅分区状态中拉取移量position )代表的提交移量
    consumedOffset 到服务端 ,而没有更新分区状态的提交移量( committed),就会导致服务端的 “ 提交移量”和消费者本地订阅状态的
    “提交偏移量”数据不一致

    将拉取偏移量作为提交偏移量
      旧API 当客户端迭代消费消息时会更新分区信息的已消费移量 并且有一后台线程定时将分区信息的已消费偏移量作为已提交偏移量发送给
    协调者节点 API中,订状态分区状态有拉取偏移量( position 提交移量( committed 个变量。 客户端的轮询方法会在返回拉取的记录集之前,
    更新分区状态的拉取偏移量,为下次轮询操作中的拉取做准备 。 但客户端在迭代消费者记录集时,并没有更新分区状态的提交偏移量 。 所以拉取偏移量
    变量也要能够代表分区的消费进度 ,即API会使用拉取偏移量的值作为分区的提交偏移量发送给协调者节点 
     
      新API在迭代消息时没有更新订阅状态的任何变量,可以认为并不存在且消费偏移量这个变量 。分区状态还要保存提交偏移量这个变量的原因是 
    在轮询时 ,如果分区没有拉取偏移量,需要从协调者获取其他消费者提交的分区偏移量 , 然后保存到分区状态对象的提交偏移量 , 再将提交偏移量赋值
    给拉取偏移量,这样分区状态的拉取偏移量就有数据了,客户端才可以发送拉取请求拉取消息

      因为延迟任务的调度是在客户端的轮询中触发,而客户端的轮询又是在Kafka消费者的轮询方法中调用的,所以如果Kafka消费者没有轮询,
    就不会执行延迟的任务 使任务超时了,它也没有机会从延迟队列中移除 去并执行。Kafka的轮询除了客户端的轮询
    (在客户端轮询之前,还有发送拉取请求),还有一个步骤是拉取器获取记录集,客户端应用程序调用一次Kafka的轮询 
    会返回一批消费者记录集 拉取器在返回获取的记录集给客户端应用程序处理之前,会更新本次拉取记录集后的订阅状态,
    即分区的拉取偏移量。综合上面两点的背景知识,再结合拉取器拉取消息、 Kafka轮询的流程,具体步骤如下
    (1)拉取器发送拉取请求;客户端轮询,会把拉取请求发送出去
    (2) 客户端轮询还有可能弹出超时的延迟任务,比如定时提交任务的调度时间到 了,应该立即执
    (3)拉取器的拉取请求完成后,通过回调处理器暂存拉取结果
    (4) 拉取器调用获取记录集方法,更新订阅状态中分区的拉取偏移量,并返回结果给客户端应用程序
    (5 ) 最后客户端应用程序开始处理Kafka轮询返回的消费者记录集

    从上面的步骤中可以得出的结论是 延迟的提交任务超时后会被即执行,它比获取记录集时更新分区状态的拉取偏移量要早 。 Kafka轮询到结果集后,
    前面这两个步骤都执行完后,客户端应用程序才会真正处理拉取的消费者记录集 

      现在来回答“定时提交任务为什么可以采用拉取偏移量作为提交偏移量”了 定时提交任务在超时后会立即执行,并且发生在本次轮询中拉取器
    更新最新一批记录集的拉取偏移量之前而且这一次Kafka轮询中的定时提交任务定发生在上一次的Kafka轮询都全部执行完成之后,而上一次Kafka轮询
    定成功更新了拉取偏移量,并且也成功处理了上一次拉取的那批记录集所以本次轮询中定时提交任务需要获取的提交偏移,实际上等价于上一次轮询
    更新后的拉取偏移

      消费者拉取消息、心跳请求以及本节的定时提交任务都和轮询有关可见,轮询是消费者的入口,通过轮询,只要事件发生,就有对应的处理逻辑来接手,
    后端的操作对于消费者都是透明的

    同步提交偏移量
       自动提交任务使用异步模式提交偏移量,调用client. qutckPoll ()后,可以立即回到主线程,所以异步模式是无阻塞的 。 而同步模式提交偏移量,
    调用者必须等到提交偏移量完成后才回到主线程,所以同步模式是阻塞的 。 
    自动提交任务使用异步方式提交偏移量 , 因为任务是周期性运行的,没有什么依赖条件 , 不需要采用塞方式 ;而同步提交通常是因为存在某些依赖条件,
    必须待提交完成后才能往下进行。

    异步提交偏移量是通过自动动提交任务触发的,那么同步提交偏移量是候被调
      消费者在准备入或重新入消费组之果开启了自动提交任务,要先暂停定时任务,执步模式提交偏移量方法
     消费者调用 commitOffsetsSync ()方法后 ,必待消费者偏移量提交到服务端并且应结果,然后才允许进行下一步的操作 
     
      消费者自动提交任务虽然是异步的, 是定果消费者想要更精确提交偏移量的时机, 用 KafkaConsumer暴露
    同步提交方法( commitSync() )或异步提交方法( commitAsync() 。 如,处理每条记录就提交次偏移量,或者只有轮询一次才提交次 

    消费者的消息处理语义
      消费者从消息理节点拉取到分区的消息后,对条消息的处理语义有下面3种情况
    - 至多一次。消息最多被处理可能会丢失,但绝不会重复传输
    - 至少一次。消息至少被处理次,不可丢失,但可能会重复传输
    - 正好一次。消息正好被处理次,不可丢失,也不可能重复传输

    1 . 至多一次
      消费者读取消息, 先保存消费进度,然后才处理消息这样有可能会出现:消费者保存完消费进度,但在处理消息之前挂了 。 新的消费者会从保存的
    位置开始,但实际上在这个位置之前的消息可能并没有被真正处理。 这种场景对应了“至多次”的语义, 即消息、有可能丢失(没有被处理)。 
    Kafka消费者实现“至多次”的做法是 设置消费者自动提交偏移量,并且设置较短的提交时间间隔

    2. 至少一次
      消费者读取消息, 先处理消息,最后才保存消费进度这样有可能会出现 消费者处理完消息,但是在保存消费进度之前挂了 。 新的消费者从保存
    的位置开始,有可能会重新处理上个消费者已经处理过的消息 。 场景对应了“至少次”的语义, 消息有可能会被重复处理。 
    Kafka消费者实现至少次的做法是 设置消费者自动提交偏移量,但设置很长的提交间隔(或者关闭向动提交偏移量)。 在处理完消息后,
    手动调用同步模式的提交偏移量方法

    3 . 正好一次
      实现正好一次的消息处理语义有两种典型的解决方案 在保存消费进度和保存消费结果之间,引 人两阶段提交协议;或者让消费
    者将消费进度和处理结果保存在同一个存储介质中 比如,将读取的数据和偏移盘起存储到HDFS , 确保数据和偏移量要么起被更新,要么都不会更新。
    Kafka消费者实现正好次的做法是 : 设置消费者不自动提交偏移量,订阅主题时设置自定义的消费者再平衡监听器( ConsumerRebalancelistener 

  • 相关阅读:
    Linux系统下的安装jdk和tomcat教程
    CentOS环境下安装jdk和tomcat
    Java的一个高性能快速深拷贝方法。Cloneable?
    AOP面向切面
    struts中实现ajax的配置信息
    上传下载固定配置
    mysql常用命令
    阿里云部署前后台项目
    PMP相关文件梳理
    面试思路总结
  • 原文地址:https://www.cnblogs.com/jixp/p/9851417.html
Copyright © 2011-2022 走看看