MongooseJS "versionKey"(__v 字段)是 "vector clock" 吗?

Is the MongooseJS "versionKey" (__v field) a "vector clock"?

我使用 MongooseJS 的 revisionKey 已有一段时间了 - 默认情况下,它包含在文档中的 __v 字段。我明白修订号的用途是什么,一般什么时候更新。

我最近和一个朋友谈论 "vector clock" 的想法,我提到 MongoDB 和 MongooseJS 有这个 __v 字段。当时,这听起来像是一个矢量时钟。但是在阅读了一些有关矢量时钟的内容后,现在我不确定了。

所以我想知道: MongooseJS 的 versionKey 属性,以及它默认生成的 __v 字段是否可以被视为矢量时钟?是或否,为什么?

据我了解,versionKey 值仅通过 savefindOneAndUpdate 函数递增。由于在执行 update 时或使用 mongo cli 完成手动更新时 versionKey 值不会增加,我相信这将无法通过向量定义测试时钟。

在我看来,你提到的 versionKey 不能被视为矢量时钟。不过,您可以将其视为 Lamport timestamp(或 Lamport 时钟)。

让我们全面了解一下我们正在管理的内容:

Lamport 时间戳和矢量时钟都是用于定义分布式系统中发生的不同事件的因果顺序的算法。换句话说,两种算法都用于同步没有共同参考的事件。

Lamport 时间戳算法为每个进程使用一个计数器(在这个问题的情况下,我们可以说每个文档都有一个计数器)。该算法的工作原理如下:

1) 每次进程内发生事件(通信、修改等)时,计数器都会预递增。

2) 当一个进程向其他进程发送消息时,它将计数器的值附加到发送的消息中。

3) 当进程接收到任何类型的通信时,计数器递增(如果接收到的值小于或等于当前计数器值),或者如果计数器值大于接收到的值,则将计数器值设置为接收到的值当前值。

下面是应用于三个进程的算法示例:

Lamport 时间戳为所有进程提供了一个计数器,可以确定哪个是进程的最新版本(或 mongoose 案例中的文档。

说到这里,我们可以得出结论,versionKey 是一种机制,可以让我们知道我们正在处理的版本是当前版本还是已过时。

作为Aaron Heckmann points out in his blog post about versioning in Mongoose (Mongoose v3 part 1 :: Versioning:

In version 3, documents now have an increment() method which manually forces incrementation of the document version. This is also used internally whenever an operation on an array potentially alters array element position.

因此,开箱即用,如果您尝试修改数组形式的子文档并且您正在更改该数组的顺序,那么您将仅使用 versionKey

另一方面,Aaron 指出 increment() 方法手动强制增加文档版本。如果您实现了 Lamport 算法,则可以使用此方法来增加满足算法第一条规则的版本。在这种情况下,您将使用 versionKey 作为 Lamport 时间戳。

所以(这里是您问题的实际答案)。为什么 versionKey 不能被认为是矢量时钟:

  • 向量时钟为环境中涉及的每个进程使用一个计数器。在文档的情况下,矢量时钟应该用于保存同一文档的多个版本。这允许您在两个不同的文档具有相同版本号时解决冲突。由于 versionKey 是单个值,因此不能将其视为矢量时钟。 DynamoDB 使用矢量时钟来处理版本,here is an interesting reading about it

这是论文的摘录:

Dynamo uses vector clocks in order to capture causality between different versions of the same object. A vector clock is effectively a list of (node, counter) pairs. One vector clock is associated with every version of every object. One can determine whether two versions of an object are on parallel branches or have a causal ordering, by examine their vector clocks. If the counters on the first object’s clock are less-than-or-equal to all of the nodes in the second clock, then the first is an ancestor of the second and can be forgotten. Otherwise, the two changes are considered to be in conflict and require reconciliation.

所以我不会将 versionKey 视为矢量时钟,而是将其视为具有一些变通方法的 Lamport 时间戳。