本页内容
本页描述了MongDB如何在副本集成员中路由读指令。
默认情况下,应用程序直接将读取指令发送副本集的 primary成员。
重要:在指定读取首选项时要小心:除了 primary,其他的成员可能会返回过时的数据,因为其他成员是在异步线程从
primary
同步数据的,secondary成员有可能无法同步到最新数据。
注意:读取首选项不会对数据的可见性造成影响,例如:数据在数据集的大部分成员里传播或者已达前,该数据的写入对于客户端来说是可见的。
不管 write concern参数的值是什么,只要readConcern的参数是
"local"
或者"available"
,那么,服务器成员在数据被客户端确认以前就会收到结果。对readConcern 字段使用了
"local"
or"available"
的成员,可以读取随后就会回滚的数据。
Use Cases
下面是一些常用的读取首选项(针对 non-primary
成员):
- 在不影响前端的情况下运行服务器操作
注意:读取首选项对直接链接到Mongd的单例是无效的。然而,为了对直接连接到副本集的secondary成员执行读取指令,你必须设置一个读取首选项,例如 secondary.
为地理分布式应用环境提供本地读取。
如果你的服务器是分布在几个数据中心的,你可能需要考虑一下使用geographically distributed replica set并且使用一个non primary或者nearest
之类的读取首选项。这允许客户端直接从最低延迟的成员里读取数据,而不应该一直从primary读取。在故障转移期间维护可用性。
如果你想你的应用在正常情况下直接从primary 成员里读取数据,请使用primaryPreferred
。但如此一来,当primary 不可用的时候,就会从secondaries 读取可能并不是最新的数据。在故障转移期间,为你的程序提供 “只读模式”。
一般情况下,不用使用 secondary
and secondaryPreferred
为读取提供额外支持,因为:
- 副本集里的所有成员的流量相当于写入的流量;因为secondaries的读取速度跟primary的写入速度是差不多的。
- 复制是在异步线程进行的,并且写入成功后到secondaries将数据复制过来会有一定的延迟。在secondary成员读取数据可能会返回旧数据;从不同的secondary成员之间读取可能会返回不同的数据。
在3.6版本以后,可以使用 Client Sessions来确保不同secondary之间读取的数据是一致的。
如果副本集里的某些成员挂了,那么分布式读取可能会造成效率下降,因为剩下的成员可能不一定能把请求处理得过来。
查询带有 balancer的分片集合,secondaries 可能会返回残缺的数据(丢失或者重复),因为块迁徙可能不完整或者被终止。
分片会把读和写操作分发给不同的机器来提高操作效率,这是一个高效性策略。
读取首选项模式
重要:因为secondaries从primary复制数据会存在一定的延迟,使用secondaries返回的可能是旧数据。如果你使用了 non-
primary
mode.请确保你的应用程序可以容忍旧数据。
MongDB驱动支持5种类型的读取模式:
读取模式 | 描述 |
---|---|
primary |
默认模式. 所有读取操作都从 primary读取. |
primaryPreferred |
大多数情况下都从 primary 读取,但是如果primary不可用的话, 会从 secondary 成员读取. |
secondary |
所有读取操作都从 secondary 成员读取. |
secondaryPreferred |
大多数情况下从 secondary 读取,但如果所有secondary 成员都不可用的话,读取指令会发送到primary. |
nearest |
忽略成员的身份,从延迟最低的成员读取. |
读取模式的语法在这: specific to the driver and to the idioms of the host language.
使用mongos直接连接到分片集群的客户端也可以使用读取模式。当连接到分片集群里的副本集时,mongos遵循指定的读取模式。
在shell里,游标方法 readPref()
提供了对读取首选项的访问。
maxStalenessSeconds
3.4以后才新增的概念。
在 secondaries读取的时候,由于网络不畅通、低磁盘吞吐量、某个操作长时间占用等情况下, secondaries的数据可能会落后于primary。读取首选项的maxStalenessSeconds 选项可以让你指定一个最大复制延迟。当服务器预计某个secondary成员的延迟超过maxStalenessSeconds,则服务器不会通过该secondary成员来执行读取操作。
重要:maxStalenessSeconds 选项意在优化从secondaries成员的读取操作,并且尽量保持secondaries成员和primary成员的数据一致性。例如,一个secondary成员由于停机而导致无法从primary成员同步数据,这样的情况下,读取操作就不应被该secondary成员处理,直至到管理员解决问题以后,该secondary成员继续进行数据同步。
MongDB版本必须为3.4以上才能使用maxStalenessSeconds选项。如果使用了早期的版本,MongDB会报错。
你可以参照以下文档来指定maxStalenessSeconds参数:
maxStalenessSeconds参数只能用于处理读取操作的secondary成员,primary是不兼容该参数的。
当某台带有maxStalenessSeconds参数的服务器处理读取操作的时候,MongDB决定读取操作在哪个secondary成员上执行是依据:每一个secondary成员的最后写入时间跟primary的写入时间进行对比,时间小于或者约等于maxStalenessSeconds的secondary。
如果没有primary成员,MongDB会使用最近写入过的secondary成员来执行读取操作。
默认情况下,没有maxStalenessSeconds,并且在指定读取操作的时候不会考虑secondary的情况。
你必须将maxStalenessSeconds的时间指定为90秒或更长:指定一个小于90s的值会报错。服务器在通过定期检查每一个成员的最后写入时间来估计数据的新鲜程度。由于不是频繁进行该检查,所以数据的新鲜程度估计是粗略的。然而,你就是不能将maxStalenessSeconds指定为90s以下。(译者备注:你吹咩?)
标签设置
设置标签将允许你将写入操作指定委派给副本集里的某个成员。
自定义读取首选项和write concerns评估标签是不一样的。当你指定由某个成员处理该读取操作时,成员会通过tag的值来决定是否接受该请求。 Write concerns 是忽略tag的值的,只会检查该值是否是唯一的。
同样的,primary成员也是不兼容tag的。通常情况是指定某个secondary成员来处理读取操作才用得上tag。但是,在 nearest
模式下,使用tag set合并时,会使用网络延迟最低的成员来处理,该成员可以是primary或者secondary。
基于读取首选项的模式和tag sets,所有的接口都会使用相同的 member selection logic来为读取操作选择成员。