消费者拉取数据是在拉取器中完成的,发送心跳是在消费者的协调者上完成的,但并不是说拉取器和消费者的协调者就没有关联关系 。
 “消费者的协调者”的作用是确保客户端的消费者和服务端的协调者之间的正常通信,如果消费者没有连接上协调者(比如协调者认为消费者挂了,或者消费者认
或者消费者认为协调者挂了),那么拉取器的拉取工作以及后续的消息消费等工作就都无法正常进行。

  每个消费者都需要定时地向协调者发送心跳,以表明向己是存活的 。 如果消费者一段时间内没有发送心跳,协调者就会认为消费者挂掉了 。
 协调者还要能够对消费组成员失败进行处理,比如将失败消费者拥有的分区分配给其他消费者消费。 心跳通常会作为分布式系统的健康检查状况手段,通过让
每个节点都定时上报心跳信息、给某个中心节点,如果一段时间没有收到某个节点的心跳,中心节点就认为那个节点挂掉了 。

心跳状态

  每个消费者客户端都只有一个心跳任务,心跳对象( Heartbeat )除了记录心跳任务的元数据——会话超时时间( timeout )、定时任务时间间隔( interval ),
还会记录当前心跳任务的状态一一最近的会话重置时间 、最近的心跳发送时间 、最近的心跳接收时间 。

  心跳任务发送心跳请求的主要逻辑是:在发送心跳请求前,记录心跳状态的最近心跳发送时间( lastHeartbeatSend );在收到心跳响应结果后,
记录心跳状态的最近心跳接收时间( lastHeartbeatReceive );然后计算下一次心跳任务的发生时间,新创建一个延迟的心跳任务 。

处理心跳结果的示例

  客户端启动时会创建调度时间为0秒的延迟任务加入队列 。 客户端轮询的时间为2秒,会弹出延迟任务(因为延迟任务的调度时间小于当前时间),
现在队列为空了 。 但是因为没有上一次心跳,只有上一次的会话重置时间,经过下面3个步骤的计算后,会重新创建一个调度时间为5秒
的延迟任务加入队列 。
(1) 距离上次心跳的时间间隔=当前轮询的时间-上次会话的重置时间= 2秒 - 0秒= 2秒 。
(2) 距离下次心跳的时间间隔=心跳间隔 -距离上次心跳的时间间隔= 5秒 - 2秒= 3秒 。
(3)下次心跳任务的时间=当前轮询的时间+距离下次心跳的时间间隔= 2秒 + 3秒= 5秒。

上面的步骤执行尾,队列中延迟任务的调度时间为5秒。 在这之后,如果轮询时间小子5秒,则不 会弹出队列的延迟任务,因为轮询的当前时间

小于延迟任务的调度时间 。 如下图所示,只有当轮询时间为5秒时,才会弹州调度时间为5秒的延迟任务,现在队列又为空 了 。 此时经过下面两个步骤计算
出来的“距离下次心跳时间间隔”为0秒,就会执行发送心跳请求的逻辑。
(1)距离上次心跳的时间间隔 = 当前轮询的时间-上次会话的重置时间= 5秒-0秒= 5秒 。
(2)距离下次心跳的时间间隔 = 心跳间隔 -距离上次心跳的时间间隔 = 5秒- 5秒= 0秒 。

在发送心跳请求之前,先记录上一次的心跳时间为当前时间即 5秒。 假设心跳在8秒时才完成(虚线部分), 经过下面3个步骤后,
 会重新创建调度时间为 10秒的延迟任务放入队列中 。
(1) 距离上次心跳的时间间隔 = 心跳完成的时间 -上次心跳的时间= 8秒 - 5秒= 3秒 。
(2) 距离下次心跳的时间间隔 = 心跳间隔-距离上次心跳的时间间隔= 5秒 - 3秒= 2秒 。
(3)下次心跳任务的时间 = 心跳完成的时间+距离下次心跳的时间间隔= 8秒 + 2秒= 10秒

  延迟任务并不是一个线程,它必须通过客户端的轮询来触发执行。 客户端刚启动时必须先创建一个延迟任务放入队列,这样客户端在轮询时,
