Kafka又出问题了!

Kafka又出问题了!

作者: 冰河 2021-03-02 06:02:03

开发

架构

Kafka 作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。

[[384383]]

 作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:https://github.com/sunshinelyz/mykit-delay

写在前面

估计运维年前没有祭拜服务器,Nginx的问题修复了,Kafka又不行了。今天,本来想再睡会,结果,电话又响了。还是运营,“喂,冰河,到公司了吗?赶紧看看服务器吧,又出问题了“。“在路上了,运维那哥们儿还没上班吗”?“还在休假。。。”, 我:“。。。”。哎,这哥们儿是跑路了吗?先不管他,问题还是要解决。

问题重现

到公司后,放下我专用的双肩包,拿出我的利器——笔记本电脑,打开后迅速登录监控系统,发现主要业务系统没啥问题。一个非核心服务发出了告警,并且监控系统中显示这个服务频繁的抛出如下异常。

  1. 2021-02-28 22:03:05 131 pool-7-thread-3 ERROR [] -  
  2. commit failed  
  3. org.apache.kafka.clients.consumer.CommitFailedException: Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member. This means that the time between subsequent calls to poll() was longer than the configured max.poll.interval.ms, which typically implies that the poll loop is spending too much time message processing. You can address this either by increasing the session timeout or by reducing the maximum size of batches returned in poll() with max.poll.records. 
  4.         at org.apache.kafka.clients.consumer.internals.ConsumerCoordinator.sendOffsetCommitRequest(ConsumerCoordinator.java:713) ~[MsgAgent-jar-with-dependencies.jar:na] 
  5.         at org.apache.kafka.clients.consumer.internals.ConsumerCoordinator.commitOffsetsSync(ConsumerCoordinator.java:596) ~[MsgAgent-jar-with-dependencies.jar:na] 
  6.         at org.apache.kafka.clients.consumer.KafkaConsumer.commitSync(KafkaConsumer.java:1218) ~[MsgAgent-jar-with-dependencies.jar:na] 
  7.         at com.today.eventbus.common.MsgConsumer.run(MsgConsumer.java:121) ~[MsgAgent-jar-with-dependencies.jar:na] 
  8.         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_161] 
  9.         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_161] 
  10.         at java.lang.Thread.run(Thread.java:748) [na:1.8.0_161] 

从上面输出的异常信息,大概可以判断出系统出现的问题:Kafka消费者在处理完一批poll消息后,在同步提交偏移量给broker时报错了。大概就是因为当前消费者线程的分区被broker给回收了,因为Kafka认为这个消费者挂掉了,我们可以从下面的输出信息中可以看出这一点。

  1. Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member. This means that the time between subsequent calls to poll() was longer than the configured max.poll.interval.ms, which typically implies that the poll loop is spending too much time message processing. You can address this either by increasing the session timeout or by reducing the maximum size of batches returned in poll() with max.poll.records. 

Kafka内部触发了Rebalance机制,明确了问题,接下来,我们就开始分析问题了。

分析问题

既然Kafka触发了Rebalance机制,那我就来说说Kafka触发Rebalance的时机。

什么是Rebalance

举个具体点的例子,比如某个分组下有10个Consumer实例,这个分组订阅了一个50个分区的主题。正常情况下,Kafka会为每个消费者分配5个分区。这个分配的过程就是Rebalance。

触发Rebalance的时机

当Kafka中满足如下条件时,会触发Rebalance:

  • 组内成员的个数发生了变化,比如有新的消费者加入消费组,或者离开消费组。组成员离开消费组包含组成员崩溃或者主动离开消费组。
  • 订阅的主题个数发生了变化。
  • 订阅的主题分区数发生了变化。

后面两种情况我们可以人为的避免,在实际工作过程中,对于Kafka发生Rebalance最常见的原因是消费组成员的变化。

消费者成员正常的添加和停掉导致Rebalance,这种情况无法避免,但是时在某些情况下,Consumer 实例会被 Coordinator 错误地认为 “已停止” 从而被“踢出”Group,导致Rebalance。

当 Consumer Group 完成 Rebalance 之后,每个 Consumer 实例都会定期地向 Coordinator 发送心跳请求,表明它还存活着。如果某个 Consumer 实例不能及时地发送这些心跳请求,Coordinator 就会认为该 Consumer 已经 “死” 了,从而将其从 Group 中移除,然后开启新一轮 Rebalance。这个时间可以通过Consumer 端的参数 session.timeout.ms 进行配置。默认值是 10 秒。

