线上一组 kafka 消费者在运行了很多天之后突然积压,日志显示该 kafka 消费者频繁 rebalance 并且大概率返回失败。
错误消息如下
1 | kafka server: The provided member is not known in the current generation |
有时候日志里还会伴随着
1 | i/o timeout |
我们添加了 errors 和 notifications 日志,发现每次错误都伴随着 rebalance。
我们首先认为是超时时间过短导致的,于是我们调大了连接超时和读写超时,但是问题没有得到解决。
我们又认为是我们处理信息的时间过长,导致 kafka server 认为 client 死掉了,然后进行 rebalance 导致的。于是我们将每条获取到的 message 放到 channel 中,由多个消费者去消费 channel 来解决问题,但是问题仍然没有解决。我们阅读了 sarama 的 heartbeat 机制,发现每个 consumer 都有单独的 goroutine 每 3 秒发送一次心跳。因此这个处理时间应该只会导致消费速度下降,不会导致 rebalance。
我们于是只好另外启动了一个消费者,指定了另外一个 group id,在消费过程中,我们看到并未发生 rebalance。这时我们更加一头雾水了。
直到我们看到了这篇文章 kafka consumer 频繁 reblance,这篇文章提到:
kafka 不同 topic 的 consumer 如果用的 group id 名字一样的情况下,其中任意一个 topic 的 consumer 重新上下线都会造成剩余所有的 consumer 产生 reblance 行为。
而我们正是不同的 topic 下有名字相同的 group id 的多个消费者。为了验证确实是由这个问题导致的,我们暂停了该 group id 下其他消费者的消费,之前频繁 rebalance 的消费者果真再也没有发生过 rebalance。
于是我们更改了这些消费者的 group id,以不同后缀进行区分,问题便解决了。
结论
由于 zookeeper 的特性,相同 group id 的不同 topic,只要有一个发生了 rebalance,都会广播给所有 topic,导致其他 topic 也发生 rebalance。在最坏情况下可能导致每个消费者都夯住。因此我们要注意用不同的 group id 来消费 kafka。