0

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

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

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

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

还是我需要启用事务(或其他配置)?

4

2 回答 2

5

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

简短的回答

默认情况下,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 的事务,再加上良好的组织,是解决此问题的正确解决方案。

同时这个问题可以通过遵循这个设计建议来解决。

于 2021-02-23T09:53:40.020 回答
1

只是跟进...... Mongock 的锁定机制适用于副本。为了解决“长时间运行的脚本”问题,我们将从 Kubernetes 运行我们的 Mongock 脚本initContainer。K8s 在启动 pod 的主要服务容器之前会等待initContainers 完成。对于交易,我们将遵循上述使我们的脚本具有幂等性的建议。

于 2021-03-31T00:40:44.750 回答