Read Preference
在本页面
读取首选项描述 MongoDBClient 端如何将读取操作路由到replica set的成员。
默认情况下,应用程序将其读取操作定向到replica set中的primary成员(即读取首选项模式“主要”)。但是,Client 端可以指定读取首选项,以将读取操作发送到辅助对象。
读取首选项由读取偏好模式以及可选的tag set和maxStalenessSeconds组成。
Important
指定读取首选项时请多加注意:primary以外的模式可能会返回陈旧数据,因为使用asynchronous replication时,辅助数据库中的数据可能无法反映最新的写入操作。 [1]
Note
读取首选项不会影响数据的可见性;即,Client 端可以在确认或传播到大多数副本集成员之前查看写入结果:
-
不管write concern为何,使用"local"或"available"的其他 Client 端 readConcern 都可以在向发布 Client 端确认写入操作之前看到写入操作的结果。
-
使用"local"或"available" readConcern 的 Client 端可以读取随后可能是rolled back的数据。
Use Cases
Indications
以下是使用非primary读取首选项模式的常见用例:
- 正在运行不影响前端应用程序的系统操作。
- 为地理分布的应用程序提供本地读取。
如果您在多个数据中心中都有应用程序服务器,则可以考虑拥有地理上分散的副本集并使用非主要或nearest读取首选项。这允许 Client 端从最低延迟成员中读取,而不是始终从主要成员中读取。
- 在故障转移期间保持可用性。
如果您希望应用程序在正常情况下从主数据库读取数据,请使用primaryPreferred,但在主数据库不可用时允许从辅助数据库进行过时的读取。这为故障转移期间的应用程序提供了“只读模式”。
Counter-Indications
通常,不要使用secondary和secondaryPreferred为读取提供额外的容量,因为:
-
副本的所有成员具有大致相等的写入流量;结果,辅助服务器将以与主服务器大致相同的速率读取数据。
-
复制是异步的,成功的写操作及其复制到辅助副本之间存在一定的延迟。从辅助节点读取可能会返回陈旧数据;来自不同次级的读取可能会导致非单调读取。
在 3.6 版中进行了更改:从 MongoDB 3.6 开始,Client 端可以使用Client 会议和因果一致性保证来确保单调读取。
- 如果集合的任何成员变得不可用,则将读取操作分配给次要对象可能会损害可用性,因为集合的其余成员将需要能够处理所有应用程序请求。
Sharding通过在一组计算机之间分布读写操作来增加读写容量,并且通常是增加容量的更好策略。
有关读取首选项的内部应用的更多信息,请参见服务器选择算法。
读取首选项模式
Important
除primary以外的所有读取首选项模式都可能返回陈旧数据,因为secondaries从主数据库复制操作会有一定的延迟。 [1]如果您选择使用非primary模式,请确保您的应用程序可以忍受过时的数据。
MongoDB drivers支持五种读取首选项模式。
读取首选项模式 | Description |
---|---|
primary | 默认模式。所有操作均从当前副本集primary读取。 |
primaryPreferred | 在大多数情况下,操作是从primary读取的,但如果不可用,则操作是从secondary成员读取的。 |
secondary | 所有操作均从副本集的secondary个成员读取。 |
secondaryPreferred | 在大多数情况下,操作是从secondary成员读取的,但是如果没有secondary成员可用,则操作是从primary读取的。 |
nearest | 无论成员的类型如何,操作都会从replica set成员中读取网络延迟最少的操作。 |
Tag Set
如果一个或多个副本集成员与tags关联,则可以在读取首选项中指定一个标记集(标记规范文档的数组)以定位这些成员。
要configure一个带有标签的成员,请将members[n].tags设置为包含标签名称和值对的文档。标签的值必须是字符串。
{ "<tag1>": "<string1>", "<tag2>": "<string2>",... }
然后,您可以在读取首选项中包含一个标记集,以定位标记的成员。标签集是标签规范文档的数组,其中每个标签规范文档都包含一个或多个标签/值对。
[ { "<tag1>": "<string1>", "<tag2>": "<string2>",... }, ... ]
为了查找副本集成员,MongoDB 会连续尝试每个文档,直到找到匹配项。有关详情,请参见标签匹配 Sequences。
例如,如果辅助成员具有以下members[n].tags:
{ "region": "South", "datacenter": "A" }
然后,以下标记集可以将读取操作定向到上述辅助节点(或具有相同标记的其他成员):
[ { "region": "South", "datacenter": "A" }, { } ] // Find members with both tag values. If none are found, read from any eligible member.
[ { "region": "South" }, { "datacenter": "A" }, { } ] // Find members with the specified region tag. Only if not found, then find members with the specified datacenter tag. If none are found, read from any eligible member.
[ { "datacenter": "A" }, { "region": "South" }, { } ] // Find members with the specified datacenter tag. Only if not found, then find members with the specified region tag. If none are found, read from any eligible member.
[ { "region": "South" }, { } ] // Find members with the specified region tag value. If none are found, read from any eligible member.
[ { "datacenter": "A" }, { } ] // Find members with the specified datacenter tag value. If none are found, read from any eligible member.
[ { } ] // Find any eligible member.
标签匹配 Sequences
如果标记集列出了多个文档,则 MongoDB 会连续尝试每个文档,直到找到匹配项为止。找到匹配项后,该标签说明文档将用于查找所有合格的匹配成员,而其余标签说明文档将被忽略。如果没有成员与任何标签规范文档匹配,则读取操作返回错误。
Tip
为了避免在没有成员符合任何标签规范的情况下出错,您可以添加一个空文档{ }
作为标签集的最后一个元素,以从任何符合条件的成员中读取。
例如,考虑以下带有三个标签规范文档的标签集:
[ { "region": "South", "datacenter": "A" }, { "rack": "rack-1" }, { } ]
首先,MongoDB 尝试查找同时标记为"region": "South"
和"datacenter": "A"
的成员。
{ "region": "South", "datacenter": "A" }
-
如果找到成员,则不会考虑其余的标签规范文档。相反,MongoDB 使用此标签规范文档来查找所有符合条件的成员。
-
另外,MongoDB 尝试查找具有第二个文档中指定的标签的成员
{ "rack": "rack-1" }
-
如果发现某个成员已标记,则不考虑其余的标记规范文档。相反,MongoDB 使用此标签规范文档来查找所有符合条件的成员。
- 否则,考虑第三份文件。
{ }
空文档匹配任何符合条件的成员。
标记设置和读取首选项模式
标签与模式primary不兼容,并且通常仅在集合的selecting和secondary成员进行读取操作时适用。但是,nearest读取模式与标签集组合时,会选择具有最低网络延迟的匹配成员。该成员可以是主要成员或次要成员。
Mode | Notes |
---|---|
primaryPreferred | 指定的标签集仅在选择符合条件的次级标签时适用。 |
secondary | 指定的标记集始终适用。 |
secondaryPreferred | 指定的标签集仅在选择符合条件的次级标签时适用。 |
nearest | 指定的标记集适用于选择主要还是合格的次要对象。 |
有关modes和标记集之间的交互的信息,请参考特定的阅读首选项模式文档。
有关配置标签集的信息,请参见配置副本集标记集教程。
配置读取首选项
使用 MongoDB 驱动程序时,可以在连接到副本集或分片群集时指定读取首选项。例如,请参阅connection string。您还可以在更详细的级别上指定读取首选项。有关详细信息,请参见驱动程序的api documentation。
对于给定的读取首选项,MongoDB 驱动程序使用相同的成员选择逻辑。
使用mongo
Shell 程序时,请参见cursor.readPref()和Mongo.setReadPref()。例如:
db.collection.find({}).readPref( "secondary", [ { "region": "South" } ] )
maxStalenessSeconds
3.4 版的新功能。
由于网络拥塞,磁盘吞吐量低,运行时间长等原因,副本集成员可能会滞后于primary。读取首选项maxStalenessSeconds
选项使您可以为从secondaries读取指定最大复制滞后或“陈旧性”。当辅助节点的估计陈旧度超过maxStalenessSeconds
时,Client 端将停止将其用于读取操作。
Important
maxStalenessSeconds
读取首选项选项适用于从辅助目录读取的应用程序,并且希望避免从辅助目录中进行读取,而该辅助目录在复制主目录的写入操作时落后太多。例如,辅助节点可能由于其自身与主要节点之间的网络中断而停止复制。在这种情况下,Client 端应停止从辅助服务器读取数据,直到 Management 员解决中断并辅助服务器追赶为止。
要使用maxStalenessSeconds
,部署中的所有 MongoDB 实例必须使用 MongoDB 3.4 或更高版本。如果任何实例在 MongoDB 的早期版本上,则驱动程序或mongos将引发错误。
您可以使用以下读取首选项模式指定maxStalenessSeconds
:
最大过期时间与模式primary不兼容,并且仅在集合selecting和secondary的成员进行读取操作时适用。
当选择服务器以maxStalenessSeconds
进行读取操作时,Client 端会通过比较辅助节点的上次写入与主节点的最后一次写入来估计每个辅助节点的陈旧程度。然后,Client 端会将读取操作定向到辅助计算机,该辅助计算机的估计延迟小于或等于maxStalenessSeconds
。
如果没有主服务器,Client 端将使用具有最新写入操作的辅助服务器进行比较。
默认情况下,没有最大的陈旧性,并且在选择将读取操作定向到何处时,Client 端不会考虑辅助节点的延迟。
您必须将maxStalenessSeconds
值指定为 90 秒或更长时间:指定较小的maxStalenessSeconds
值将引发错误。Client 通过定期检查每个副本集成员的最新写入日期来估计次要节点的过时状态。由于这些检查很少,因此陈旧性估计值很粗糙。因此,Client 端不能将maxStalenessSeconds
值强制设置为少于 90 秒。
[1] | (1,2)在some circumstances中,副本集中的两个节点可能短暂地认为它们是主要节点,但是最多只能有{ w: "majority" }个写入问题来完成写入。可以完成{ w: "majority" }写入的节点是当前的主节点,另一个节点是以前的主节点,通常由于network partition而尚未识别其降级。发生这种情况时,尽管请求了读取首选项primary,但连接到先前主服务器的 Client 端仍可能会观察到过时的数据,并且对先前主服务器的新写入最终将回滚。 |