代码改变世界

MongoDB Read Concern

2024-11-28 19:55  abce  阅读(13)  评论(0编辑  收藏  举报

1.读关注(read concern)

通过 readConcern 选项,可以控制从副本集和分片集群读取数据的一致性和隔离属性。

 

通过有效使用写关注和读关注,可以适当调整一致性和可用性保证的级别,如等待更强的一致性保证,或放宽一致性要求以提供更高的可用性。

 

副本集和分片群集支持设置全局默认读关注。未指定显式读关注的操作会继承全局默认读关注设置。

可以在不同的范围上设置读关注:

1.1.默认的读/写关注

查看默认的读/写关注设置

> db.runCommand({ getDefaultRWConcern: 1 })
{
        "defaultReadConcern" : {
                "level" : "local"
        },
        "defaultWriteConcern" : {
                "w" : "majority",
                "wtimeout" : 0
        },
        "defaultWriteConcernSource" : "implicit",
        "defaultReadConcernSource" : "implicit",
        "localUpdateWallClockTime" : ISODate("2024-11-19T05:34:44.866Z"),
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1731994477, 1),
                "signature" : {
                        "hash" : BinData(0,"M/mzGWY1a6bzw0s9oOXDkCXBx/8="),
                        "keyId" : NumberLong("7375822993269719041")
                }
        },
        "operationTime" : Timestamp(1731994477, 1)
}

 

设置默认的读/写关注级别

语法:

db.adminCommand(
  {
    setDefaultRWConcern : 1,
    defaultReadConcern: { <read concern> },
    defaultWriteConcern: { <write concern> },
    writeConcern: { <write concern> },    ##可选项
    comment: <any>    ##可选项
  }
)

比如:

db.adminCommand({
  "setDefaultRWConcern" : 1,
  "defaultReadConcern" : { "level" : "majority" }
})

db.adminCommand({
  "setDefaultRWConcern" : 1,
  "defaultWriteConcern" : {
    "w" : 2
  }
})

 

重置默认的读写关注

db.adminCommand( {
   "setDefaultRWConcern" : 1,
   "defaultReadConcern" : {}
} )

db.adminCommand( {
   "setDefaultRWConcern" : 1,
   "defaultWriteConcern" : {}
} )

 

如果不是多文档事务,可以在支持读关注的命令或方法中,直接指定一个读关注级别:

readConcern: { level: <level> }

比如在mongosh中的db.collection.find()中执行读关注级别:

db.collection.find().readConcern(<level>)

 

对于多文档事务,在事务级别设置读关注,不是在单个操作级别设置。事务中的所有操作都使用事务级别的读关注,任何设置在集合、数据库级别的读关注都被忽略。如果事务级别的读关注是显式设置的,客户端级别的读关注也会被忽略。

 

不要显式的设置单独操作的读关注。

 

可以在事务启动的时候设置读关注:

·对于多文档事务,可以设置的读关注级别有:local、majority、snapshot

·多文档事务中的写操作,可以支持事务级别的读关注

·在事务中可以创建集合和索引。如果显式创建集合和索引,事务必须使用 local 读关注。如果是隐式创建集合,只可以使用事务可用的读关注。

 

如果在事务启动的时候没有指定读关注级别,事务使用会话级别的读关注,如果没有指定会话级别的读关注,使用客户端读关注。

 

因果一致(Causally Consistent)会话和可用的读关注

对于因果一致性会话中的操作,可使用 "local"、"majority "和 "snapshot "级别。不过,要保证因果一致性,必须使用 "majority"。

 

1.2支持读关注的操作

以下操作支持读关注:

要为事务中的操作设置读关注,应在事务级别而不是单个操作级别设置读关注。不要为事务中的单个操作显式设置读关注。

命令/方法

local

available

majority

snapshot

linearizable

count

Y

Y

Y

 

Y

distinct

Y

Y

Y

Y

Y

find

Y

Y

Y

Y

Y

db.collection.find() via

cursor.readConcern()

Y

Y

Y

 

Y

getMore

Y

     

Y

aggregate

db.collection.aggregate()

Y

Y

Y

Y

Y

Session.startTransaction()

Y

 

Y

Y

 

 

 

以下写操作如果是多文档事务内的,也可以接受读关注:

命令

local

available

majority

snapshot

linearizable

delete

db.collection.deleteOne()

db.collection.deleteMany()

db.collection.remove()

Y

   

Y

 

findAndModify

db.collection.findAndModify()

db.collection.findOneAndDelete()

db.collection.findOneAndReplace()

db.collection.findOneAndUpdate()

Y

   

Y

 

insert

db.collection.insertOne()

db.collection.insertMany()

Y

   

Y

 

