Kafka-消费者-Consumer Group Rebalance设计

在同一个Consumer Group中,同一个Topic的不同分区会分配给不同的消费者进行消费,那么为消费者分配分区的操作是在Kafka服务端完成的吗?分区是如何进行分配呢?下面来分析Rebalance操作的原理。

方案一

Kafka最开始的解决方案是通过ZooKeeper的Watcher实现的。

每个Consumer Group在ZooKeeper下都维护了一个“/consumers/[group_id]/ids”路径,在此路径下使用临时节点记录属于此Consumer Group的消费者的Id,由Consumer启动时创建。

还有两个与ids节点同级的节点,它们分别是:
owners节点,记录了分区与消费者的对应关系;
offsets节点,记录了此Consumer Group在某个分区上的消费位置。

每个Broker、Topic以及分区在ZooKeeper中也都对应一个路径,如下所示。

  • /brokers/ids/broker_id:记录了host、port以及分配在此Broker上的Topic的分区列表。
  • /brokers/topics/[topic_name]:记录了每个Partition的Leader、ISR等信息。
  • /brokers/topics/[topic_name]/partitions/[partition_num]/state:记录了当前Leader、选举epoch等信息
    路径图如图所示。

在这里插入图片描述
每个Consumer都分别在“/consumers/[group_id]/ids”和“brokers/ids”路径上注册一个Watcher。

当“/consumers/[group_id]/ids”路径的子节点发生变化时,表示ConsumerGroup中的消费者出现了变化;

当“/brokers/ids”路径的子节点发生变化时,表示Broker出现了增减。
这样,通过Watcher,每个消费者就可以监控Consumer Group和Kafka集群的状态了。

这个方案看上去不错,但是严重依赖于ZooKeeper集群,有两个比较严重的问题:

  • 羊群效应(Herd Effect):先解释一下什么是“羊群效应”,一个被Watch的ZooKeeper节点变化,导致大量的Watcher通知需要被发送给客户端,这将导致在通知期间其他操作延迟。

    一般出现这种情况的主要原因就是没有找到客户端真正的关注点,也算是滥用Watcher的一种场景。
    继续前面的分析,任何Broker或Consumer加入或退出,都会向其余所有的Consumer发送Watcher通知触发Rebalance,就出现了“羊群效应”。

  • 脑裂(Split Brain):每个Consumer都是通过ZooKeeper中保存的这些元数据判断Consumer Group状态、Broker的状态以及Rebalance结果的,由于ZooKeeper只保证“最终一致性”,不保证“Simultaneously Consistent Cross-Client Views”,不同Consumer在同一时刻可能连接到ZooKeeper集群中不同的服务器,看到的元数据就可能不一样,这就会造成不正确的Rebalance尝试。

方案二

由于上述两个原因,Kafka的后续版本对Rebalance操作进行了改进,也对消费者进行了重新设计。

其核心设计思想是:将全部的Consumer Group分成多个子集,每个Consumer Group子集在服务端对应一个GroupCoordinator对其进行管理,GroupCoordinator是KafkaServer中用于管理Consumer Group的组件,消费者不再依赖ZooKeeper,而只有GroupCoordinator在ZooKeeper上添加Watcher。

消费者在加入或退出Consumer Group时会修改ZooKeeper中保存的元数据,这点与上文描述的方案一类似,此时会触发GroupCoordinator设置的Watcher,通知GroupCoordinator开始Rebalance操作。

下面简述这个过程:

  1. 当前消费者准备加入某Consumer Group或是GroupCoordinator发生故障转移时,消费者并不知道GroupCoordinator的网络位置,消费者会向Kafka集群中的任一Broker发送ConsumerMetadataRequest,此请求中包含了其Consumer Group的Groupld,收到请求的Broker会返回ConsumerMetadataResponse作为响应,其中包含了管理此ConsumerGroup的GroupCoordinator的相关信息。

  2. 消费者根据ConsumerMetadataResponse中的GroupCoordinator信息,连接到GroupCoordinator并周期性地发送HeartbeatRequest,HeartbeatRequest的具体格式在后面会详细介绍。

    发送HeartbeatRequest的主要作用是为了告诉GroupCoordinator此消费者正常在线,GroupCoordinator会认为长时间未发送HeartbeatRequest的消费者已经下线,触发新一轮的Rebalance操作。

  3. 如果HeartbeatResponse中带有IllegalGeneration异常,说明GroupCoordinator发起了Rebalance操作,此时消费者发送JoinGroupRequest(具体格式在后面介绍)给GroupCoordinator,JoinGroupRequest的主要目的是为了通知GroupCoordinator,当前消费者要加入指定的Consumer Group。

    之后,GroupCoordinator会根据收到的JoinGroupRequest和ZooKeeper中的元数据完成对此Consumer Group的分区分配。

  4. GroupCoordinator会在分配完成后,将分配结果写入ZooKeeper保存,并通过JoinGroupResponse返回给消费者。消费者就可以根据JoinGroupResponse中分配的分区开始消费数据。

  5. 消费者成功成为Consumer Group的成员后,会周期性发送HeartbeatRequest。如果HeartbeatResponse包含IlegalGeneration异常,则执行步骤3。如果找不到对应的GroupCoordinator(HeartbeatResponse包含NotCoordinatorForGroup异常),则周期性地执行步骤1,直至成功。

