Kafka 2.3发布后官网的Consumer参数中增加了一个新的参数:group.instance.id。下面是这个参数的解释:

A unique identifier of the consumer instance provided by end user. Only non-empty strings are permitted. If set, the consumer is treated as a static member, which means that only one instance with this ID is allowed in the consumer group at any time. This can be used in combination with a larger session timeout to avoid group rebalances caused by transient unavailability (e.g. process restarts). If not set, the consumer will join the group as a dynamic member, which is the traditional behavior.

大致意思是:它是用户指定的一个consumer成员ID。每个消费者组下这些ID必须是唯一的。一旦设置了该ID,该消费者就会被视为是一个静态成员(Static Member)。静态成员配以较大的session超时设置能够避免因成员临时不可用(比如重启)而引发的Rebalance。由此可见,消费者组静态成员是2.3版本新引入的一个概念,主要是为了避免不必要的Rebalance。

 Rebalance Recap

之前我们在Kafka消费者组一文中讨论过Rebalance机制。它的主要作用是为消费者组下所有成员分配分区。Client端和Broker端需要同时参与到Rebalance过程。在Broker端,Coordinator组件负责处理成员管理,比如处理组成员发送的JoinGroup请求、SyncGroup请求、Heartbeat请求和LeaveGroup请求;在Client端,Leader Consumer成员接收Coordinator发送的成员订阅信息,然后根据一定的策略(Range/Round-Robin/Sticky/自定义)制定分配方案。

Rebalance发生的条件有三个:

  • 成员数量发生变化,即有新成员加入或现有成员离组(包括主动离组和崩溃被动离组)
  • 订阅主题数量发生变化
  • 订阅主题分区数量发生变化

其实,后两个条件可以合并成一个,即Rebalance触发条件只有两个:1. 成员数量发生变化;2. 订阅信息发生变化。

Rebalance的流程在那篇文章中也谈到了:首先,各个成员发送JoinGroup请求入组,Coordinator会等待一段时间等它们加入——这段时间由所有成员中max.poll.interval.ms的最大值来决定(在Kafka Connect中则是有专属的参数rebalance.timeout.ms来指定)。之后各成员发送SyncGroup请求等待Coordinator发送分配方案,然后开始正常消费。在消费的同时,各个consumer还会定期(heartbeat.interval.ms)上报心跳,告诉Coordinator组件它还活着。

 Issues for Rebalance

在实际场景中,因为成员离组而发生的Rebalance应该算是最多的,但有些场景下的Rebalance是非常不合理的。比如我们公司就有这样的痛点:Consumer的处理逻辑发生变更,必须要更新代码重新上线,此时就要引发Rebalance,但其实重启Consumer也许只需要几分钟而已,也就是说我的消费只要中断几分钟就可以了,Kafka完全没必要为这个就触发一轮Rebalance,更没有必要重新分配分区,维持之前的分配方案足矣。虽然社区提供的Sticky分配方案在一定程度上能够缓解此问题,但Rebalance的Stop The World(STW)的特性还是决定了生产环境中Rebalance越少越好。

Static Member

在目前的Rebalance设计中,消费者组下的每个实例都会被Coordinator分配一个成员ID,即member.id。很多Kafka用户都有过这样的疑问:我能手动设置这个member.id吗?很遗憾,这个memberID是Kafka自动生成的,在静态成员被引入前,规则是client.id-UUID,这里的client.id就是Consumer端参数client.id的值,而且这个ID会随着每轮Rebalance发生变化的。换句话说,Coordinator无法持久化地保存某个consumer实例的member.id。我想这可能是制约Rebalance时所有成员必须强制重新加入的部分原因,因为Coordinator无法记住每个成员都是谁。如果你看源代码,可以发现在每次Client重启回来发送JoinGroup时,它会封装一个UNKNOWN_MEMBER_ID的空串,没有任何有意义的信息给到Broker端。Coordinator接收到后只能把它当做是一个全新的成员。相反地,如果member.id能够被记住,那么Coordinator就可以容忍它短暂的离线而不开启Rebalance,从而缩短消费者组整体不可用的时间窗口。

