Linearizable Reads via findAndModify通过findAndModify进行线性化读取

Overview概述

When reading from a replica set, it is possible to read data that is stale (i.e. may not reflect all writes that have occurred prior to the read operation) or not durable (i.e. the state of the data may reflect a write that has not been acknowledged by a majority or the replica set members and thus could be rolled back), depending on the read concern used.从副本集读取时,可能会读取过时(即,可能不会反映读取操作之前发生的所有写入)或不持久(即,数据的状态可能会反映大多数或副本集成员尚未确认的写入,因此可能会回滚),具体取决于所使用的读取问题。

Starting in version 3.4, MongoDB introduces "linearizable" read concern that returns durable data that is not stale. 从3.4版开始,MongoDB引入了"linearizable"读关注点,它返回的是不过时的持久数据。Linearizable read concern guarantees only apply if read operations specify a query filter that uniquely identifies a single document.仅当读取操作指定了唯一标识单个文档的查询筛选器时,读取关注点保证才适用。

This tutorial outlines an alternative procedure, one using db.collection.findAndModify() to read data that is not stale and cannot be rolled back, for deployments using MongoDB 3.2. 本教程概述了另一个过程,对于使用MongoDB 3.2的部署,使用db.collection.findAndModify()读取未过期且无法回滚的数据。For MongoDB 3.4, although the outlined procedure can be applied, see "linearizable" read concern instead.对于MongoDB 3.4,尽管可以应用概述的程序,但请参见"linearizable"阅读关注点。

Linearizable Reads via findAndModify通过findAndModify进行线性化读取

This procedure uses db.collection.findAndModify() to read data that is not stale and cannot be rolled back. 此过程使用db.collection.findAndModify()读取未过期且无法回滚的数据。To do so, the procedure uses the findAndModify() method with a write concern to modify a dummy field in a document. 为此,该过程使用findAndModify()方法和写关注点来修改文档中的虚拟字段。Specifically, the procedure requires that:具体而言,该程序要求:

Important

The “quorum read” procedure has a substantial cost over simply using a read concern of "majority" because it incurs write latency rather than read latency. “仲裁读取”过程比简单地使用"majority"的读取关注点有很大的成本,因为它会导致写入延迟而不是读取延迟。This technique should only be used if staleness is absolutely intolerable.只有当陈腐绝对无法忍受时,才应使用这种方法。

Prerequisites先决条件

This tutorial reads from a collection named products. 本教程阅读名为products的集合。Initialize the collection using the following operation.使用以下操作初始化集合。

db.products.insert( [
   {
     _id: 1,
     sku: "xyz123",
     description: "hats",
     available: [ { quantity: 25, size: "S" }, { quantity: 50, size: "M" } ],
     _dummy_field: 0
   },
   {
     _id: 2,
     sku: "abc123",
     description: "socks",
     available: [ { quantity: 10, size: "L" } ],
     _dummy_field: 0
   },
   {
     _id: 3,
     sku: "ijk123",
     description: "t-shirts",
     available: [ { quantity: 30, size: "M" }, { quantity: 5, size: "L" } ],
     _dummy_field: 0
   }
] )

The documents in this collection contain a dummy field named _dummy_field that will be incremented by the db.collection.findAndModify() in the tutorial. 此集合中的文档包含一个名为_dummy_field的虚拟字段,该字段将由教程中的db.collection.findAndModify()递增。If the field does not exist, the db.collection.findAndModify() operation will add the field to the document. 如果该字段不存在,db.collection.findAndModify()操作会将该字段添加到文档中。The purpose of the field is to ensure that the db.collection.findAndModify() results in a modification to the document.该字段的用途是确保db.collection.findAndModify()会导致对文档的修改。

Procedure程序

1

Create a unique index.创建一个唯一的索引。

Create a unique index on the fields that will be used to specify an exact match in the db.collection.findAndModify() operation.在字段上创建一个唯一索引,用于在db.collection.findAndModify()操作中指定精确匹配。

This tutorial will use an exact match on the sku field. 本教程将在sku字段中使用精确匹配。As such, create a unique index on the sku field.因此,在sku字段上创建一个唯一索引。

db.products.createIndex( { sku: 1 }, { unique: true } )
2

Use findAndModify to read committed data.使用findAndModify读取提交的数据。

Use the db.collection.findAndModify() method to make a trivial update to the document you want to read and return the modified document. 使用db.collection.findAndModify()方法对要读取的文档进行简单的更新,并返回修改后的文档。A write concern of { w: "majority" } is required. 需要{ w: "majority" }的写入关注。To specify the document to read, you must use an exact match query that is supported by a unique index.要指定要读取的文档,必须使用唯一索引支持的精确匹配查询。

The following findAndModify() operation specifies an exact match on the uniquely indexed field sku and increments the field named _dummy_field in the matching document. 以下findAndModify()操作指定唯一索引字段sku的精确匹配,并在匹配文档中增加名为_dummy_field的字段。While not necessary, the write concern for this command also includes a wtimeout value of 5000 milliseconds to prevent the operation from blocking forever if the write cannot propagate to a majority of voting members.虽然没有必要,但该命令的写稿关注还包括一个5000毫秒的wtimeout值,以防止在写操作无法传播到大多数投票成员时操作永远阻塞。

var updatedDocument = db.products.findAndModify(
   {
     query: { sku: "abc123" },
     update: { $inc: { _dummy_field: 1 } },
     new: true,
     writeConcern: { w: "majority", wtimeout: 5000 }
   }
);

Even in situations where two nodes in the replica set believe that they are the primary, only one will be able to complete the write with w: "majority". 即使在副本集中的两个节点认为自己是主节点的情况下,也只有一个节点能够用w: "majority"完成写操作。As such, the findAndModify() method with "majority" write concern will be successful only when the client has connected to the true primary to perform the operation.因此,只有当客户端连接到真正的主服务器以执行操作时,具有"majority"写关注点的findAndModify()方法才会成功。

Since the quorum read procedure only increments a dummy field in the document, you can safely repeat invocations of findAndModify(), adjusting the wtimeout as necessary.由于quorum read过程只会增加文档中的一个伪字段,因此可以安全地重复findAndModify()的调用,并根据需要调整wtimeout