在使用了最新版的 kafka-python 1.4.6 在 broker 对 topic 进行默认配置的情况下报出类似错误

CommitFailedError
CommitFailedError: 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 rebalance timeout with max_poll_interval_ms,
or by reducing the maximum size of batches returned in poll()
with max_poll_records.

这里要申明一点,在 1.4.0 以上的 kafka-python 版本使用了独立的心跳线程去上报心跳。

这里报错大概表达的意思是 无法在默认 300000ms 中完成处理操作。我们通常会一次性 poll 拉默认 500 条数据下来。我们需要在 300s 中完成 500 条数据的处理。如果不能完成的话就可能会触发这个问题。

因为这个报错的提示写得非常清楚,所以我们先按这个方向去尝试处理这个问题。首先调高了我们的 max_poll_interval_ms 的时间,但是无效。

然后 records 的条数减少,依然无效,该报错还是会报错。这不禁让我怀疑触发这个问题的是否并非这里报错建议的那些地方。

所以我把目光放到了 broker 日志那边去,想看下到底是因为什么原因导致爆出类似错误。

在日志上发现了一些日志,对应的 consumer 在反复的 rebalance:

[-- ::,] INFO [GroupCoordinator ]: Member kafka-python-1.4.-05ed83f1-aa90--b097-4cf467598082 in group sync_group_20180321 has failed, removing it from the group (kafka.coordinator.group.GroupCoordinator)
[-- ::,] INFO [GroupCoordinator ]: Stabilized group sync_group_20180321 generation (__consumer_offsets-) (kafka.coordinator.group.GroupCoordinator)
[-- ::,] INFO [GroupCoordinator ]: Member kafka-python-1.4.-f7826720-fef7-4b02--d1f38065c2fe in group sync_group_20180321 has failed, removing it from the group (kafka.coordinator.group.GroupCoordinator)
[-- ::,] INFO [GroupCoordinator ]: Preparing to rebalance group sync_group_20180321 with old generation (__consumer_offsets-) (kafka.coordinator.group.GroupCoordinator)
[-- ::,] INFO [GroupCoordinator ]: Member kafka-python-1.4.-ac5f6aff--4e67-a529-31674c72b1e4 in group sync_group_20180321 has failed, removing it from the group (kafka.coordinator.group.GroupCoordinator)
[-- ::,] INFO [GroupCoordinator ]: Stabilized group sync_group_20180321 generation (__consumer_offsets-) (kafka.coordinator.group.GroupCoordinator)
[-- ::,] INFO [GroupCoordinator ]: Assignment received from leader for group sync_group_20180321 for generation (kafka.coordinator.group.GroupCoordinator)

参考 sentry 打出来的错误,我们可以认为这和 sentry 爆出来的问题有直接关系。因此我们要从另外一个角度去思考一下为什么我的 max_poll_interval_ms 已经调高并且每次拉取处理条数降低却依然会报出此问题,并且频繁触发 rebalance 。

kafka-python 在 1.4.0 版本分离了心跳线程和 poll 主线程。我的第一反应就是会不会因为 poll 线程阻塞了心跳线程的切换,或者引起了某种死锁从而导致心跳线程无法正确的发起心跳。最后导致 broker 认为 group 已经死亡然后主动触发了 rebalance .

然后我去 kafka-python 的 gihub 搜索了一下类似问题,马上就发现了有不少人都有这个问题。

https://github.com/dpkp/kafka-python/issues/1418

从中找到一些有趣的信息,比如来自 vimal3271 的测试

I am seeing consumer rebalances even if there is no messages to consume. Start three consumers in a group and send some messages to topic and after that stop the producer. The consumer will start seeing rebalances after -6mins.
Sample code here:
https://stackoverflow.com/questions/54908902/kafka-consumer-rebalance-occurs-even-if-there-is-no-message-to-consume

他说即使在没有消息可以消费的情况下,也可以看到 kafka consumer 在过了 5 - 6 mins 之后开启了 rebalance 。