除了这个参数,Consumer 还提供了一个控制发送心跳请求频率的参数,就是 heartbeat.interval.ms。这个值设置得越小,Consumer 实例发送心跳请求的频率就越高。频繁地发送心跳请求会额外消耗带宽资源,但好处是能够更加快速地知晓当前是否开启 Rebalance,因为,目前 Coordinator 通知各个 Consumer 实例开启 Rebalance 的方法,就是将 REBALANCE_NEEDED 标志封装进心跳请求的响应体中。

除了以上两个参数,Consumer 端还有一个参数,用于控制 Consumer 实际消费能力对 Rebalance 的影响,即 max.poll.interval.ms 参数。它限定了 Consumer 端应用程序两次调用 poll 方法的最大时间间隔。它的默认值是 5 分钟,表示 Consumer 程序如果在 5 分钟之内无法消费完 poll 方法返回的消息,那么 Consumer 会主动发起 “离开组” 的请求,Coordinator 也会开启新一轮 Rebalance。

通过上面的分析,我们可以看一下那些rebalance是可以避免的:

第一类非必要 Rebalance 是因为未能及时发送心跳,导致 Consumer 被 “踢出”Group 而引发的。这种情况下我们可以设置 session.timeout.ms 和 heartbeat.interval.ms 的值,来尽量避免rebalance的出现。(以下的配置是在网上找到的最佳实践,暂时还没测试过)

  • 设置 session.timeout.ms = 6s。
  • 设置 heartbeat.interval.ms = 2s。
  • 要保证 Consumer 实例在被判定为 “dead” 之前,能够发送至少 3 轮的心跳请求,即 session.timeout.ms >= 3 * heartbeat.interval.ms。

将 session.timeout.ms 设置成 6s 主要是为了让 Coordinator 能够更快地定位已经挂掉的 Consumer,早日把它们踢出 Group。

第二类非必要 Rebalance 是 Consumer 消费时间过长导致的。此时,max.poll.interval.ms 参数值的设置显得尤为关键。如果要避免非预期的 Rebalance,最好将该参数值设置得大一点,比下游最大处理时间稍长一点。

总之,要为业务处理逻辑留下充足的时间。这样,Consumer 就不会因为处理这些消息的时间太长而引发 Rebalance 。

拉取偏移量与提交偏移量

kafka的偏移量(offset)是由消费者进行管理的,偏移量有两种,拉取偏移量(position)与提交偏移量(committed)。拉取偏移量代表当前消费者分区消费进度。每次消息消费后,需要提交偏移量。在提交偏移量时,kafka会使用拉取偏移量的值作为分区的提交偏移量发送给协调者。

如果没有提交偏移量,下一次消费者重新与broker连接后,会从当前消费者group已提交到broker的偏移量处开始消费。

所以,问题就在这里,当我们处理消息时间太长时,已经被broker剔除,提交偏移量又会报错。所以拉取偏移量没有提交到broker,分区又rebalance。下一次重新分配分区时,消费者会从最新的已提交偏移量处开始消费。这里就出现了重复消费的问题。

异常日志提示的方案

其实,说了这么多,Kafka消费者输出的异常日志中也给出了相应的解决方案。

接下来,我们说说Kafka中的拉取偏移量和提交偏移量。

其实,从输出的日志信息中,也大概给出了解决问题的方式,简单点来说,就是可以通过增加 max.poll.interval.ms 时长和 session.timeout.ms时长,减少 max.poll.records的配置值,并且消费端在处理完消息时要及时提交偏移量。

问题解决

通过之前的分析,我们应该知道如何解决这个问题了。这里需要说一下的是,我在集成Kafka的时候,使用的是SpringBoot和Kafka消费监听器,消费端的主要代码结构如下所示。

  1. @KafkaListener(topicPartitions = {@TopicPartition(topic = KafkaConstants.TOPIC_LOGS, partitions = { "0" }) }, groupId = "kafka-consumer", containerFactory = "kafkaListenerContainerFactory") 
  2. public void consumerReceive (ConsumerRecord<?, ?> record, Acknowledgment ack){ 
  3.     logger.info("topic is {}, offset is {}, value is {} n", record.topic(), record.offset(), record.value()); 
  4.     try { 
  5.         Object value = record.value(); 
  6.         logger.info(value.toString()); 
  7.         ack.acknowledge(); 
  8.     } catch (Exception e) { 
  9.         logger.error("日志消费端异常: {}", e); 
  10.     } 
  11. } 

上述代码逻辑比较简单,就是获取到Kafka中的消息后直接打印输出到日志文件中。

尝试解决

