读取偏好使用案例
在此页面上
以下文档解释了各种 读取偏好模式的常见使用案例,并通过 反证概述了何时不应将读取偏好更改为默认值 primary
。
读取偏好模式
读取偏好模式 | 说明 |
---|---|
在大多数情况下,操作将从主节点读取,但如果主节点不可用,则操作将从从节点成员读取。 读取偏好 | |
操作通常从副本集的从节点成员读取数据。如果副本集只有一个主节点成员,并且没有其他成员,则操作将从主节点成员读取数据。 读取偏好 | |
根据指定的延迟阈值,从符合条件的随机副本集成员读取操作,无论该成员是主节点成员还是从节点成员。 该操作在计算延迟时会考虑以下因素:
|
使用非主节点读取偏好的指示
以下是使用非 primary
读取偏好模式的常见用例:
运行不影响前端应用程序的系统操作。
为按地理位置分布的应用程序提供本地读取。
如果应用程序服务器位于多个数据中心,则可以考虑地理分布的副本集或使用非主节点或
nearest
读取偏好。这样客户端可以从延迟最低的节点读取,无需总是从主节点读取。在故障转移期间保持可用性。
如果您希望应用程序在正常情况下从主节点读取数据,但允许在主节点不可用时从从节点读取过时数据,请使用
primaryPreferred
。
非主节点偏好的反证
通常请勿使用 secondary
和 secondaryPreferred
为读取提供额外容量,因为:
副本的所有成员都具有大致相等的写入流量;因此,从节点将以与主节点大致相同的速率提供读取服务。
复制是异步的,成功的写入操作与其复制到从节点之间存在一定程度的延迟。从从节点读取可能会返回过时的数据;从不同的从节点读取可能会导致非单调读取。
注意
客户端可以使用客户端会话和因果一致性保证来确保单调读取。
如果副本集中的任何节点变得不可用,则将读取操作分发到从节点可能会影响可用性,因为其余节点必须能够处理所有应用程序请求。
分片通过在一组机器上分配读写操作来增加读写容量,通常是增加容量的更好策略。
请参阅服务器选择算法,进一步了解读取偏好的内部应用。
最大限度提高一致性
为避免过时读取,请使用 primary
读取偏好和 "majority"
readConcern
。如果主节点不可用,例如在选举期间或当大多数副本集不可访问时,使用 primary
读取偏好的读取操作会产生错误或抛出异常。
在某些情况下,副本集可能暂时有两个主节点;但是,只有一个主节点能够通过 "majority"
写关注确认写入。
部分网络分区可能将主节点 (
P
old) 分隔为包含少数节点的分区,而分区的另一端则包含多数节点。拥有多数节点的分区将选举一个新的主节点 (P
new),但在短时间内,旧的主节点 (P
old) 可能仍会继续提供读取和写入服务,因为它尚未检测到它只能看到副本集中的少数节点。在此期间,如果旧的主节点 (P
old) 仍然作为主节点对客户端可见,则从该主节点读取的数据可能反映的是过时数据。主节点(
P
旧)可能会变得无响应,从而触发选举,可以选举新的主节点(P
新)以提供读取和写入服务。如果无响应的主节点(P
旧)再次开始响应,则两个主节点将在短时间内可见。当P
旧降级时,这个短时间就会结束。但是,在该短时间内,客户端可能会从旧的主节点P
旧中读取,可能会提供过时的数据。
要提高一致性,可以禁用自动故障转移;但禁用自动故障转移会牺牲可用性。
可用性最大化
要尽可能允许读取操作,请使用primaryPreferred
。 当有主节点时,您将获得一致的读取[ 1 ] ,但如果没有主节点,您仍然可以查询从节点。 但是,在使用此读取模式时,请考虑secondary
与secondaryPreferred
中描述的情况。
[1] | 在某些情况下,副本集中的两个节点可能会暂时认为自己是主节点,但最多只能有一个在 { w:
"majority" } 写关注时完成写入。可以完成 { w: "majority" } 写入操作的节点是当前主节点,另一个节点是尚未识别其降级(通常是由于网络分区)的前主节点。发生这种情况时,尽管请求了读取偏好 primary ,但连接到前主节点的客户端可能会观察到过时数据,并且对前主节点的新写入操作最终将回滚。 |
尽量减少延迟
要始终从低延迟节点读取数据,请使用 nearest
。驱动程序或 mongos
将从最近的节点以及距离最近节点不超过 15 毫秒 [2] 的节点读取。
nearest
不保证一致性。如果距离应用程序服务器最近的成员是具有一定复制延迟的从节点,则查询可能返回过时数据。nearest
仅反映网络距离,不反映 I/O 或 CPU 负载。
[2] | 此阈值可配置。请参阅 localPingThresholdMs ,了解 mongos ;或参阅您的驱动程序文档,了解适当的配置。 |
从按地理位置分布的节点进行查询
如果副本集的成员分布在不同地域,您可以基于此创建反映实例位置的副本标签,然后将应用程序配置为查询附近的成员。
例如,如果“东部”和“西部”数据中心的成员标记为 {'dc': 'east'}
和 {'dc': 'west'}
,则东部数据中心的应用程序服务器可以使用以下读取偏好从附近的成员读取数据:
db.collection.find().readPref('nearest', [ { 'dc': 'east' } ])
虽然 nearest
会优先选择网络延迟较低的成员,但包含该标记可以让选择更加可预测。
secondary
vs secondaryPreferred
对于特定的专用查询(例如ETL、报告),您可以使用 secondary
读取偏好模式将读取负载从主节点转移。对于这个使用案例,secondary
模式比 secondaryPreferred
模式更可取,因为 secondaryPreferred
可能会出现以下情况:如果所有从节点都不可用并且您的副本集有足够的仲裁节点 [3] 以防止主节点让位,那么主节点将接收来自客户端的所有流量。如果主节点无法处理此负载,查询将与写入操作竞争。出于这个原因,请使用读取偏好 secondary
来分配这些特定的专用查询,而不要使用 secondaryPreferred
。
[3] | 一般来说,避免在副本集中部署仲裁节点,而使用奇数个数据承载节点。如果必须部署仲裁节点,请避免为每个副本集部署多个仲裁节点。 |