这就跟我们的问题非常相似,我们并不是 process 的过程消耗的时间过长而触发了 rebalance 而是有可能是因为消费得太快,导致有些消费者处于 空 poll 的状态从而阻塞了心跳线程。客观来说,我目前还会报出这个问题的 topic 有多达 50 个partitions,我开启了5个消费者对其进行消费,平均一个消费者需要消费 10 个parititons 。如果有某个 partitions 长期没有消费过来我们可能会被阻塞在那里最终导致 heartbeat 超时。 1.4.6 的客户端默认 10s 没心跳就超时,而发送间隔仅为 3s 。也就是连续三个周期没有发送就超时了。

下面看到 dpkp 的一个回复,表达了有可能就是被 poll 主线程阻塞,的问题,并且有 workaround 可以用来避免这种情况:

vimal: thanks for posting. I believe you may be hitting lock contention between an idle client.poll -- which can block and hold the client lock for the entire request_timeout_ms -- and the attempt by the heartbeat thread to send a new request. It seems to me that we may need to use KafkaClient.wakeup() to make sure that the polling thread drops the lock if/when we need to send a request from a different thread.

This shouldn't be an issue when messages are flowing through your topics at a steady rate. If this is just a test environment, and you expect your production environment to have more steady live data, then you could just ignore the error in testing. But if you are managing a topic w/ very low traffic -- delays of minutes between consecutive messages, for example -- you might try to reduce the request_timeout_ms to something closer to the heartbeat_interval_ms, which should prevent the read side from blocking for much longer than the heartbeat timeout. But note that other timeouts may also need to change (max_poll_interval_ms and session_timeout_ms perhaps). Another workaround might be to reduce metadata_max_age_ms to something close / equal to your heartbeat_timeout_ms. This will cause more frequent metadata requests, but should unblock the send side when there is no socket data available for reads.

dpkp 的观点在于,如果我们数据发送过来的频率是稳定的,消费者是正好可以消费完队列里面的信息的情况的时候,不应该出现这样的问题。出现这样的问题与我们预期和看到报错的情况可能恰恰相反,不是我们消费得太慢,而是我们消费得太快,并且生产者发送消息的频率过低导致的。在 poll 不到消息的时候,主线程可能会面临阻塞,而无法及时切换到心跳线程进行心跳的发送,最终导致了这个问题。

他给到一个 trick 的方法来解决这个问题,当面临这种情况的时候我们可以把 metadata_max_age_ms 调整到和心跳发送频率差不多 close / equal to our heartbeat_timeout_ms.

发送 metadata_request 会解除我们发送端的阻塞,从而达到抑制死锁的效果。

self.kafka = kafka.KafkaConsumer(
auto_offset_reset=auto_offset_reset,
bootstrap_servers=['10.171.97.1:9092', '10.163.13.219:9092', '10.170.249.122:9092'],
group_id=group_id,
metadata_max_age_ms=metadata_max_age_ms
)
self.kafka.subscribe(topics)

尝试补充了 metadata_max_age_ms 大约 3000 ms ,这个问题得到了很大程度的解决和缓解。

既然确定了可能是因为消费太快,然后生产慢导致的主线程锁住的问题,剩下可以验证一下是否真的是这样。尝试打日志看一下切换线程发送心跳的情况可以来确认该问题是否如此。

另外看代码发现 poll 主线程在 poll 之前会默认会进行 wakeup() 但是在 1.4.6里面也因为之前的 某个 bug 而默认关闭了,不知道是否有影响,等后续测试之后补上。

Reference:

https://github.com/dpkp/kafka-python/issues/1418  Heartbeat failed for group xxxWorker because it is rebalancing

https://github.com/dpkp/kafka-python/issues/1760  [1.4.5] KafkaProducer raises KafkaTimeoutError when attempting wakeup()

https://www.cnblogs.com/huxi2b/p/6815797.html  Kafka 0.11版本新功能介绍 —— 空消费组延时rebalance