才有可能获取出延迟的任务去执行。 如果客户端启动时没有创建延迟任务,那么队列中就永远不会有延迟任务 。 另外,轮询时如果弹出了需要执行的延迟
任务,不管有没有执行发送心跳请求的流程,都要重新创建新的延迟任务放入队列 。  那么第一次创建延迟任务是在客户端启动后的什么时候
发生呢?

心跳和协调者的关系

  客户端调用心跳任务的 reset ()方法会创建第一个延迟任务,这个方法的调用链如下 。

- 确保协调者是已知的,即消费者客户端必须连接上管理消费组的协调者 。
- 确保消费组是活动的, 即消费者必须分配到分区 。

  消费者和协调者进行交互操作,必须确保消费者已经知道并且连接上协调者所在的节点,如果都没有连接上协调者,心跳等其他操作都不会正常进行。
连接上协调者后,就可以立即向协调者发送一次心跳。 另外,如果消费者需要重新加入消费组,在分配到分区后,也要重置心跳任务 。

  消费者发送心跳,正常来说应当只是通知一下服务端协调者而已 。 不过在分布式系统中,通信的双方可能都会存在一些问题,
比如协调者可能会突然挂掉。 这时服务端应该为每个消费组重新选择一个协调者,但如果此后消费者连接的还是原来的协调者就有问题了
(它应该连接最新的协调者节点),这种情况应该让消费者重新获取协调者。 服务端如果能够在客户端定时发送的心跳任务中附带这种信
息,客户端就能够及时知道应该再去找最新的协调者 。 消费者针对不同错误码的处理方式如下 。

- 协调者挂掉了,客户端设置“消费组的协调者”对象为空 ,消费者需要重新发送“获取消费组的协调者”请求获取新的协调者。
- 协调者没有挂掉,客户端设置“需要重新加入组”变量为 true ,消费者需要向协调者重新发送“加入组请求”加入消费组。

  心跳的响应处理中并不执行具体的错误处理操作,比如让客户端连接新的协调者或者让消费者重新加入消费组,心跳只是更新这些后续错误处理操作
相关的条件变量 。 当客户端轮询时会监听到条件 变量发生了变化,从而让轮询操作主动地执行对应的操作 。 这里可以把心跳看作任务通知,必须依赖

客户端的轮询来确保能及时捕获到错误情况进行错误处理,不在心跳中处理任务是因为任务的操作时间可能比心跳间隔长得多 。 所以,客户端的轮询非常重要,
它不仅仅驱动了数据的不断拉取,还可以根据心跳结果执行不同的任务 。

  消费者的协调者因为需要定时存储分区的消费进度,还有一个自动提交偏移量的定时任务。

