>>>>>>> cn
翻译或纠错本页面

在复制集上执行Quorum投票读取

3.2 新版功能.

概览

当读取复制集的主节点读取数据的时候,根据使用read conern [#edge-cases-2-primaries]_的级别,有可能读到的数据是过期的或者没有持久化的数据。使用read conern的级别为:readconcern:“local”`时客户端可能在数据:term:`durable`之前就被读取,这就是说在这些数据为了实现容错而传播到足够多的复制集成员上之前就会被读到。当read concern级别为:readconcern:“majority”`将保证持久化读取,但是有可能读到的是过期的数据,这些数据有可能已经被写操作覆盖掉了。

本教程将概要的介绍如何使用:method:`db.collection.findAndModify()`方法读取不是过期的数据并且不能被回滚的过程。为了实现我们的目的,这个过程将使用通过:ref:`write concern <write-concern>`关键字来使用method:`~db.collection.findAndModify()`方法来修改一个文档中虚拟的字段。这个过程特别的还需要:

  • :method:`db.collection.findAndModify()`使用*精确*匹配查询和一个:doc:`unique index </core/index-unique>`**必须存在**的数据来满足查询。

  • :method:`~db.collection.findAndModify()`必须实际修改一个文档,也就是说结果一定会修改这个文档。

  • ~db.collection.findAndModify()`必须使用write concern:writeconcern:`{ w: "majority" }

重要

“Quorum投票读取”过程会耗用比简单的使用:readconcern:`“majority”`的read concern操作更多的资源,因为它将导致写入延迟而不是读取延迟。这种技术应该只使用在过期数据无法容忍的场景下。

前提

本教程读取一个名为``products``的集合。使用如下操作初始化这个集合。

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
   }
] )

本教程中文档的集合有一个名为``_dummy_field``的虚拟字段,这个字段会使用:method:`db.collection.findAndModify()`进行自增。如果字段不存在:method:`db.collection.findAndModify()`操作将在文档中增加这个字段。这个字段的目的是确保:method:`db.collection.findAndModify()`结果文档的修改是在一个操作中完成的。

步骤

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.

This tutorial will use an exact match on the sku field. As such, create a unique index on the sku field.

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

Use findAndModify to read committed data.

Use the db.collection.findAndModify() method to make a trivial update to the document you want to read and return the modified document. A write concern of { w: "majority" } is required. 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. 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.

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". 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.

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.

[1]

在:ref:some circumstances <edge-cases>`中,复制集中的两个节点可能会在*极短*的时间内都认为自己是主节点,但是至多他们中的一个可以使用writeconcern:`{ w: “majority” } <”majority”>`完成写操作的write concern。完成:writeconcern:`{ w: “majority” } <”majority”>`写入操作的节点将是主节点,而另外一个还没有意识到自己已经降级的节点,通常降级的原因是由于:term:`network partition。当这种情况发生后连接到这个降级节点的客户端会发现这些数据已经不是最新的了,尽管请求使用了读偏好:readmode:primary,新写入这个前主节点的数据最终将回滚。