在 Kubernetes 上重新启动时持久的 Kafka transaction-id
Persistent Kafka transacton-id across restarts on Kubernetes
我正在尝试使用 Spring-Kafka on Kubernetes 在 Kafka 上实现精确一次交付。
据我所知,事务 ID 必须在生产者上设置,并且在重新启动时它应该相同,如此处所述 .
在 Kubernetes 上使用此语义会出现问题。 如何获得一致的 ID?
为了解决这个问题,我实现了一个 Spring 启动应用程序,我们称它为“副本计数器”,它通过 Kubernetes API 检查有多少 pods与调用者同名,所以我为每个 pod 副本都有一个计数器。
例如,假设我要部署一个Pod,我们称它为APP-1
。
此应用执行以下操作:
- 它向副本计数器执行
GET
并将 pod 名称作为参数传递。
- replicas-counter 调用 Kubernetes API 以检查有多少 pods 具有该 pod 名称。所以它对调用者做了一个 +1 和 returns 。我还需要计算未就绪 pods(考虑第一次部署,如果我不检查未就绪 pods,他们将无法获得 ID)。
- APP-1 获取 ID 并将其用作交易 ID
但是,如您所见,执行滚动更新时可能会出现问题,例如:
假设我们有 3 个 pods:
一开始我们有:
- app-1: transactional-id-1
- app-2: transactional-id-2
- app-3:交易 ID-3
因此,在滚动更新期间我们将:
old-app-1: transactional-id-1
old-app-2: transactional-id-2
old-app-3: transactional-id-3
new-app-3: transactional-id-4(未就绪,等待就绪)
New-app-3 准备就绪,因此 Kubernetes 关闭了 Old-app-3。所以是时候继续滚动更新了。
old-app-1: transactional-id-1
old-app-2: transactional-id-2
new-app-3: transactional-id-4
new-app-2: transactional-id-4(未就绪,等待就绪)
如你所见,我有 2 个 pods 具有相同的交易 ID。
据我了解,这些 ID 在重新启动时必须相同且唯一。
我怎样才能实现给我一致 ID 的东西?有人处理过这个问题吗?
这些 ID 的问题仅适用于 Kubernetes 部署,而不适用于有状态集,因为它们有一个稳定的标识符作为名称。我不想将所有部署都转换为有状态集来解决这个问题,因为我认为这不是处理这种情况的正确方法。
保证Pods
唯一性的唯一方法是使用StatefulSet。
StatefulSets
将允许您保持活动副本的数量,但每次 pod 死亡时,它将被替换为相同的主机和配置。这将防止所需的数据丢失。
Statefulset
中的服务必须是 headless
,因为每个 pod 都是独一无二的,所以您需要一定的流量才能达到一定的 pods。
每个 pod
都需要一个 PVC
(以便存储数据并在 pod 从该数据中删除时重新创建)。
Here 是一篇很好的文章,描述了为什么在类似情况下应使用 StatefulSet
。
我正在尝试使用 Spring-Kafka on Kubernetes 在 Kafka 上实现精确一次交付。 据我所知,事务 ID 必须在生产者上设置,并且在重新启动时它应该相同,如此处所述 .
在 Kubernetes 上使用此语义会出现问题。 如何获得一致的 ID?
为了解决这个问题,我实现了一个 Spring 启动应用程序,我们称它为“副本计数器”,它通过 Kubernetes API 检查有多少 pods与调用者同名,所以我为每个 pod 副本都有一个计数器。
例如,假设我要部署一个Pod,我们称它为APP-1
。
此应用执行以下操作:
- 它向副本计数器执行
GET
并将 pod 名称作为参数传递。 - replicas-counter 调用 Kubernetes API 以检查有多少 pods 具有该 pod 名称。所以它对调用者做了一个 +1 和 returns 。我还需要计算未就绪 pods(考虑第一次部署,如果我不检查未就绪 pods,他们将无法获得 ID)。
- APP-1 获取 ID 并将其用作交易 ID
但是,如您所见,执行滚动更新时可能会出现问题,例如:
假设我们有 3 个 pods:
一开始我们有:
- app-1: transactional-id-1
- app-2: transactional-id-2
- app-3:交易 ID-3
因此,在滚动更新期间我们将:
old-app-1: transactional-id-1
old-app-2: transactional-id-2
old-app-3: transactional-id-3
new-app-3: transactional-id-4(未就绪,等待就绪)
New-app-3 准备就绪,因此 Kubernetes 关闭了 Old-app-3。所以是时候继续滚动更新了。
old-app-1: transactional-id-1
old-app-2: transactional-id-2
new-app-3: transactional-id-4
new-app-2: transactional-id-4(未就绪,等待就绪)
如你所见,我有 2 个 pods 具有相同的交易 ID。
据我了解,这些 ID 在重新启动时必须相同且唯一。
我怎样才能实现给我一致 ID 的东西?有人处理过这个问题吗?
这些 ID 的问题仅适用于 Kubernetes 部署,而不适用于有状态集,因为它们有一个稳定的标识符作为名称。我不想将所有部署都转换为有状态集来解决这个问题,因为我认为这不是处理这种情况的正确方法。
保证Pods
唯一性的唯一方法是使用StatefulSet。
StatefulSets
将允许您保持活动副本的数量,但每次 pod 死亡时,它将被替换为相同的主机和配置。这将防止所需的数据丢失。
Statefulset
中的服务必须是 headless
,因为每个 pod 都是独一无二的,所以您需要一定的流量才能达到一定的 pods。
每个 pod
都需要一个 PVC
(以便存储数据并在 pod 从该数据中删除时重新创建)。
Here 是一篇很好的文章,描述了为什么在类似情况下应使用 StatefulSet
。