为此,社区于2.3和2.4版本引入了静态成员(Static Member)的概念以及一个新的Consumer端参数:group.instance.id。一旦配置了该参数,成员将自动成为静态成员,否则的话和以前一样依然被视为是动态成员。你可以认为这个新参数是一个要被持久化的新member.id。它依然不能由用户指定,构建规则是`group.instsance.id`-UUID。和member.id不同的是,每次成员重启回来后,其静态成员ID值是不变的,因此之前分配给该成员的所有分区也是不变的,而且在没有超时前静态成员重启回来是不会触发Rebalance的。

静态成员Rebalance条件

显然,静态成员触发Rebalance的难度要小于动态成员。如果使用了静态成员,现在触发Rebalance的条件变更为:

  • 新成员加入组:这个条件依然不变。当有新成员加入时肯定会触发Rebalance重新分配分区
  • Leader成员重新加入组:比如主题分配方案发生变更
  • 现有成员离组时间超过了session超时时间:即使它是静态成员,Coordinator也不会无限期地等待它。一旦超过了session超时时间依然会触发Rebalance
  • Coordinator接收到LeaveGroup请求:成员主动通知Coordinator永久离组。毕竟Kafka还是要提供方法让一个成员能够永远地退出组,此时重启Rebalance还是必要的

请求协议变更

为了支持group.instance.id,与消费者组相关的协议格式也要做对应的变化。我看了下官网,JoinGroup、SyncGroup、LeaveGroup和OffsetCommit请求的协议格式都做了相应的变更。比如JoinGroup请求的Request和Response格式都增加了group-instance-id字段,如下所示:

JoinGroup Request (Version: 5) => group_id session_timeout_ms rebalance_timeout_ms member_id group_instance_id protocol_type [protocols]
  group_id => STRING
  session_timeout_ms => INT32
  rebalance_timeout_ms => INT32
  member_id => STRING
  group_instance_id => NULLABLE_STRING
  protocol_type => STRING
  protocols => name metadata
  name => STRING
  metadata => BYTES

JoinGroup Response (Version: 5) => throttle_time_ms error_code generation_id protocol_name leader member_id [members]
  throttle_time_ms => INT32
  error_code => INT16
  generation_id => INT32
  protocol_name => STRING
  leader => STRING
  member_id => STRING
  members => member_id group_instance_id metadata
  member_id => STRING
  group_instance_id => NULLABLE_STRING
  metadata => BYTES

其他请求格式的变更也是类似的,这里就不贴了。

其他变更

鉴于目前静态成员短暂重启或不可用不会触发Rebalance的改动,社区对消费者组最大session过期时间也做了修改。之前Consumer端参数group.min.session.timeout.ms值是6秒——要想在这个时间内重启完一个应用通常都是很困难的,因此社区现在将该值默认值改为30分钟。这就是说,只要配置有静态成员的Consumer程序代码更新及重启在30分钟之内完成,Consumer Group就不会发生Rebalance。当然在这段时间内,该Consumer的消费进度会中断,但是分区分配方案不会发生变化。

总结

目前静态成员的部分功能已经集成进Kafka 2.3版本,还有一部分功能正在开发中,未来会进到2.4版本中。从目前的设计来看,静态成员机制能够帮助我们规避很多线上环境中本不必要的Rebalance,应该说是个很令人期待的新特性。同时,社区针对Rebalance的Stop The World酝酿一次大的修正,即所谓的增量协同式Rebalance(Incremental Cooperative Rebalance)。大致思想是允许单个consumer实例自行采用增量或渐进式的方式进行Rebalance,避免全局的STW。相关的代码正在开发中,后续我也会带来这方面的功能介绍。

