我在Kafka 0.10.0.1集群中有一个包含10个分区的主题。我有一个产生多个消费者线程的应用程序。对于这个主题,我产生了5个线程。很多时候,在我的应用程序日志中,我看到了这个条目
INFO :: AbstractCoordinator:600 - Marking the coordinator x.x.x.x:9092
(id:2147483646 rack: null) dead for group notifications-consumer
然后有几个条目说(Re-)joining group notifications-consumer.
之后我也看到一个警告说
Auto commit failed for group notifications-consumer: 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 by poll() with max.poll.records.
现在我已经调整了我的消费者配置
props.put("max.poll.records", 200);
props.put("heartbeat.interval.ms", 20000);
props.put("session.timeout.ms", 60000);
所以,即使在正确调整配置后,我仍然会收到此错误。在重新平衡期间,我们的应用程序完全没有响应。请帮忙。
答案 0 :(得分:5)
使用session.timeout.ms
只能控制心跳超时,这意味着自上次心跳后已经过session.timeout.ms
毫秒,集群将您声明为死节点并触发重新平衡。
在KIP-62之前,在轮询中发送了心跳但现在被移动到特定的后台线程,以避免在花费的时间超过session.timeout.ms
时调用另一个{{1 }}。
将心跳分离到特定线程将处理与告知集群已启动并运行的处理分离,但这带来了" livelock"过程有效,但没有取得进展的情况,因此除了使心跳独立于poll()
之外,还引入了新的超时以确保消费者活着并取得进展。
文档说明了KIP-62之前的实现:
只要消费者发送心跳,它就会对分配的分区进行锁定。如果该过程以无法取得进展但仍继续发送心跳的方式失效,则该组中的其他成员将无法接管分区,这会导致延迟增加。然而,心跳和处理都在同一个线程中完成的事实保证了消费者必须在保持其分配方面取得进展。任何影响处理的失速也会影响心跳。
KIP-62引入的变化包括:
解耦处理超时:我们建议为记录处理引入单独的本地强制超时和后台线程,以使会话保持活动状态,直到超时到期。我们将此新超时称为"进程超时"并在消费者的配置中将其公开为max.poll.interval.ms。此配置设置客户端调用poll()
之间的最大延迟
根据您发布的日志,我认为您可能处于这种情况,您的应用程序花费的时间超过poll
(默认为5分钟),以处理200个轮询记录。
如果您处于这种情况下,则只能减少max.poll.interval.ms
或增加max.poll.records
。
您日志中显示的max.poll.interval.ms
配置来自(至少)kafka 0.10.1.0,所以我假设您在那里犯了一个小错误。
如果我理解你错了,请纠正我,但是在你的上一条评论中,你说你正在创造25个消费者(例如,如果你使用的是java {25 max.poll.interval.ms
)并将它们怀疑为N个不同的主题但使用相同的{ {1}}。
如果这是正确的,每次启动或停止org.apache.kafka.clients.consumer.KafkaConsumer
时都会看到重新启动,因为它会发送包含group.id
或KafkaConsumer
消息(请参阅相应的kafka protocol) JoinGroup
和LeaveGroup
(group.id
不是主机,因此在同一进程中创建的两个使用者仍将具有不同的ID)。请注意,这些消息不包含主题订阅信息(尽管该信息应该在代理中,但是kafka不会将其用于重新平衡)。
因此,每次群集收到member.id
的{{1}}或member.id
时,都会触发具有相同JoinGroup
X的所有消费者的重新平衡。
如果您启动25个具有相同LeaveGroup
的消费者,您将看到重新平衡,直到创建最后一个消费者并且相应的重新平衡结束(如果您继续看到此消息,则可能会阻止消费者)。
我有this issue a couple months ago。
如果我们有两个KafkaConsumer使用相同的group.id(在相同的进程或两个不同的进程中运行)并且其中一个被关闭,它会触发另一个KafkaConsumer的重新平衡,即使他们订阅了不同的主题。 我想经纪人必须只考虑group.id进行重新平衡,而不是与LeaveGroupRequest对(group_id,member_id)对应的订阅主题,但我想知道这是否是预期的行为或者&# 39;应该改进的东西? 我想这可能是避免代理中更复杂的重新平衡的第一个选项,并且考虑到解决方案非常简单,即只是为不同的KafkaConsumer使用不同的组ID,即使它们在同一个进程中运行,也会订阅不同的主题。
当重新平衡发生时,我们会看到重复的消息
这是已消除的行为,一个消费者使用消息但在提交偏移量之前触发了重新平衡并且提交失败。当重新平衡完成时,将具有该主题分配的进程将再次使用该消息(直到提交成功)。
我分成两组,现在突然问题从过去2个小时就消失了。
你在这里击中了钉子,但如果你不想看到任何(可避免的)再平衡,你应该为每个主题使用不同的group.id
。
以下是关于不同重新平衡方案的great talk。