kafka-python 1.4.6 版本触发的一个 rebalance 问题的更多相关文章

  1. 【原创】Windows平台搭建Kafka源代码开发环境(Eclipse版本)

    最近在研究Kafka源代码,需要自己搭建一个开发环境.官网上给出的提示略显简单,照着做了一遍也碰到了一些问题.特此记录下来. 开发环境: Oracle Java 1.7_u71 + Eclipse 4 ...

  2. 升级python到2.7版本pip不可用

    升级python到2.7版本pip不可用 [root@localhost pip-7.1.2]# pip Traceback (most recent call last): File "/ ...

  3. python和numpy的版本、安装位置

    命令行下查看python和numpy的版本和安装位置 1.查看python版本 方法一: python -V 注意:‘-V‘中‘V’为大写字母,只有一个‘-’ 方法二: python --versio ...

  4. 升级python的sqlite库版本

    今天了解了一下用python获取chrome cookie信息,在研究的过程中,发现打开数据库失败,后来调查了一下发现是由于sqlite3库太老的缘故,起码需要3.8以上,然后看了一下python 2 ...

  5. Maya Max python PySide集成 shiboken版本对应关系

    Maya_Max _python_PySide集成_shiboken版本对应关系 1.如何查看 Maya Max 集成的 Python版本: Maya:在 Maya 的安装目录下的 bin 文件夹中找 ...

  6. 如何查看安装python和numpy的版本

    命令行下查看python和numpy的版本和安装位置 1.查看python版本 方法一: python -V 注意:‘-V‘中‘V’为大写字母,只有一个‘-’ 方法二: python --versio ...

  7. 命令行下查看python和numpy的版本和安装位置

    命令行下查看python和numpy的版本和安装位置 1.查看python版本 方法一: python -V 注意:‘-V‘中‘V’为大写字母,只有一个‘-’ 方法二: python --versio ...

  8. 【转】python 2.6.6升级到python 2.7.x版本的方法

    1.下载python2.7.x wget https://www.python.org/ftp/python/2.7.6/Python-2.7.6.tgz 2.解压并编译安装 tar -zxvf Py ...

  9. 2个版本并存的python使用新的版本安装django的方法

    2个版本并存的python使用新的版本安装django的方法 默认是使用 pip install django 最新版的django会提示  要求python版本3.4以上,系统默认的版本是2.7.5 ...

随机推荐

  1. 使用 ProcessMonitor 找到进程所操作的文件的路径

    原文:使用 ProcessMonitor 找到进程所操作的文件的路径 很多系统问题都是可以修的,不需要重装系统,但是最近我还是重装了.发现之前正在玩的一款游戏的存档没有了--因为我原有系统的数据并没有 ...

  2. 华为、华三 交换机 开启SNMP 简单网络管理协议

    [huawei]snmp-agent //使能SNMP代理 [huawei]snmp-agent sys-info version all //允许所有SNMP 支持 协议 [huawei]snmp- ...

  3. VMware 网络介绍

       3.1 网卡介绍 如图所示,你的机器有两块网卡,一个是有线,一个是无线. 装完VM之后,会出现两块虚拟网卡,如图 VM有四种连接方式,我们着重介绍前三种    3.2 桥接 选择桥接模式,说明V ...

  4. ssm动态sql语句

    1.将上面的元素分为四组来演示,分别为:[if,where,trim],[if,set,trim],[choose,when,otherwise],[foreach] ________________ ...

  5. 防止用户重复提交表单数据,session方式,js方式

    1. 使用session的方式创建Token令牌解决 创建一个生成令牌的工具类,在该类中有返回类的对象,生成token的方法 public class TokenUtil { /* *单例设计模式(保 ...

  6. 2019 4399java面试笔试题 (含面试题解析)

    本人3年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.4399等公司offer,岗位是Java后端开发,最终选择去了4399. 面试了很多家公司,感觉大部分公司考察的点 ...

  7. Java自学-控制流程 switch

    Java的 switch 语句 switch 语句相当于 if else 的另一种表达方式 示例 1 : switch switch可以使用byte,short,int,char,String,enu ...

  8. AngularJS $http用法总结

    最近由于项目需要,在研究AngularJS $http的用法,查了很多资料,发现貌似没有一篇内容可以完整的满足我对$http的基本了解,为了下次方便自己查找,所以特意把最近查到的一些资料和自己的理解记 ...

  9. 【Win10】系统修改

    1.删除“快速访问”[操作说明]      a.打开HKEY_CLASSES_ROOT\CLSID\{679f85cb-0220-4080-b29b-5540cc05aab6}\ShellFolder ...

  10. 【TBarCode SDK教程】TBarCode SDK 如何在 Microsoft Office 中工作?

    使用条形码软件组件 TBarCode SDK,你可以在 Microsoft Office 中快速且简便地创建各种条形码.都不需要任何编程的技巧,只需要点击几次鼠标就可以将TBarCode SDK集成到 ...