我一直在使用MongooseJS的revisionKey
一段时间 - 默认情况下它包含文档的__v
字段。我理解修订号的目的是什么,通常是在更新时。
我最近和一位朋友谈过“矢量时钟”的想法,我提到MongoDB和MongooseJS有这个__v
字段。当时,听起来这可能是一个矢量时钟。但是我已经阅读了一些关于矢量时钟的内容,现在我不确定。
所以我想知道:MongooseJS的versionKey
属性和它默认生成的__v
字段是否可以被视为矢量时钟?是的,还是不,为什么?
答案 0 :(得分:4)
在我看来,你提到的versionKey
不能被视为矢量时钟。你可以认为它是Lamport timestamp(或Lamport Clock)。
让我们全面了解我们正在管理的内容:
Lamport时间戳和向量时钟都是用于定义分布式系统中发生的不同事件的因果关系顺序的算法。换句话说,两种算法都用于同步不具有共同参考的事件。
Lamport时间戳算法为每个进程使用一个计数器(在问题的情况下,我们可以为每个文档说一个计数器)。该算法的工作原理如下:
1)每次在过程中发生事件(通信,修改等)时,计数器都会预先增量。
2)当进程向其他进程发送消息时,它会将计数器的值附加到已发送的消息。
3)当进程接收到任何类型的通信时,计数器会递增(如果接收的值小于或等于当前计数器值),或者如果计数器值大于当前值,则将计数器值设置为接收值。
以下是应用于三个过程的算法示例:
Lamport时间戳为所有进程提供单个计数器,允许确定哪个进程的最后版本(或mongoose情况下的文档。
有了这个说法,我们可以得出结论,versionKey
是一种机制,可以让我们知道我们正在处理的版本是当前版本还是我们已经过时了。
正如Aaron Heckmann在他的博客文章中指出的关于Mongoose的版本控制(Mongoose v3 part 1 :: Versioning:
在版本3中,文档现在具有
increment()
方法,该方法手动强制增加文档版本。只要对数组上的操作可能改变数组元素位置,就会在内部使用它。
因此,如果您尝试修改作为数组的子文档并且您正在更改该数组的顺序,则开箱即用只会使用versionKey
。
另一方面,Aaron声明increment()
方法手动强制增加文档版本。如果您实现了Lamport算法,则可以使用此方法来增加符合算法第一规则的版本。在这种情况下,您将使用 versionKey 作为Lamport时间戳。
所以(这是你问题的实际答案)。为什么versionKey
不能被视为矢量时钟:
versionKey
是单个值,因此不能将其视为矢量时钟。 DynamoDB使用向量时钟来处理版本here is an interesting reading about it 以下是该论文的摘录:
Dynamo使用矢量时钟来捕获同一对象的不同版本之间的因果关系。矢量时钟实际上是(节点,计数器)对的列表。一个矢量时钟与每个对象的每个版本相关联。通过检查它们的向量时钟,可以确定对象的两个版本是在并行分支上还是具有因果排序。如果第一个对象的时钟上的计数器小于或等于第二个时钟中的所有节点,则第一个是第二个时钟的祖先,可能会被遗忘。否则,这两项更改将被视为冲突,需要进行对帐。
所以我不会考虑versionKey
矢量时钟,我会认为它是一个Lamport时间戳,有一些解决方法。
答案 1 :(得分:2)
据我了解,versionKey
值仅由save
和findOneAndUpdate
函数递增。由于versionKey
值在执行update
时没有增加,或者使用mongo cli完成手动更新,我相信这将无法通过测试来定义矢量时钟。