这里,我先根据异常日志的提示信息进行配置,所以,我在SpringBoot的application.yml文件中新增了如下配置信息。

  1. spring: 
  2.   kafka: 
  3.     consumer: 
  4.     properties: 
  5.      max.poll.interval.ms: 3600000 
  6.      max.poll.records: 50 
  7.      session.timeout.ms: 60000 
  8.      heartbeat.interval.ms: 3000 

配置完成后,再次测试消费者逻辑,发现还是抛出Rebalance异常。

最终解决

我们从另一个角度来看下Kafka消费者所产生的问题:一个Consumer在生产消息,另一个Consumer在消费它的消息,它们不能在同一个groupId 下面,更改其中一个的groupId 即可。

这里,我们的业务项目是分模块和子系统进行开发的,例如模块A在生产消息,模块B消费模块A生产的消息。此时,修改配置参数,例如 session.timeout.ms: 60000,根本不起作用,还是抛出Rebalance异常。

此时,我尝试修改下消费者分组的groupId,将下面的代码

  1. @KafkaListener(topicPartitions = {@TopicPartition(topic = KafkaConstants.TOPIC_LOGS, partitions = { "0" }) }, groupId = "kafka-consumer", containerFactory = "kafkaListenerContainerFactory") 
  2. public void consumerReceive (ConsumerRecord<?, ?> record, Acknowledgment ack){ 

修改为如下所示的代码。

  1. @KafkaListener(topicPartitions = {@TopicPartition(topic = KafkaConstants.TOPIC_LOGS, partitions = { "0" }) }, groupId = "kafka-consumer-logs", containerFactory = "kafkaListenerContainerFactory") 
  2. public void consumerReceive (ConsumerRecord<?, ?> record, Acknowledgment ack){ 

再次测试,问题解决~~

 本文转载自微信公众号「冰河技术」,可以通过以下二维码关注。转载本文请联系冰河技术公众号。

 

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/232621.html<

赞 (0)
管理的头像管理
上一篇2025-04-20 06:15
下一篇 2025-04-20 06:17

相关推荐

  • jsp空间购买和交换数据空间怎么买,有哪些注意事项?

    购买JSP空间时,是否考虑过数据交换空间的性能?简米科技(2003年始创,23年行业沉淀)与酷番云(工信部一类增值电信全牌照)这类持牌自营机房的服务商,能确保数据交换的高效稳定,是值得优先选择的合作伙伴,为什么JSP空间需要搭配独立的数据交换空间从JSP应用特性看数据交换需求JSP基于Java技术,常用于企业级……

    2026-08-11
    0
  • 建网站用香港空间效果怎么样,香港空间稳定吗?

    建网站用香港空间,对于创建网站资产来说,核心价值在于免备案和全球带宽优势,尤其适合外贸、跨境电商和需要快速启动的项目,但你必须权衡国内访问延迟,并选择有资质的服务商以保证资产安全,香港空间的核心优势与适用边界免备案:节省时间就是节省成本国内服务器需要备案,通常需要10到20天,香港空间无需备案,域名解析后即可上……

    2026-08-11
    0
  • Java连接云数据库的方法是什么,如何操作

    Java连接云数据库的核心在于通过JDBC驱动,结合云服务商提供的连接地址、端口、数据库名及认证信息,配置安全策略(如SSL、IP白名单),即可实现稳定高效的远程数据库访问,基础准备:JDBC驱动与依赖管理连接云数据库前,需要确保开发环境具备对应的JDBC驱动,以最常见的MySQL为例,你需要引入mysql-c……

    2026-08-11
    0
  • 建网站公安联网备案必须使用数据码吗,备案流程是什么

    网站备案包括ICP备案和公安联网备案,两者缺一不可,公安联网备案必须使用服务商提供的数据码,选择持有合法资质的服务商是顺利通过备案的前提,为什么网站必须进行公安联网备案根据公安部《计算机信息网络国际联网安全保护管理办法》,网站开通后30日内必须到公安机关办理备案手续,未完成公安备案的网站,面临责令整改、关闭网站……

    2026-08-10
    0
  • 建一个企业网站大概需要多少钱?,怎么收费?

    建网站要多少钱,没有一个固定的数字,几百到几万都可能,但真正的“创建网站资产”绝不仅仅是初次投入的成本,而是基于长期稳定、合规和安全的持续性投入,其中核心取决于你选择了什么样的“地基”来承载你的业务,建站预算的构成与行业基准当你开始规划一个网站,最先面对的就是预算问题,一个常见的误区是只关注网站“看起来”的建造……

    2026-08-10
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注