Kafka Streams on Kubernetes:重新部署后长期重新平衡
Kafka Streams on Kubernetes: Long rebalancing after redeployment
问题
我们使用 StatefulSet 在 Kubernetes 上部署 Scala Kafka Streams 应用程序。这些实例有单独的 applicationId
s,因此它们每个都复制完整的输入主题以实现容错。它们本质上是只读服务,只能读取状态主题并将其写入状态存储,从那里通过 REST 服务客户请求。这意味着,在任何给定时间,消费者组始终只包含一个 单个 Kafka Streams 实例。
我们现在的问题是,在触发滚动重启时,每个实例启动大约需要5分钟,其中大部分时间都在REBALANCING
状态下等待。我读过 here Kafka Streams 不会发送 LeaveGroup
请求以便在容器重启后快速返回,无需重新平衡。为什么这对我们不起作用,为什么重新平衡需要这么长时间,即使 applicationId
是相同的?理想情况下,为了最大限度地减少停机时间,应用程序应该在重新启动时立即从它离开的地方接管。
配置
以下是我们从默认值更改的一些配置:
properties.put(StreamsConfig.consumerPrefix(ConsumerConfig.MAX_POLL_RECORDS_CONFIG), "1000")
properties.put(StreamsConfig.consumerPrefix(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG), "300000")
properties.put(StreamsConfig.consumerPrefix(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG), "earliest")
// RocksDB config, see https://docs.confluent.io/current/streams/developer-guide/memory-mgmt.html
properties.put(StreamsConfig.ROCKSDB_CONFIG_SETTER_CLASS_CONFIG, classOf[BoundedMemoryRocksDBConfig])
问题/相关配置
- 是否有助于减少
session.timeout.ms
?我们将其设置为相当大的值,因为 Kafka 代理位于不同的数据中心并且网络连接有时不是非常可靠。
- This answer 建议减少
max.poll.interval.ms
,因为它与重新平衡超时有关。那是对的吗?我犹豫是否要更改此设置,因为它可能会对我们应用程序的正常运行模式产生影响。
- There is mention 配置
group.initial.rebalance.delay.ms
以在部署期间延迟重新平衡 - 但在从崩溃中恢复后也会导致延迟,不是吗?
- 我还偶然发现了 KIP-345,它的目标是完全通过
group.instance.id
消除静态成员资格的消费者再平衡,这很适合我们的用户案例,但它似乎并不在我们的经纪人上可用。
我对众多配置以及如何使用它们在更新后启用快速恢复感到困惑。谁能解释一下他们是如何一起玩的?
您引用的另一个问题并没有说重启时可以避免重新平衡。不发送 LeaveGroupRequest
只会在您停止应用程序时避免重新平衡。因此,重新平衡的次数从两个减少到一个。当然,对于你有点不寻常的单实例部署,你在这里什么也得不到(事实上,它可能实际上 "hurt" 你...)a
Would it help to decrease session.timeout.ms? We set it to quite a large value as the Kafka brokers live in a different data center and network connections are at times not super reliable.
可能是,取决于您重启应用的速度。 (下面有更多详细信息。)也许只是尝试一下(即,将其设置为 3 分钟以保持较高的稳定性值并看到重新平衡时间下降到 3 分钟?
This answer suggests to decrease max.poll.interval.ms, as it is tied to a rebalance timeout. Is that correct? I'm hesitant to change this, as it might have consequences on the normal operation mode of our app.
max.poll.interval.ms
也会影响再平衡时间(更多详情见下文)。但是,默认值为 30 秒,因此不应导致 5 分钟的重新平衡时间。
There is mention of a config group.initial.rebalance.delay.ms to delay rebalancing during a deployment - but that would cause delays also after recovery from a crash, wouldn't it?
这只适用于空的消费组,默认值只有3秒。所以应该不会影响到你。
I also stumbled upon KIP-345, which targets to eliminate consumer rebalancing for static memberships entirely via group.instance.id, which would be a good fit for our user case, but it does not seem to be available yet on our brokers.
使用静态组成员资格实际上可能是最好的选择。也许值得升级您的经纪人以获得此功能。
顺便说一句,session.timeout.ms
和 max.poll.interval.ms
之间的区别在另一个问题中有解释:
一般来说,代理方组协调器维护每个 "group generation" 所有成员的列表。如果成员主动离开组(通过发送 LeaveGroupRequest
)、超时(通过 session.timeout.ms
或 max.poll.interval.ms
)或新成员加入组,则会触发重新平衡。如果发生重新平衡,每个成员都有机会重新加入该组以包含在下一代中。
对于您的情况,群组只有一名成员。当您停止您的应用程序时,不会发送 LeaveGroupRequest
,因此组协调员只会在 session.timeout.ms
通过后删除该成员。
如果您重新启动该应用程序,它将作为 "new" 成员返回(从组协调员的角度来看)。这将触发重新平衡,使该组的所有成员都可以更改以重新加入该组。对于您的情况, "old" 实例可能仍在组中,因此只有在组协调员从组中删除旧成员后,再平衡才会向前推进。问题可能是,组协调员认为该组从一个成员扩展到两个成员......(这就是我上面的意思:如果要发送 LeaveGroupRequest
,当你发送时,该组将变为空停止你的应用程序,并且在重新启动时只有新成员会在组中并且重新平衡会立即进行。)
使用静态组成员可以避免这个问题,因为在重启时实例可以被重新识别为 "old" 实例,并且组协调器不需要等待旧组成员过期。
问题
我们使用 StatefulSet 在 Kubernetes 上部署 Scala Kafka Streams 应用程序。这些实例有单独的 applicationId
s,因此它们每个都复制完整的输入主题以实现容错。它们本质上是只读服务,只能读取状态主题并将其写入状态存储,从那里通过 REST 服务客户请求。这意味着,在任何给定时间,消费者组始终只包含一个 单个 Kafka Streams 实例。
我们现在的问题是,在触发滚动重启时,每个实例启动大约需要5分钟,其中大部分时间都在REBALANCING
状态下等待。我读过 here Kafka Streams 不会发送 LeaveGroup
请求以便在容器重启后快速返回,无需重新平衡。为什么这对我们不起作用,为什么重新平衡需要这么长时间,即使 applicationId
是相同的?理想情况下,为了最大限度地减少停机时间,应用程序应该在重新启动时立即从它离开的地方接管。
配置
以下是我们从默认值更改的一些配置:
properties.put(StreamsConfig.consumerPrefix(ConsumerConfig.MAX_POLL_RECORDS_CONFIG), "1000")
properties.put(StreamsConfig.consumerPrefix(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG), "300000")
properties.put(StreamsConfig.consumerPrefix(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG), "earliest")
// RocksDB config, see https://docs.confluent.io/current/streams/developer-guide/memory-mgmt.html
properties.put(StreamsConfig.ROCKSDB_CONFIG_SETTER_CLASS_CONFIG, classOf[BoundedMemoryRocksDBConfig])
问题/相关配置
- 是否有助于减少
session.timeout.ms
?我们将其设置为相当大的值,因为 Kafka 代理位于不同的数据中心并且网络连接有时不是非常可靠。 - This answer 建议减少
max.poll.interval.ms
,因为它与重新平衡超时有关。那是对的吗?我犹豫是否要更改此设置,因为它可能会对我们应用程序的正常运行模式产生影响。 - There is mention 配置
group.initial.rebalance.delay.ms
以在部署期间延迟重新平衡 - 但在从崩溃中恢复后也会导致延迟,不是吗? - 我还偶然发现了 KIP-345,它的目标是完全通过
group.instance.id
消除静态成员资格的消费者再平衡,这很适合我们的用户案例,但它似乎并不在我们的经纪人上可用。
我对众多配置以及如何使用它们在更新后启用快速恢复感到困惑。谁能解释一下他们是如何一起玩的?
您引用的另一个问题并没有说重启时可以避免重新平衡。不发送 LeaveGroupRequest
只会在您停止应用程序时避免重新平衡。因此,重新平衡的次数从两个减少到一个。当然,对于你有点不寻常的单实例部署,你在这里什么也得不到(事实上,它可能实际上 "hurt" 你...)a
Would it help to decrease session.timeout.ms? We set it to quite a large value as the Kafka brokers live in a different data center and network connections are at times not super reliable.
可能是,取决于您重启应用的速度。 (下面有更多详细信息。)也许只是尝试一下(即,将其设置为 3 分钟以保持较高的稳定性值并看到重新平衡时间下降到 3 分钟?
This answer suggests to decrease max.poll.interval.ms, as it is tied to a rebalance timeout. Is that correct? I'm hesitant to change this, as it might have consequences on the normal operation mode of our app.
max.poll.interval.ms
也会影响再平衡时间(更多详情见下文)。但是,默认值为 30 秒,因此不应导致 5 分钟的重新平衡时间。
There is mention of a config group.initial.rebalance.delay.ms to delay rebalancing during a deployment - but that would cause delays also after recovery from a crash, wouldn't it?
这只适用于空的消费组,默认值只有3秒。所以应该不会影响到你。
I also stumbled upon KIP-345, which targets to eliminate consumer rebalancing for static memberships entirely via group.instance.id, which would be a good fit for our user case, but it does not seem to be available yet on our brokers.
使用静态组成员资格实际上可能是最好的选择。也许值得升级您的经纪人以获得此功能。
顺便说一句,session.timeout.ms
和 max.poll.interval.ms
之间的区别在另一个问题中有解释:
一般来说,代理方组协调器维护每个 "group generation" 所有成员的列表。如果成员主动离开组(通过发送 LeaveGroupRequest
)、超时(通过 session.timeout.ms
或 max.poll.interval.ms
)或新成员加入组,则会触发重新平衡。如果发生重新平衡,每个成员都有机会重新加入该组以包含在下一代中。
对于您的情况,群组只有一名成员。当您停止您的应用程序时,不会发送 LeaveGroupRequest
,因此组协调员只会在 session.timeout.ms
通过后删除该成员。
如果您重新启动该应用程序,它将作为 "new" 成员返回(从组协调员的角度来看)。这将触发重新平衡,使该组的所有成员都可以更改以重新加入该组。对于您的情况, "old" 实例可能仍在组中,因此只有在组协调员从组中删除旧成员后,再平衡才会向前推进。问题可能是,组协调员认为该组从一个成员扩展到两个成员......(这就是我上面的意思:如果要发送 LeaveGroupRequest
,当你发送时,该组将变为空停止你的应用程序,并且在重新启动时只有新成员会在组中并且重新平衡会立即进行。)
使用静态组成员可以避免这个问题,因为在重启时实例可以被重新识别为 "old" 实例,并且组协调器不需要等待旧组成员过期。