mongock 能否与 kubernetes 副本一起正常工作?

Will mongock work correctly with kubernetes replicas?

Mongock 看起来很有前途。我们想在具有多个 运行 并行副本的 kubernetes 服务中使用它。

我们希望在部署我们的服务时,第一个副本将获得 mongockLock 并且其所有 ChangeLogs/ChangeSets 将在其他副本尝试 运行 之前完成。

我们在 kubernetes 环境中有一个 mongodb 运行ning 实例,我们希望 mongock ChangeLogs/ChangeSets 只执行一次。

mongockLock 会保证只有一个副本 运行 ChangeLogs/ChangeSets 完成吗?

或者我是否需要启用交易(或其他一些配置)?

我将先提供简短的答案,然后再提供长的答案。我建议您也阅读长篇,以便正确理解它。

简答

默认情况下,Mongock 保证 ChangeLogs/changeSets 将 运行 一次仅由一个 pod 执行。拥有锁的人。

长答案

幕后真正发生的事情(如果没有另外配置的话)是当一个 pod 拿到锁时,其他 pod 也会尝试获取它,但他们不能,所以他们被迫等待一个while(可配置,但默认为 4 分钟)与锁配置的次数相同(默认为 3 次)。在此之后,如果我无法获取它并且仍有未决的更改要应用,Mongock 将抛出 MongockException,这应该意味着 JVM 启动失败(Spring 中默认发生的情况)。

这在 Kubernetes 中很好,因为它确保它会重新启动 pods。 所以现在,假设 pods 再次启动并且 changeLogs/changeSets 已经应用,pods 成功启动,因为它们甚至不需要获取锁,因为没有要应用的挂起更改.

MongoDB 没有事务支持和 Spring

等框架的潜在问题

现在,假设锁和互斥是明确的,我想指出一个需要通过 changeLog/changeSet 设计来缓解的潜在问题。

如果您在 Kubernetes 等具有 pod 初始化时间的环境中,则此问题适用,您的迁移需要比该初始化时间更长的时间,并且在 pod 变为 ready/health 之前执行 Mongock 进程(并且这是它的条件)。最后一个条件是非常需要的,因为它确保应用程序 运行 具有正确版本的数据。

在这种情况下,假设 Pod 启动了 Mongock 进程。在 Kubernetes 初始化时间之后,该过程仍未完成,但 Kubernetes 突然停止了 JVM。这意味着一些 changeSets 被成功执行,其他一些甚至没有启动(没问题,它们将在下一次尝试中处理),但是一个 changeSet 被部分执行并标记为未完成。这是潜在的问题。下一次 Mongock 运行s,它将看到 changeSet 处于待处理状态,并且将从头开始执行它。如果您没有相应地设计 changeLogs/changeSets,您可能会遇到一些意想不到的结果,因为该 changeSet 涵盖的数据处理的某些部分已经发生,并且还会再次发生。

这需要以某种方式缓解。借助交易等机制,changeLog/changeSet 设计考虑到这一点,或者两者兼而有之。

Mongock 目前提供了“全有或全无”的事务,但它并没有多大帮助,因为它每次都会从头开始重试,很可能会陷入无限循环。下一个版本 5 将提供每个 ChangeLogs 和 changeSets 的事务,再加上良好的组织,是解决这个问题的正确方法。

同时,可以通过以下方式解决此问题 this design suggestions

只是为了跟进...Mongock 的锁定机制适用于副本。为了解决“long-运行ning 脚本”问题,我们将 运行 来自 Kubernetes initContainer 的 Mongock 脚本。 K8s 将等待 initContainers 完成,然后再启动 pod 的主要服务容器。 对于交易,我们将遵循上面的建议使我们的脚本具有幂等性。