MongoDB 不专业指北(十八):创建多个副本进程实现高可用服务 (下)

·  阅读 433
MongoDB 不专业指北(十八):创建多个副本进程实现高可用服务 (下)

本文翻译自 MongoDB 官网文档:docs.mongodb.com/v4.4/replic…,略有修改并附加了示例。

前言

上篇MongoDB 不专业指北(十七):创建多个mongod副本集实现高可用服务 (上)介绍了MongoDB 复制集的基础概念和示例,通过主节点写、从节点同步,多节点读的方式可以提供高可用的数据服务。同时 MongoDB 的主节点宕机后,从节点会自动选举新的主节点,从而恢复读写服务。本篇来介绍复制集的读操作。

读偏好选(Read Preference)择

默认情况下,客户端从主节点读取数据。但是就像我们上一篇演示的那样,可以指定客户端访问从节点读取。

mongo --port <port> --host <host | IP>
复制代码

image.png

但是,由于存在主从异步复制数据,客户端在从节点读取的数据可能会和主节点的不一样。对于多文档的事务操作中,如果包含了读操作,那么必须要从主节点读取数据。对于同一个事务来说,不可以跨节点操作。读偏好操作有三种模式: 主节点:所有读操作都使用当前的主节点,这是默认的模式。如果主节点宕机,读操作讲抛出异常。主节点模式与使用标签集(tag sets)或最大有效延迟时间(maxStalenessSeconds)的读操作不兼容。

主节点优先:这种模式下,在大多数情况下,都是从主节点读取数据。然而,如果主节点不可用的时候,读操作会在满足最大有效延迟时间及标签集后切换到从节点读取数据。当设置为主节点优先模式且设置了最大有效延迟时间,当发生主节点不可用时,客户端会通过最后一次写入数据的时间评估各个从节点的时效性。然后选择一个低于或等于最大有效延迟时间的从节点读取数据。

当读偏好设置包含了标签集,主节点不可用时,客户端视图查找匹配标签的从节点(基于标签规则按需匹配直到找到一个)。如果找到了匹配的从节点,客户端则从匹配的节点中最临近的组中随机选择一个从节点读取数据。但如果没有找到的话,那就会产生一个错误。

当同时包含了最大有效延迟时间和标签集时,客户端会优先通过时效性来选择哪个从节点。使用主节点优先的读操作可能会返回滞后的数据。因此使用最大有效延迟时间选项可以避免读取过旧的数据。

从节点:客户端只从从节点读取数据。如果没有可用的从节点,读操作会产生错误或异常。大部分副本集会至少有一个从节点,但是也可能存在不可用的从节点(全部从节点宕机)。如果这种模式设置了最大有效延迟时间,客户端会评估主节点写入从节点的时效性,然后选择延时低于或等于最大有效延迟时间的节点。如果没有主节点,将会选择从写入时间最近的从节点读取数据。

当从节点模式包括了标签集时,客户端会视图找到匹配标签的从节点读取数据。如果找到了匹配的从节点,客户端则从匹配的节点中最临近的组中随机选择一个从节点读取数据。但如果没有找到的话,那就会产生一个错误。同样的,从节点模式也可能读取到滞后的数据,可以设置最大有效时间延迟来避免读取过旧的数据。

从节点优先:这种模式下,大多数情况下都是从从节点读取数据。但如果这个复制集只有一个主节点,就会从主节点读取数据。如果有多个可用的从节点,那选择哪个从节点和从节点模式一样。

最近模式(nearest):这种模式下,客户端不区分主从节点,而是会从网络延迟落在可接受的延迟范围内的节点读取数据。这种模式可以以最低的网络延迟中选择节点,因此默认情况下不会对数据的时效性做出偏好选择。

如果设置了最大有效延迟时间,客户端会评估主节点写入从节点的时效性,存在主节点的时候,客户端会评估会主节点写入各个从节点的时效性;如果没有主节点,则调出最近写入的节点。然后从这些节点中过滤掉那些超过最大有效延迟时间的节点,再从剩下的节点中(不区分主从节点)挑选网络时延低于可接受范围的节点读取数据。

如果指定了标签集,客户端会试图找到匹配标签集的节点,然而从最临近的组中选举一个节点读取数据。如果同时指定了最大有效延迟时间和标签集,客户端会先使用时效性过滤节点,接着使用标签集过滤。对于剩下的 mongod 实例,客户端随机地从满足网络时延的节点中挑选一个读取数据。

同样的,使用这种模式也可能读取到过期数据,可以通过设置最大有效延迟时间来降低这种情况发生的机率。

配置读偏好

如果使用了 MongoDB 的驱动,可以从驱动的 API 中配置读偏好模式。当使用 mongo 客户端连接时,可以使用 cursor.readPref()和 Mongo.setReadRef()来设置。

db.getMongo().setReadPref(
   "secondary",		//从节点模式
   [	
      { "datacenter": "B" },    // 先匹配数据中心标签
      { "region": "West"},      // 如果没找到,就从区域标签匹配
      { }                       // 如果没找到,就使用空文档匹配所有候选节点
   ]
)
复制代码
db.collection.find({ }).readPref(
   "secondary",
   [
      { "datacenter": "B" },    // 先匹配数据中心标签
      { "region": "West"},      
      { }
   ]
)
复制代码

总结

可以看到,MongoDB 的复制集针对读操作配置了多种模式。其中标签模式更是适用于分布式存储的情况。这也是 MongoDB 相对其他数据库的一些优点,在集群部署上提供了很多可选的方式进行配置,以提高可用性和降低数据延迟。

分类:
后端