这里只是简略地描述此方案的步骤,整个方案还是有点复杂的,其中比较严谨地描述了消费者和GroupCoordinator的状态图和各个阶段可能发生的故障以及故障转移处理,本文重点关注Consumer Group Rebalance方面。

上面这种方案虽然解决了“羊群效应”、“脑裂”问题,但是还是有两个问题:

  • 分区分配的操作是在服务端的GroupCoordinator中完成的,这就要求服务端实现Partition的分配策略。当要使用新的Partition分配策略时,就必须修改服务端的代码或配置,之后重启服务,这就显得比较麻烦。

  • 不同的Rebalance策略有不同的验证需求。当需要自定义分区分配策略和验证需求时,就会很麻烦。

方案三

为了解决上述问题,Kafka进行了重新设计,将分区分配的工作放到了消费者这一端进行处理,而Consumer Group管理的工作则依然由GroupCoordinator处理。

这就让不同的模块关注不同的业务,实现了业务的切分和解耦,这种思想在设计时很重要。

重新设计后的协议在上一版本的协议上进行了修改,将JoinGroupRequest的处理过程拆分成了两个阶段,分别是Join Group阶段和Synchronizing Group State阶段。

当消费者查找到管理当前Consumer Group的GroupCoordinator后,就会进入Join Group阶段,Consumer首先向GroupCoordinator发送JoinGroupRequest请求,其中包含消费者的相关信息;

服务端的GroupCoordinator收到JoinGroupRequest后会暂存消息,收集到全部消费者之后,根据JoinGroupRequest中的信息来确定Consumer Group中可用的消费者,从中选取一个消费者成为Group Leader,还会选取使用的分区分配策略,最后将这些信息封装成JoinGroupResponse返回给消费者。

虽然每个消费者都会收到JoinGroupResponse,但是只有Group Leader收到的JoinGroupResponse中封装了所有消费者的信息。

当消费者确定自己是Group Leader后,会根据消费者的信息以及选定的分区分配策略进行分区分配。

在Synchronizing Group State阶段,每个消费者会发送SyncGroupRequest到GroupCoordinator,但是只有Group Leader的SyncGroupRequest请求包含了分区的分配结果,GroupCoordinator根据Group Leader的分区分配结果,形成SyncGroupResponse返回给所有Consumer。

消费者收到SyncGroupResponse后进行解析,即可获取分配给自身的分区。

最后,我们来了解消费者的状态转移与各请求之间的关系,如图所示。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/631167.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

583.两个字符串的删除操作 72.编辑距离

583.两个字符串的删除操作 72.编辑距离 583.两个字符串的删除操作 力扣题目链接(opens new window) 给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。 示例: 输入: “…

dubbo项目发布时Destroyed异常分析

1、问题现象 在发布项目时,elk有打印use dubbo version 2.6.2 is DESTROYED, can not be invoked any more!相关的报错日志,来提示dubbo消费者调用生产者时,生产者服务已经DESTROYED。 ChatGpt可知: 2、问题溯源 com.alibaba.dub…

序列到序列模型

一.序列到序列模型的简介 序列到序列(Sequence-to-Sequence,Seq2Seq)模型是一类用于处理序列数据的深度学习模型。该模型最初被设计用于机器翻译,但后来在各种自然语言处理和其他领域的任务中得到了广泛应用。 Seq2Seq模型的核…

怎样通过powershell 打开win10的自动更新?

要通过PowerShell命令打开Windows 10的自动更新,可以按照以下步骤操作: 打开PowerShell:在Windows 10中,点击“开始”按钮,输入“PowerShell”,然后选择“Windows PowerShell”。 以管理员身份运行PowerSh…

【软件测试学习笔记6】Linux常用命令

格式 command [-options] [parameter] command 表示的是命令的名称 []表示是可选的,可有可无 [-options]:表示的是命令的选项,可有一个或多个,也可以没有 [parameter]:表示命令的参数,可以有一个或多…

VLAN区域间路由详解

LAN局域网 WAN 广域网 WLAN无线局域网 VLAN:虚拟局域网 交换机和路由器,协同工作后,将原来的一个广播域,切分为多个,节省硬件成本; 配置思路: 交换机上创建vlan交换机上的各个接口划分到对应的vlan中 T…

微信小程序页面传值的几种方式

1.URL参数传值:通过在跳转链接中附加参数,在目标页面的onLoad函数中获取参数。 2.全局变量:通过在app.js文件中定义全局变量,在源页面设置变量的值,目标页面通过getApp().globalData获取变量的值。 3.缓存存储&#xf…

