以下文档解释了各种读取偏好模式的常见使用案例,并通过反证概述了何时不应更改读取偏好的默认值 primary。
读取偏好模式
读取偏好模式 | 说明 |
|---|---|
默认模式。从当前副本集主节点 (primary node in the replica set)读取的操作。 包含读取操作的事务必须使用读取偏好(read preference) | |
操作从主节点 (primary node in the replica set)读取(如果可用)。如果不是,则从符合条件的从从节点(secondary node from replica set)读取。 | |
操作从副本集符合条件的从从节点(secondary node from replica set)读取数据。如果没有符合条件的可用从节点,则操作将从主节点 (primary node in the replica set)节点读取。 | |
操作从网络延迟在延迟窗口内且符合条件的成员中读取,无论它是主节点 (primary node in the replica set)还是从节点(secondary node from replica set)。 |
对于所有模式,当节点响应客户端的定期监控检查时,该节点可用,这些检查确认该节点可通过网络访问并且能够响应请求。
对于除
primary之外的所有模式,如果成员满足读取偏好的 maxStalenessSeconds 选项和任何指定的标签集列表,则该成员符合资格。
重要
读取偏好模式不保证操作成功。可用性和资格决定了客户端会考虑哪些节点,但所选节点仍可拒绝操作,例如当节点处于负载状态时。
使用非主节点读取偏好的指示
以下是使用非 primary 读取偏好模式的常见用例:
在故障转移期间保持可用性。
如果您希望应用程序在正常情况下从主节点读取数据,但允许在主节点不可用时从从节点读取过时数据,请使用
primaryPreferred。
非主节点偏好的反证
通常请勿使用 secondary 和 secondaryPreferred 为读取提供额外容量,因为:
副本的所有成员都具有大致相等的写入流量;因此,从节点将以与主节点大致相同的速率提供读取服务。
复制是异步的,成功的写入操作与其复制到从节点之间存在一定程度的延迟。从从节点读取可能会返回过时的数据;从不同的从节点读取可能会导致非单调读取。
注意
客户端可以使用客户端会话和因果一致性保证来确保单调读取。
如果副本集中的任何节点变得不可用,则将读取操作分发到从节点可能会影响可用性,因为其余节点必须能够处理所有应用程序请求。
分片通过在一组机器上分配读写操作来增加读写容量,通常是增加容量的更好策略。
请参阅服务器选择算法,进一步了解读取偏好的内部应用。
最大限度提高一致性
为避免过时读取,请使用 primary 读取偏好和 "majority" readConcern。如果主节点不可用,例如在选举期间或当大多数副本集不可访问时,使用 primary 读取偏好的读取操作会产生错误或抛出异常。
在某些情况下,副本集可能暂时有两个主节点;但是,只有一个主节点能够通过 "majority" 写关注确认写入。
部分网络分区可能将主节点 (
Pold) 分隔为包含少数节点的分区,而分区的另一端则包含多数节点。拥有多数节点的分区将选举一个新的主节点 (Pnew),但在短时间内,旧的主节点 (Pold) 可能仍会继续提供读取和写入服务,因为它尚未检测到它只能看到副本集中的少数节点。在此期间,如果旧的主节点 (Pold) 仍然作为主节点对客户端可见,则从该主节点读取的数据可能反映的是过时数据。主节点(
P旧)可能会变得无响应,从而触发选举,可以选举新的主节点(P新)以提供读取和写入服务。如果无响应的主节点(P旧)再次开始响应,则两个主节点将在短时间内可见。当P旧降级时,这个短时间就会结束。但是,在该短时间内,客户端可能会从旧的主节点P旧中读取,可能会提供过时的数据。
要提高一致性,可以禁用自动故障转移;但禁用自动故障转移会牺牲可用性。
可用性最大化
要尽可能允许读取操作,请使用 primaryPreferred。当有主节点 (primary node in the replica set)时,您将获得一致的读取 [1],但如果没有主节点 (primary node in the replica set),您仍然可以查询从节点。但是,在使用此读取模式时,请考虑 secondary 与 secondaryPreferred 中描述的情况。
| [1] | 在某些情况下,副本集中的两个节点可能会暂时认为自己是主节点,但最多只能有一个在 |
尽量减少延迟
To always read from a low-latency node, use nearest. The driver or mongos will read from the nearest member and those no more than 15 milliseconds [2] further away than the nearest member.
nearest 不保证一致性。如果距离应用程序服务器最近的成员是具有一定复制延迟的从节点,则查询可能返回过时数据。nearest 仅反映网络距离,不反映 I/O 或 CPU 负载。
| [2] | 此阈值可配置。请参阅 localPingThresholdMs,了解 mongos;或参阅您的驱动程序文档,了解适当的配置。 |
从按地理位置分布的节点进行查询
如果副本集的成员分布在不同地域,您可以基于此创建反映实例位置的副本标签,然后将应用程序配置为查询附近的成员。
例如,如果“东部”和“西部”数据中心的成员标记为 {'dc': 'east'} 和 {'dc': 'west'},则东部数据中心的应用程序服务器可以使用以下读取偏好从附近的成员读取数据:
db.collection.find().readPref('nearest', [ { 'dc': 'east' } ])虽然 nearest 会优先选择网络延迟较低的成员,但包含该标记可以让选择更加可预测。
secondary vs secondaryPreferred
For specific dedicated queries (e.g. ETL, reporting), you may shift the read load from the primary by using the secondary read preference mode. For this use case, the secondary mode is preferable to the secondaryPreferred mode because secondaryPreferred risks the following situation: if all secondaries are unavailable and your replica set has enough arbiters [3] to prevent the primary from stepping down, then the primary will receive all traffic from the clients. If the primary is unable to handle this load, the queries will compete with the writes. For this reason, use read preference secondary to distribute these specific dedicated queries instead of secondaryPreferred.
| [3] | 一般来说,避免在副本集中部署仲裁节点,而使用奇数个数据承载节点。如果必须部署仲裁节点,请避免为每个副本集部署多个仲裁节点。 |