Kafka技术内幕 读书笔记之(四) 新消费者——心跳任务的更多相关文章

  1. Kafka技术内幕 读书笔记之(四) 新消费者——消费者提交偏移量

    消费组发生再平衡时分区会被分配给新的消费者,为了保证新消费者能够从分区的上一次消费位置继续拉取并处理消息,每个消费者需要将分区的消费进度,定时地同步给消费组对应的协调者节点 .新AP I为客户端提供了 ...

  2. Kafka技术内幕 读书笔记之(四) 新消费者——新消费者客户端(二)

    消费者拉取消息 消费者创建拉取请求的准备工作,和生产者创建生产请求的准备工作类似,它们都必须和分区的主副本交互.一个生产者写入的分区和消费者分配的分区都可能有多个,同时多个分区的主副本有可能在同一个节 ...

  3. Kafka技术内幕 读书笔记之(一) Kafka入门

    在0.10版本之前, Kafka仅仅作为一个消息系统,主要用来解决应用解耦. 异步消息 . 流量削峰等问题. 在0.10版本之后, Kafka提供了连接器与流处理的能力,它也从分布式的消息系统逐渐成为 ...

  4. Kafka技术内幕 读书笔记之(五) 协调者——消费组状态机

    协调者保存的消费组元数据中记录了消费组的状态机 , 消费组状态机的转换主要发生在“加入组请求”和“同步组请求”的处理过程中 .协调者处理“离开消费组请求”“迁移消费组请求”“心跳请求” “提交偏移量请 ...

  5. Kafka技术内幕 读书笔记之(五) 协调者——延迟的加入组操作

      协调者处理不同消费者的“加入组请求”,由于不能立即返回“加入组响应”给每个消费者,它会创建一个“延迟操作”,表示协调者会延迟发送“加入组响应”给消费者 . 但协调者不会为每个消费者的 “加入组请求 ...

  6. Kafka技术内幕 读书笔记之(三) 消费者:高级API和低级API——消费者消费消息和提交分区偏移量

    消费者拉取钱程拉取每个分区的数据,会将分区的消息集包装成一个数据块( FetchedDataChunk )放入分区信息的队列中 . 而每个队列都对应一个消息流( KafkaStream ),消费者客户 ...

  7. Kafka技术内幕 读书笔记之(三) 生产者——消费者:高级API和低级API——基础知识

    1. 使用消费组实现消息队列的两种模式 分布式的消息系统Kafka支持多个生产者和多个消费者,生产者可以将消息发布到集群中不同节点的不同分区上:消费者也可以消费集群中多个节点的多个分区上的消息 . 写 ...

  8. Kafka技术内幕 读书笔记之(二) 生产者——新生产者客户端

    消息系统通常由生产者(producer ). 消费者( consumer )和消息代理( broker ) 三大部分组成,生产者会将消息写入消息代理,消费者会从消息代理中读取消息 . 对于消息代理而言 ...

  9. Kafka技术内幕 读书笔记之(六) 存储层——日志的读写

    -Kafka是一个分布式的( distributed ).分区的( partitioned ).复制的( replicated )提交日志( commitlog )服务 . “分布式”是所有分布式系统 ...

随机推荐

  1. Python中的numpy模块解析

    numpy 1.  创建对象 维度(dimensions):轴 轴的个数:秩(rank) Numpy最重要的一个特点就是其N维数组对象(即ndarray) 创建数组最简单的函数就是用array函数: ...

  2. 二分图最小点覆盖König定理的简单证明 (加入自己理解)

    第一次更改:http://blog.sina.com.cn/s/blog_51cea4040100h152.html 讲的更细致 增广路:https://blog.csdn.net/qq_374572 ...

  3. Django+Xadmin打造在线教育系统(五)

    课程相关功能实现 课程列表 创建课程相关的urls.py path("course/", include('course.urls', namespace="course ...

  4. PKUWC2019 凉凉记

    请配合 BGM 食用. 菜就是菜,说什么都是借口. Day 0 前一天先到纪中报道,高铁上打了一会单机膈膜,然后又打了一遍 \(FFT\) 板子,就到了中山. 到了后,发现气温骤然升高,马上 脱 换裤 ...

  5. 聊聊GarbageCollectionNotificationInfo

    序本文主要研究一下GarbageCollectionNotificationInfo CompositeDatajava.management/javax/management/openmbean/C ...

  6. ftp利用脚本添加本地用户

    指定用户名,家目录,密码,顺序不可颠倒.eg: sh 脚本名 用户名 家目录 密码 #!/bin/bash # set -e ] //判断给定参数是否为三个 homepath=$ password=$ ...

  7. su命令详解

    -----------------------------------------------------------------su 权限设置[root@localhost ~]# vim /etc ...

  8. 使用zabbix监控mariadb性能状态

    0x01 前言 zabbix内置Mysql的监控模版,因为mariadb和Mysql两者的相关性,所以这个模版也能用在mariadb services上. 0x02 Mysql 首先要在mariadb ...

  9. springAop @AfterReturning注解 获取返回值

    @AfterReturning(returning="rvt", pointcut="@annotation(com.sinosoft.redis.cache.PutCa ...

  10. VS code golang 开发环境搭建

    安装go (1)下载go安装程序 下载地址:https://golang.org/dl/(墙内下载地址http://www.golangtc.com/download),如果是您的系统是windows ...