flink源码分析 - yaml解析

flink版本: flink-1.12.1 代码位置: org.apache.flink.configuration.GlobalConfiguration 主要看下解析yaml文件的方法: org.apache.flink.configuration.GlobalConfiguration#loadYAMLResource /** Licensed to the Apache Software Foundation (ASF) under one* or…

尚无忧【无人共享空间 saas 系统源码】无人共享棋牌室系统源码共享自习室系统源码,共享茶室系统源码

可saas多开,非常方便,大大降低了上线成本 UNIAPPthinkphpmysql 独立开源! 1、定位功能:可定位附近是否有店 2、能通过关键字搜索现有的店铺 3、个性轮播图展示,系统公告消息提醒 4、个性化功能展示,智能…

LED车灯电源解决方案SCT8162x、SCT2464Q、SCT71403Q、SCT71405Q、SCT53600等

随着LED封装技术的成熟和成本的下降,LED车灯渗透率迅速提升。车灯控制技术不断向节能化、智能化和个性化方向发展。ADB大灯配置门槛下探,像素数据急剧增加,LED 数量不断增加,陆续有智能车灯达到百万级像素,且动画效果需…

【算法小记】深度学习——循环神经网络相关原理与RNN、LSTM算法的使用

文中程序以Tensorflow-2.6.0为例 部分概念包含笔者个人理解,如有遗漏或错误,欢迎评论或私信指正。 卷积神经网络在图像领域取得了良好的效果,卷积核凭借优秀的特征提取能力通过深层的卷积操作可是实现对矩形张量的复杂计算处理。但是生活中除…

前端——框架——Vue

提示: 本文只是从宏观角度简要地梳理一遍vue3,不至于说学得乱七八糟、一头雾水、不知南北,如果要上手写代码、撸细节,可以根据文中的关键词去查找资料 简问简答: vue.js是指vue3还是vue2? Vue.js通常指的是…

DNS - 全家桶(114 DNS、阿里DNS、百度DNS 、360 DNS、Google DNS)

DNS是什么? DNS是域名系统,Domain Name System的缩写,是一个服务。 DNS就是把域名解析为IP地址,提供我们上网,我们能够上网最终是找到IP地址。 比如,http://xxxx.com是域名,那么他的IP地址假设是144.144.144.144&am…

网络安全中的人工智能:保护未来数字世界的利剑

随着现代社会的数字化进程不断推进,网络安全问题变得日益严峻。为了更好地应对日益复杂的网络威胁,人工智能(AI)技术正被广泛应用于网络安全领域。 在互联网的时代背景下,网络安全已成为国家和企业面临的一项重大挑战。…

Rust 错误处理(下)

目录 1、用 Result 处理可恢复的错误 1.1 传播错误的简写:? 运算符 1.2 哪里可以使用 ? 运算符 2、要不要 panic! 2.1 示例、代码原型和测试都非常适合 panic 2.2 当我们比编译器知道更多的情况 2.3 错误处理指导原则 2.4 创建自定义类型进行有效性验证 …

K8s面试题——情景篇

文章目录 一、考虑一家拥有分布式系统的跨国公司,拥有大量数据中心,虚拟机和许多从事各种任务的员工。您认为这样公司如何以与 Kubernetes 一致的方式管理所有任务?二、考虑一种情况,即公司希望通过维持最低成本来提高其效率和技术运营速度。…

uni-app 经验分享,从入门到离职(年度实战总结:经验篇)——上传图片以及小程序隐私保护指引设置

文章目录 🔥年度征文📋前言⏬关于专栏 🎯关于上传图片需求🎯前置知识点和示例代码🧩uni.chooseImage()🧩uni.chooseMedia()📌uni.chooseImage() 与 uni.chooseMedia() 🧩uni.chooseF…

语义分割结果后处理与可视化:轮廓、中心点和重心标记

目标 介绍一个用于语义分割后处理和可视化的Python脚本。该脚本通过OpenCV库实现,可以在图像中标记出分割区域的轮廓、中心点和重心,以提供更直观的视觉反馈 import cv2 import numpy as npfilename ./mask/3.png # 读取灰度图像 gray_image cv2.imre…

【playwright】新一代自动化测试神器playwright+python系列课程14_playwright网页相关操作_获取网页标题和URL

Playwright 网页操作_获取网页标题和URL 在做web自动化测试时,脚本执行完成后需要进行断言,判断脚本执行是否存在问题。在断言时通常选择一些页面上的信息或者页面上元素的状态来断言,使用网页标题或url来断言就是常见的断言方式&#xff0c…

ssh:connect to host github.com port 22: Connection timed out

解决流程 1.将github的端口由22改为443 ssh -T -p 443 gitssh.github.com 2.接着输入yes进行确认 The authenticity of host [ssh.github.com]:443 ([192.168.1.100]:443) cant be established. TG45532 key fingerprint is SHA256:dfjeDFlkkfdfkDFKEidkfkDFkkKKdjFESDCFLE. …