Kafka消费者组静态成员(static consumer member)的更多相关文章

  1. 详细解析kafka之 kafka消费者组与重平衡机制

    消费组组(Consumer group)可以说是kafka很有亮点的一个设计.传统的消息引擎处理模型主要有两种,队列模型,和发布-订阅模型. 队列模型:早期消息处理引擎就是按照队列模型设计的,所谓队列 ...

  2. Kafka消费者组再均衡问题

    在Kafka中,当有新消费者加入或者订阅的topic数发生变化时,会触发Rebalance(再均衡:在同一个消费者组当中,分区的所有权从一个消费者转移到另外一个消费者)机制,Rebalance顾名思义 ...

  3. Kafka 消费者解析

    一.消费者相关概念 1.1 消费组&消费者 消费者: 消费者从订阅的主题消费消息,消费消息的偏移量保存在Kafka的名字是__consumer_offsets的主题中 消费者还可以将⾃⼰的偏移 ...

  4. Kafka消费组(consumer group)

    一直以来都想写一点关于kafka consumer的东西,特别是关于新版consumer的中文资料很少.最近Kafka社区邮件组已经在讨论是否应该正式使用新版本consumer替换老版本,笔者也觉得时 ...

  5. Kafka设计解析(十三)Kafka消费组(consumer group)

    转载自 huxihx,原文链接 Kafka消费组(consumer group) 一直以来都想写一点关于kafka consumer的东西,特别是关于新版consumer的中文资料很少.最近Kafka ...

  6. kafka消费组、消费者

    consumer group consumer instance 一个消费组可能有一个或者多个消费者.同一个消费组可以订阅一个或者多个主题.主题的某一个分区只能被消费组的某一个消费者消费.那么分区和消 ...

  7. kafka Poll轮询机制与消费者组的重平衡分区策略剖析

    注意本文采用最新版本进行Kafka的内核原理剖析,新版本每一个Consumer通过独立的线程,来管理多个Socket连接,即同时与多个broker通信实现消息的并行读取.这就是新版的技术革新.类似于L ...

  8. kafka 消费组功能验证以及消费者数据重复数据丢失问题说明 3

    原创声明:作者:Arnold.zhao 博客园地址:https://www.cnblogs.com/zh94 背景 上一篇文章记录了kafka的副本机制和容错功能的说明,本篇则主要在上一篇文章的基础上 ...

  9. kafka producer自定义partitioner和consumer多线程

    为了更好的实现负载均衡和消息的顺序性,Kafka Producer可以通过分发策略发送给指定的Partition.Kafka Java客户端有默认的Partitioner,平均的向目标topic的各个 ...

随机推荐

  1. 小程序开发第一天josn和wxml

    视频中只有app.josn路径还有wxm文本.js中没有调用page.原视频中是可以出来文本内容的. 但是把js调用page以后是可以呈现的 所以疑问点就是为什么以前可以? 1.微信开发工具改了,强制 ...

  2. Windbg Assembly Code(反汇编)窗口的使用

    在WinDbg中,可以通过输入命令(u, ub, uu (Unassemble))或使用反汇编窗口查看程序汇编代码. 如何打开 DissAssembly Code窗口 通过菜单View-->Di ...

  3. webpack中路径的理解

    webpack 前端打包工具, 开发人员要面对的路径主要是: 打包前的路径(开发环境路径)和打包后的路径(生产环境路径) 在webpack.config.js中配置的output.path, outp ...

  4. C++中静态成员变量要在类外部再定义或初始化的原因

    C++中静态成员变量要在类外部再定义或初始化,否则会产生错误. class A { public: static int a; }; int A::a=0; 为什么要在类的外部进行定义的原因: 1. ...

  5. hive基础知识五

    Hive 主流文件存储格式对比 1.存储文件的压缩比测试 1.1 测试数据 https://github.com/liufengji/Compression_Format_Data ​ M 1.2 T ...

  6. 10-排序6 Sort with Swap(0, i) (25 分)

    Given any permutation of the numbers {0, 1, 2,..., N−1}, it is easy to sort them in increasing order ...

  7. java_home not found in your enviroment 问题解决方法

    java_home not found in your enviroment 错误原因有一下几点 1. JAVA_HOME系统环境没配置, JAVA_HOME环境变量配置方法: <1> 右 ...

  8. React - 入门:前导、环境、目录、原理

    前导介绍: facebook.2013开源.官网:https://reactjs.org/ 版本v16之后,对其底层的核心算法进行了重构,引入了底层的新引擎React Fiber(16版本以后的rea ...

  9. 屏蔽打开文件时提示“您尝试打开的文件xxx.xls的格式与文件扩展名指定的格式不一致。打开文件前请验证文件没有损坏且来源可信。是否立即打开该文 件?”

    修改注册表解决 1.打开注册表编辑器 方法:开始 -> 运行 -> 输入regedit -> 确定 2.找到注册表子项 HKEY_CURRENT_USER\Software\Micr ...

  10. just the check 买单

    今日焦点 Just the check 买单吧 split it 平分 leave a tip 留小费 词汇实践 hey. Can I get you anything else today? 您好. ...