热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Kafka中的再均衡

在《Kafka消费者的使用和原理》中已经提到过“再均衡”的概念,我们先回顾下,一个主题可以有多个分区,而订阅该主题的消费组中可以有多个消费者。每一个分区只能被消费组中的一个消费者消

在《Kafka消费者的使用和原理》中已经提到过“再均衡”的概念,我们先回顾下,一个主题可以有多个分区,而订阅该主题的消费组中可以有多个消费者。每一个分区只能被消费组中的一个消费者消费,可认为每个分区的消费权只属于消费组中的一个消费者。但是世界是变化的,例如消费者会宕机,还有新的消费者会加入,而为了应对这些变化,让分区所属权的分配合理,这都需要对分区所属权进行调整,也就是所谓的“再均衡”。本文将对再均衡的相关知识进行详细叙述。
技术图片


触发时机

首先,我们需要了解什么情况下会触发再均衡,在前文已经提到了消费者数量的变化,是需要再均衡的。在使用Kafka时,除了消费者数量可能会变化,分区数量也同样可能变化,我们可以人为的对分区数量进行修改,但是Kafka只允许增加分区,所以我们只能把分区数量调大,不能调小,否则会收到InvalidPartitionException异常。关于为什么不能减少分区,可参考下面的回答:

按Kafka现有的代码逻辑,此功能是完全可以实现的,不过也会使得代码的复杂度急剧增大。实现此功能需要考虑的因素很多,比如删除掉的分区中的消息该作何处理?如果随着分区一起消失则消息的可靠性得不到保障;如果需要保留则又需要考虑如何保留。直接存储到现有分区的尾部,消息的时间戳就不会递增,如此对于Spark、Flink这类需要消息时间戳(事件时间)的组件将会受到影响;如果分散插入到现有的分区中,那么在消息量很大的时候,内部的数据复制会占用很大的资源,而且在复制期间,此主题的可用性又如何得到保障?与此同时,顺序性问题、事务性问题、以及分区和副本的状态机切换问题都是不得不面对的。反观这个功能的收益点却是很低,如果真的需要实现此类的功能,完全可以重新创建一个分区数较小的主题,然后将现有主题中的消息按照既定的逻辑复制过去即可。

简单来说,就是做这个功能需要考虑很多因素,这样会把代码弄的很复杂,而收益却很低,而且存在替代方案来实现该效果,创建一个分区数小的主题,再把当前主题迁移过去。

除了消费者、分区数量的变化,还有一种情况,也需要进行再均衡。当消费者订阅主题时使用的是正则表达式,例如“test.*”,表示订阅所有以test开头的主题,当有新的以test开头的主题被创建时,则需要通过再均衡将该主题的分区分配给消费者。

再均衡的三种触发时机,我们已经清楚了,下面我们看下再均衡是如何实现的。


协调者

再均衡,将分区所属权分配给消费者。因此需要和所有消费者通信,这就需要引进一个协调者的概念,由协调者为消费组服务,为消费者们做好协调工作。在Kafka中,每一台Broker上都有一个协调者组件,负责组成员管理、再均衡和提交位移管理等工作。如果有N台Broker,那就有N个协调者组件,而一个消费组只需一个协调者进行服务,那该由哪个Broker为其服务?确定Broker需要两步:



  1. 计算分区号
    partition = Math.abs(groupID.hashCode() % offsetsTopicPartitionCount)

根据groupID的哈希值,取余offsetsTopicPartitionCount(内部主题consumer_offsets的分区数,默认50)的绝对值,其意思就是把消费组哈希散列到内部主题__consumer_offsets的一个分区上。确定协调者为什么要和内部主题扯上关系。这就跟协调者的作用有关了。协调者不仅是负责组成员管理和再均衡,在协调者中还需要负责处理消费者的偏移量提交,而偏移量提交则正是提交到consumer_offsets的一个分区上。所以这里需要取余offsetsTopicPartitionCount来确定偏移量提交的分区。



  1. 找出分区Leader副本所在的Broker

确定了分区就简单了,分区Leader副本所在的Broker上的协调者,就是我们要找的。

这个算法通常用于帮助定位问题。当一个消费组出现问题时,我们可以先确定协调者的Broker,然后查看Broker端的日志来定位问题。


交互方式

协调者,我们确定了。那协调者和消费者之间是如何交互的?协调者如何掌握消费者的状态,又如何通知再均衡。这里使用了心跳机制。在消费者端有一个专门的心跳线程负责以heartbeat.interval.ms的间隔频率发送心跳给协调者,告诉协调者自己还活着。同时协调者会返回一个响应。而当需要开始再均衡时,协调者则会在响应中加入REBALANCE_IN_PROGRESS,当消费者收到响应时,便能知道再均衡要开始了。

由于再平衡的开始依赖于心跳的响应,所以heartbeat.interval.ms除了决定心跳的频率,也决定了再均衡的通知频率。
现在我们再重新看下,触发再均衡的时机,前面说到有三种情况触发再均衡,分别是消费者数量的增加或减少、分区数的增加和新创建主题,其中消费者数量增加、分区数增加和新创建主题,这都是必须是人为操作,算是计划内的再均衡。而消费者数量减少则除了是人为操作,也可能因为其他原因导致,属于计划之外的再均衡,这是我们需要关心的,毕竟再均衡的开销还是很大的,所有消费者都会停止工作,所以我们应尽量避免不必要的再均衡。下面我们看下影响消费者数量减少的参数有哪些:



  1. session.timeout.ms:Broker端参数,消费者的存活时间,默认10秒,如果在这段时间内,协调者没收到任何心跳,则认为该消费者已崩溃离组;

  2. heartbeat.interval.ms:消费者端参数,发送心跳的频率,默认3秒;

  3. max.poll.interval.ms:消费者端参数,两次调用poll的最大时间间隔,默认5分钟,如果5分钟内无法消费完,则会主动离组。

