我将先提供简短的答案,然后再提供长答案。我建议您也阅读长篇,以便正确理解它。
简短的回答
默认情况下,Mongock 保证 ChangeLogs/changeSets 一次只能由一个 pod 运行。拥有锁的人。
长答案
幕后真正发生的事情(如果没有另外配置的话)是,当一个 pod 获得锁时,其他人也会尝试获取它,但他们不能,所以他们被迫等待一段时间(可配置,但默认为 4 分钟)与配置的锁一样多(默认为 3 次)。在此之后,如果我无法获取它并且仍有待应用的更改,Mongock 将抛出一个 MongockException,这应该意味着 JVM 启动失败(在 Spring 中默认情况下会发生什么)。
这在 Kubernetes 中很好,因为它确保它会重新启动 pod。所以现在,假设 Pod 再次启动并且 changeLogs/changeSets 已经应用,Pod 启动成功,因为它们甚至不需要获取锁,因为没有待应用的更改。
没有事务支持和 Spring 等框架的 MongoDB 的潜在问题
现在,假设锁定和互斥是明确的,我想指出一个潜在的问题,需要通过 changeLog/changeSet 设计来缓解。
如果您处于 Kubernetes 等具有 pod 初始化时间的环境中,则此问题适用,您的迁移需要比初始化时间更长的时间,并且在 pod 准备好/健康之前执行 Mongock 进程(这是它的一个条件)。最后一个条件是非常需要的,因为它可以确保应用程序使用正确版本的数据运行。
在这种情况下,想象一下 Pod 启动了 Mongock 进程。过了 Kubernetes 的初始化时间,这个过程还没有结束,但是 Kubernetes 突然停止了 JVM。这意味着一些changeSets被成功执行,一些甚至没有启动(没问题,它们将在下一次尝试中处理),但是一个changeSet被部分执行并标记为未完成。这是潜在的问题。下次运行 Mongock 时,它会看到 changeSet 处于待处理状态,并且会从头开始执行它。如果您没有相应地设计您的 changeLogs/changeSets,您可能会遇到一些意想不到的结果,因为该 changeSet 所涵盖的数据过程的某些部分已经发生并且会再次发生。
这一点,需要以某种方式加以缓解。要么借助事务等机制,要么借助将这一点考虑在内的 changeLog/changeSet 设计,或两者兼而有之。
Mongock 目前提供了“全有或全无”的事务,但它并没有太大帮助,因为它每次都会从头开始重试,并且可能最终陷入无限循环。下一个版本 5 将提供每个 ChangeLogs 和 changeSets 的事务,再加上良好的组织,是解决此问题的正确解决方案。
同时这个问题可以通过遵循这个设计建议来解决。