update

db.collection.updateOne()

db.collection.updateMany()

db.collection.replaceOne()

Y

   

Y

 

create

db.createCollection()

(Requires fCV 4.4 or greater)

Y

       

createIndexes

db.collection.createIndex()

db.collection.createIndexes()

(Requires fCV 4.4 or greater)

Y

       

 

local数据库不支持读关注!

 

1.3.读关注级别

MonogDB 提供的读关注包含五个级别,分别是:local、available、majority、linearizable、snapshot。

Local

查询从实例返回数据,但不保证数据已写入副本集的大多数成员(比如,可能回滚)。默认为针对主副本和辅助副本的读取。

无论是否有因果一致的会话和事务,都可以使用"Local"读关注。

 

无论是 primary,还是 secondary,local 都是默认的读关注级别。

 

local 读关注与事务

可以在事务级别设置读关注,而不是在单个操作级别。

可以在事务中创建集合和索引。如果显式创建集合或索引,事务必须使用"local"读关注。如果隐式创建集合,则可以使用事务可用的任何读关注。

在副本集上,即使事务使用了"local"读关注,也可能会观察到更强的读隔离。

 

available

查询从实例返回数据,但不保证数据已写入副本集的大多数成员(比如,可能回滚)。

available 读关注不可用于因果一致会话和事务。

 

对于分片集群,"available"读关注可提供各种读关注中延迟最低的读。不过,这也是以牺牲一致性为代价的,因为从分片集群读取时,"available"读关注可能会返回孤儿文档。为避免从分片集合读取时返回孤儿文档的风险,请使用不同的读关注,如"local"读关注。

 

majority

查询会返回大多数副本集成员已确认的数据。即使出现故障,读操作返回的文档也是持久的。

为满足 "majority"读要求,副本集成员会从其内存中的数据视图返回多数承诺点的数据。因此,"majority"读关注点的性能成本与其他读关注相当。

无论是否有因果一致的会话和事务,都可以使用"majority"读关注。

 

要使用 "majority" 读关注级别,副本集必须使用 WiredTiger 存储引擎。

 

对于多文档事务中的操作,只有当事务提交时使用" majority"写关注时,"majority"读关注才会提供保证。否则,"majority"读关注不会对事务中读取的数据提供任何保证。

 

linearizable

查询返回的数据反映了在读取操作开始前完成的所有成功的多数节点确认写入。查询可能会等待并发执行的写操作传播到大多数副本集成员后才返回结果。

如果大多数副本集成员在读取操作后崩溃并重新启动,如果 writeConcernMajorityJournalDefault 设置为默认状态true,则读取操作返回的文档将是持久的。

 

当 writeConcernMajorityJournalDefault 设置为false 时,MongoDB 在确认写入之前不会等待w: "majority" 写入写入磁盘日志。因此,"majority"写操作可能会在给定副本集中的多数节点发生瞬时丢失(如崩溃和重启)的情况下回滚。

 

linearizable 读关注不可用于因果一致会话和事务。

 

只能为主节点上的读操作指定 linearizable 的读关注。

不能将 $out 或 $merge 阶段与读关注 "linearizable" 结合使用。也就是说,如果为db.collection.aggregate() 指定了"linearizable"读关注,就不能在管道中包含这两个阶段。

 

要求:

只有在读取操作指定了能唯一识别单个文档的查询过滤器时,才适用 linearizable 读关注保证。此外,如果不满足以下条件,linearizable 读关注可能无法从一致快照中读取,导致无法返回与筛选器匹配的文档:

·查询使用不可变字段作为查询的搜索键。例如,在_id字段上搜索或使用 $natural

·并发更新不会改变查询的搜索键。

·搜索键有唯一索引,查询使用该索引。

 

如果满足前述任何条件,查询将从一致快照中读取,返回唯一匹配的文档。

 

maxTimeMS 可确保操作不会无限期阻塞,而会在无法满足读取条件时返回错误。

 

snapshot

使用 "snapshot" 读取功能的查询会返回最近某个特定时间点在分片上出现的 majority 提交数据。只有当事务以 "majority" 写关注提交时,"snapshot" 读关注才能提供保证。

 

如果事务不是因果一致会话的一部分,那么在事务提交时使用"majority"写关注,就能保证事务操作是从多数提交数据的快照中读取的。

 

如果事务是因果关系一致的会话的一部分,则在事务提交时,如果写入带有 "majority" 写关注,则保证事务操作是从多数提交的数据快照中读取的,该数据快照与事务启动前的操作具有因果一致性。

 

适用于:

·多文档事务中的所有读取操作,读关注点设置在事务级别。

·多文档事务之外的以下方法:find、aggregate、distinct