Mongock看起来很有前途。我们希望在kubernetes服务中使用它,该服务有多个并行运行的副本。
我们希望在部署我们的服务时,第一个副本将获取mongockLock,并且它的所有ChangeLog/ChangeSet将在其他副本尝试运行它们之前完成。
我们只有一个mongodb实例在kubernetes环境中运行,我们希望mongock ChangeLogs/ChangeSets只执行一次。
mongockLock是否保证只有一个副本将运行ChangeLog/ChangeSet完成?
或者我是否需要启用事务(或其他一些配置)?
发布于 2021-02-23 17:53:40
我会先提供简短的答案,然后再提供冗长的答案。我建议你也读一读长篇,以便正确理解。
简短的回答
默认情况下,Mongock保证ChangeLogs/changeSets一次只由一个pod运行。那个拥有锁的人。
长长的答案
幕后真正发生的事情(如果没有配置)是,当pod获得锁时,其他pod也会尝试获取它,但它们无法获取,因此它们被迫等待一段时间(可配置,但默认情况下为4分钟)与配置锁的次数(默认情况下为3次)一样多。在此之后,如果我无法获取它,并且仍有未完成的更改需要应用,Mongock将抛出一个MongockException,这应该意味着JVM启动失败(在Spring中默认发生的情况)。
这在Kubernetes中是很好的,因为它可以确保它将重新启动pod。所以现在,假设pod再次启动,并且changeLogs/changeSets已经被应用,pod成功启动,因为它们甚至不需要获取锁,因为没有挂起的更改要应用。
没有事务支持和Spring等框架的MongoDB的潜在问题
现在,假设锁和互斥是明确的,我想指出一个需要通过changeLog/changeSet设计缓解的潜在问题。
如果你在Kubernetes这样的环境中,有一个pod初始化时间,你的迁移花费的时间比初始化时间要长,Mongock进程在pod变为ready/health(这是它的一个条件)之前执行Mongock进程。最后一个条件是非常需要的,因为它可以确保应用程序使用正确版本的数据运行。
在这种情况下,假设Pod启动了Mongock进程。在Kubernetes初始化时间之后,这个过程仍然没有结束,但是Kubernetes突然停止了JVM。这意味着一些changeSets被成功执行,另一些甚至没有启动(没问题,它们将在下一次尝试中被处理),但有一个changeSet被部分执行并被标记为未完成。这是一个潜在的问题。下一次Mongock运行时,它将看到changeSet挂起,并将从头开始执行它。如果您没有相应地设计您的changeLogs/ changeSet,您可能会遇到一些意想不到的结果,因为该changeSet涵盖的数据处理的某些部分已经发生,并且还会再次发生。
这需要以某种方式加以缓解。要么借助事务等机制,要么使用changeLog/changeSet设计来考虑这一点,或者两者兼而有之。
Mongock目前为事务提供了“全有或全无”,但它并没有真正起到多大作用,因为它每次都会从头开始重试,可能会以无限循环告终。下一个版本5将提供每个ChangeLogs和changeSets的事务,再加上良好的组织,这是解决此问题的正确解决方案。
同时,这个问题可以通过以下this design suggestions来解决。
发布于 2021-03-31 08:40:45
只是想跟进一下...Mongock的锁定机制可以很好地处理复制品。为了解决“长时间运行的脚本”问题,我们将从Kubernetes initContainer运行我们的Mongock脚本。在启动pod的主服务容器之前,K8s将等待initContainer完成。对于事务,我们将遵循上面的建议,使我们的脚本成为幂等的。
https://stackoverflow.com/questions/66324374
复制相似问题