可以看出session.timeout.ms和heartbeat.interval.ms是相关的,这里给出一个建议参考的公式:

session.timeout.ms ≥ 3 * heartbeat.interval.ms

为尽量避免因为偶发的网络原因,心跳无法到达协调者,在超时之前,应至少能发送3轮心跳。再给出一个经验值的设置:session.timeout.ms=6s,heartbeat.interval.ms=2s。

max.poll.interval.ms的设置,则主要和下游处理时间有关,例如下游处理时间需要6分钟,那按默认值是不合理的,消费者会频繁主动离组。所以需要把值设置的比下游处理时间大一点,避免不必要的再均衡。

这一小节主要讲了协调者如何通知消费者开始再均衡,以及如何设置参数避免不必要的再均衡,下面我们看下再均衡的流程是怎么样的。


流程

  1. 当消费者收到协调者的再均衡开始通知时,需要立即提交偏移量;

  2. 消费者在收到提交偏移量成功的响应后,再发送JoinGroup请求,重新申请加入组,请求中会含有订阅的主题信息;

  3. 当协调者收到第一个JoinGroup请求时,会把发出请求的消费者指定为Leader消费者,同时等待rebalance.timeout.ms,在收集其他消费者的JoinGroup请求中的订阅信息后,将订阅信息放在JoinGroup响应中发送给Leader消费者,并告知他成为了Leader,同时也会发送成功入组的JoinGroup响应给其他消费者;

  4. Leader消费者收到JoinGroup响应后,根据消费者的订阅信息制定分配方案,把方案放在SyncGroup请求中,发送给协调者。普通消费者在收到响应后,则直接发送SyncGroup请求,等待Leader的分配方案;

  5. 协调者收到分配方案后,再通过SyncGroup响应把分配方案发给所有消费组。

  6. 当所有消费者收到分配方案后,就意味着再均衡的结束,可以正常开始消费工作了。
    技术图片

Kafka中的再均衡



推荐阅读
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 自定义滚动条美化页面内容
    当页面内容超出显示范围时,为了提升用户体验和页面美观,通常会添加滚动条。如果默认的浏览器滚动条无法满足设计需求,我们可以自定义一个符合要求的滚动条。本文将详细介绍自定义滚动条的实现过程。 ... [详细]
  • 微软推出Windows Terminal Preview v0.10
    微软近期发布了Windows Terminal Preview v0.10,用户可以在微软商店或GitHub上获取这一更新。该版本在2月份发布的v0.9基础上,新增了鼠标输入和复制Pane等功能。 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 第二十五天接口、多态
    1.java是面向对象的语言。设计模式:接口接口类是从java里衍生出来的,不是python原生支持的主要用于继承里多继承抽象类是python原生支持的主要用于继承里的单继承但是接 ... [详细]
  • [c++基础]STL
    cppfig15_10.cppincludeincludeusingnamespacestd;templatevoidprintVector(constvector&integer ... [详细]
  • ZooKeeper 入门指南
    本文将详细介绍ZooKeeper的工作机制、特点、数据结构以及常见的应用场景,包括统一命名服务、统一配置管理、统一集群管理、服务器动态上下线和软负载均衡。 ... [详细]
  • 自动验证时页面显示问题的解决方法
    在使用自动验证功能时,页面未能正确显示错误信息。通过使用 `dump($info->getError())` 可以帮助诊断和解决问题。 ... [详细]
  • importpymysql#一、直接连接mysql数据库'''coonpymysql.connect(host'192.168.*.*',u ... [详细]
  • Framework7:构建跨平台移动应用的高效框架
    Framework7 是一个开源免费的框架,适用于开发混合移动应用(原生与HTML混合)或iOS&Android风格的Web应用。此外,它还可以作为原型开发工具,帮助开发者快速创建应用原型。 ... [详细]
  • 本文介绍了如何使用 CMD 批处理脚本进行文件操作,包括将指定目录下的 PHP 文件重命名为 HTML 文件,并将这些文件复制到另一个目录。 ... [详细]
  • 两个条件,组合控制#if($query_string~*modviewthread&t(&extra(.*)))?$)#{#set$itid$1;#rewrite^ ... [详细]
  • 本文详细介绍了DMA控制器如何通过映射表处理来自外设的请求,包括映射表的设计和实现方法。 ... [详细]
  • 解决Win10下MySQL连接问题:Navicat 2003无法连接到本地MySQL服务器(10061)
    本文介绍如何在Windows 10环境下解决Navicat 2003无法连接到本地MySQL服务器的问题,包括启动MySQL服务和检查配置文件的方法。 ... [详细]
  • 本文详细介绍了如何利用Duilib界面库开发窗体动画效果,包括基本思路和技术细节。这些方法不仅适用于Duilib,还可以扩展到其他类似的界面开发工具。 ... [详细]
author-avatar
穿越时空lily
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有