想法

mongodb之(7)mongodb副本集

2020-01-04  本文已影响0人  桥头放牛娃

MongoDB 中的副本集是一组mongod进程,它们维护相同的数据集。副本集提供冗余和高可用性,并且是所有生产部署的基础。通过在不同数据库服务器上提供多个数据副本,复制集可以保证对一定数量的数据库服务断开级别容错。

在某些场景下,clients可以通过将读操作发送到复制集的不同服务器来提高读取并发量。同时,在不同数据中心维护数据副本可以增加分布式应用程序中数据的本地性和可用性。

1、副本集成员

Mongodb中的副本集是一组mongo的进程,其为系统提高冗余和高可用性。副本集中存在不同角色的节点,他们各自拥有特殊的作用。副本集主要包含主节点和副节点及仲裁者。

1.1、主节点

主节点是副本集中唯一接受写操作的节点。客户端对主节点进行写操作时,主节点会将对应操作记录在oplog中。而副节点会同步oplog并将操作应用于本地数据集。

写操作同步处理如下:

写操作.png

副本集的所有成员都可以接受读取操作,但默认情况下,副节点会将读操作定向到主节点,可更改阅读偏好来更改读取行为。副本集最多只能包含一个主节点,若主节点不可用,会通过选举来确定新的主节点。

1.2、副节点

副节点主要同步主节点的操作,维护主节点的数据副本。为同步数据,副节点会将主节点的操作日志异步地在本地数据上重放,从而达到数据同步的目的,副本集可包含多个副节点。

主节点与副节点oplog同步如图:

oplog同步.png

客户端无法向副节点写入数据,但可以从副节点读取数据。当主节点不可用时,副节点同过选举将某个副节点升级为主节点。

1.2.1、优先级为0的副节点

优先级为0的副节点不会触发选举操作,也不会被选举成为主节点。优先级为0的节点可对写关注进行确认,对写关注为大多数的操作,优先级为0的节点必须为投票节点,即members[n].votes必须大于0。非投票的节点不能对大多数的写关注操作进行确认。除以上限制,优先级为0的节点同其他副节点相同,保存数据副本并接受读操作,并参与选举。

对于多数据中心的副本集,将某个些节点优先级设置为0,防止其在选举中的成为主节点,使其保持为副节点或作为冷备用节点。

优先级为0的节点可以成为备用节点,当副本集中某个节点不可用时,可直接替换相应节点。在大部分场景中,无需设置优先级为0的节点。但当副本集部署在有差异的硬件上,或是地理分布的数据中心时,优先级为0的配置保证了只有某些节点会成为主节点。

1.2.2、隐藏节点

隐藏节点包含了主节点的数据备份,但其对客户端应用是不可见的。隐藏节点适用于与其他成员拥有不同负载模式的节点。隐藏节点必须为优先级为0的节点,其不会成为主节点,db.isMaster()方法不会显示隐藏节点。但隐藏节点进行选举。

客户端无法配置读偏好来分发读操作到隐藏节点。因此,隐藏节点除了接收基本的操作日志外,无任何其他操作。隐藏节点适合应用于专用的任务如数据报告、数据备份等,延迟节点应该为隐藏节点。

隐藏节点可以进行投票,若下线可投票的隐藏节点,在下线前需要确认副本集大多数节点时可用的。

隐藏节点可以对w:n的写操作进行应答,对带w:"majority"的写操作,隐藏节点必须为可投票节点才会对写关注应答。非投票节点无法对写关注应答。

1.2.3、延迟节点

延迟节点保持主节点的数据拷贝,但其数据与主节点有一定的延迟。因延迟节点保持的是某个时间主节点的数据快照,故当系统故障或操作失误等导致数据破坏时,可通过延迟节点对副本集数据进行恢复。

延迟节点的优先级必须为0,以保证延迟节点不会成为主节点。

延迟节点可以为隐藏节点,可阻止客户端读取延迟节点中的数据。

延迟节点以固定的延迟拷贝主节点的oplog,当使用延迟节点时需考虑以下问题:延迟时间需要大于等于期望的故障恢复窗口,在这个时间窗口中产生的oplog日志量不能大于oplog的容量,否则oplog会将旧的操作覆盖,而导致延迟同步错误。延迟节点的写关注特性同隐藏节点一致。

在分片模式下,当平衡器开启时,延迟节点的特性会被限制。因延迟节点会延迟同步数据块,若在延迟窗口期有任何的块迁移,将导致将数据恢复到延迟节点是无效的。

延迟节点配置示例:

{ "_id" : 1, "host" : localhost:27017, "priority" : 0, "slaveDelay" : 60, "hidden" : true }

1.3、仲裁者

仲裁者无数据集的副本,不能成为主节点。仲裁者只在选举过程中投票,不会同步主节点数据,也不会被选举为主节点,其投票权重为固定的1。故其保证了选举稳定性,但不会增加复制数据的额外开销。仲裁者的优先级为固定的0.

副本集中有仲裁者的架构:

仲裁者.png

2、副本集oplog

oplog是一个设置了容量上限的的集合,其中保存主节点所有的更改操作的滚动记录。当客户端修改数据集时,主节点会将修改操作记录在oplog集合中,然后副节点会同步oplog并在本地集合应用这些操作。所有副本集节点都在local.oplog.rs集合中保存oplog的副本,这允许他们维护数据库的当前state。所有副本集节点都会向其他节点发送心跳,所有副节点都可以import来自其他节点的oplog条目。oplog中的每个操作都是幂等的,即无论对副节点的数据集应用多少次oplog操作,都会产生相同的结果。

2.1、oplog大小

对于 Unix 和 Windows 系统,默认的 oplog 大小取决于存储引擎:

存储引擎 默认的 Oplog 大小 下界 上界
In-Memory 存储引擎 物理 memory 的 5% 50 MB 50 GB
WiredTiger 存储引擎 5%的可用磁盘空间 990 MB 50 GB

对于 64-bit macOS 系统,默认的 oplog 大小是 192 MB 的物理 memory 或可用磁盘空间,具体取决于存储引擎:

存储引擎 默认的 Oplog 大小
In-Memory 存储引擎 192 MB 物理 memory
WiredTiger 存储引擎 192 MB 可用磁盘空间

在mongod创建oplog之前,可通过设置oplogSizeMB选项指定其大小。当副本集启动后,可使用replSetResizeOplog管理命令更改 oplog 大小。 replSetResizeOplog使用户可以动态调整 oplog 的大小,而无需重新启动mongod进程。

2.2、oplog大小策略

对不同的使用场景,oplog所需大小时不同的,用户需根据实际使用场景,对oplog进行配置。

在以下场景需要调大oplog大小:

2.3、oplog状态

通过rs.printReplicationInfo()方法可查看oplog的状态,包括大小和时间范围等。在某些异常情况下,副节点oplog的更新可能会落后于主节点一定时间,使用rs.printSlaveReplicationInfo()可查看副节点落后于主节点的时间。

输出示例如下:

mongoset:PRIMARY> rs.printReplicationInfo() configured oplog size: 1254.787109375MB log length start to end: 453secs (0.13hrs) oplog first event time: Tue Dec 24 2019 20:04:01 GMT+0800 oplog last event time: Tue Dec 24 2019 20:11:34 GMT+0800 now: Tue Dec 24 2019 20:11:45 GMT+0800 mongoset:PRIMARY> mongoset:PRIMARY> rs.printSlaveReplicationInfo() source: localhost:27018 syncedTo: Tue Dec 24 2019 20:09:03 GMT+0800 0 secs (0 hrs) behind the primary source: localhost:27019 syncedTo: Tue Dec 24 2019 20:09:03 GMT+0800 0 secs (0 hrs) behind the primary mongoset:PRIMARY>

在某些情况下,副节点的oplog会落后于主节点,可以在副节点上使用db.getReplicationInfo() 命令来查看oplog同步状态,从而定位是否发生非预料的复制延迟。

3、副本集数据同步

为保证副节点对主节点数据的实时拷贝,副节点需要同步或复制其他节点的数据,mongodb副本集的同步有两种形式:初始全量同步、实时增量复制。

3.1、初始全量同步

初始全量同步将所有数据集从一个节点复制到另一个节点。

同步流程

容错:初始同步具有build-in重试逻辑,可使节点从瞬态网络或操作故障中恢复。

3.2、实时增量复制

副节点在初始同步后不断复制数据。副节点从源节点同步复制oplog,并在异步处理中应用这些操作。副节点可以根据ping时间的更改和其他成员的复制状态变化来更改复制源。副节点投票值为1的节点不能同步投票值为0的节点数据,副节点不会从延迟节点和隐藏节点同步数据。

如果辅助成员成员[n] .buildIndexes设置为true,则它只能从buildIndexes为true的其他成员同步数据。 buildIndexes是false的成员可以从任何其他成员同步,除非有其他同步限制。 buildIndexes默认为true。

3.3、多线程复制

MongoDB 使用多个线程批量应用写操作以提高并发性。 MongoDB 按名称空间(MMAPv1)或文档 id(WiredTiger)对批处理进行分组,并使用不同的线程同时应用每个 group 操作组。 MongoDB总是按照原始的写顺序对给定的文档应用写操作。。

在应用批处理时,MongoDB会阻止所有读取操作。因此,副节点读取将永远不会返回数据,因批处理会改变主节点的数据状态。

使用MMAPv1存储引擎,MongoDB 获取包含受影响数据和索引的 memory 页面,以帮助改进应用 oplog 条目的 performance。这个 pre-fetch 阶段最小化 time MongoDB在应用 oplog 条目时保持写锁定的数量。默认情况下,辅助设备将 pre-fetch 全部索引。 (可选)您可以在_id字段上禁用所有 pre-fetching 或仅 pre-fetch 索引。

4、副本集部署体系

副本集的架构会影响集合的容量和性能。生产环境中可用的标准体系为三个成员的副本集。这些节点提供数据冗余和容错性。

4.1、部署策略

为副本集添加多个成员并不总会增加容错能力,在某些情况下,可将某些成员设置为特殊成员。如隐藏成员、延迟成员等。

在某些高读并发的场景中,可以通过副节点处理读请求来降低负载。为保护数据,需要保存数据副本到至少一个数据中心。如果可以,使用奇数个数据中心,并选择分布式的多个成员作为选举成员,以便当数据中心错误时,其他副本集节点依然有完整的数据拷贝,并能继续为应用提供服务。

可以使用副本集的tag集合来声明特定的副本集成员,在写关注中需要这些特定成员的同步应答,以保证操作副本集同步的稳定性。

4.2、部署模式

4.2.1、一主二副模式

三个节点组成最小副本集。其中,一个主节点,二个副节点,二个副节点都可以被选举为主节点。

一主二副.png

除主数据库外,这些部署始终提供两个完整的数据集副本。这些副本集提供了额外的容错能力和高可用性。如果主服务器不可用,则副本集将选择辅助服务器作为主服务器并继续正常操作。旧主节点在可用时重新加入集合。

4.2.2、一主一副一仲裁者模式

副本集有三个成员,一个主节点;一个副节点,备份主节点数据;一个仲裁者节点,只参与选举,不可成为主节点,也不备份主节点数据,主要为提高系统稳定性。

一主一副一仲裁.png

由于仲裁器不保存数据副本,因此这些部署仅提供一个完整的数据副本。仲裁器需要更少的资源,代价是更有限的冗余和容错。但是,具有主节点,副节点和仲裁节点的部署可确保在主节点或副节点不可用时副本集仍然可用。如果主服务器不可用,则副本集将选择副节点作为主服务器。

4.2.3、副本集分布在多个数据中心

若副本集所有节点都在同一个数据中心,当数据中心故障时,会导致整个副本集不可用。而不同地理位置的数据中心会增加副本集的冗余,并在数据中心发生故障时提供冗余容错功能。

多数据中心.png

5、副本集的高可用

副本集通过选举来保证高可用,当主节点故障时,其他节点会感知,并通过选举方式,在剩余节点中选举出新的主节点,以保证副本集的高可用。

5.1、副本集选举

当主节点在超过设定的时间后依然无响应时,会触发自动失败,其他节点将会启动选举处理并选举出新的主节点。在选举完成之前,副本集不能提供写操作。

影响选举的条件:

5.2、副本集回滚

当主节点在故障之后重新加入副本集时,会在旧的主节点回滚写操作。仅当主节点已接受客户端的写操作,但操作还未同步的副节点,而此时主节点宕机时,才需要回滚。当主节点重新加入副本集时,它会回退或回滚其写入操作,以保持与其他成员的数据一致性。

mongodb试图避免回滚,但回滚是可容忍的。当发生回滚,通常是因为网络分区,副节点无法及时同步旧主节点的操作。

当主节点的写操作已同步到其他副节点,并且此副节点可以连接到可选举副本集的大多数成员,若此时主节点宕机,是不会进行回滚操作的。

5.2.1、收集回滚数据

4.0版本开始,mongodb添加参数createRollbackDataFiles来控制是否在回滚是创建回滚文件。

当发生回滚时,MongoDB 将回滚数据写入一个BSON文件,文件目录为 <dbpath>/rollback/<db>.<collection文件夹中的BSON files。 rollback files 的名称具有以下形式:

removed.<timestamp>.bson

要读取回滚 files 的内容,请使用bsondump。根据其应用程序的内容和知识,管理员可以决定采取的下一步行动。

若回滚操作是集合或文档删除,则此回滚操作不会写入回滚文件中。

5.2.2、避免副本集回滚

对于某个副本集,缺省写关注配置为 {w:1 },即当主数据库的写操作成功即向客户端确定写成功。使用默认写入关注配置时,若主节点的写入操作复制到其他副节点之前宕机,则会导致数据回滚。

为防止已向client回复成功的数据回滚,在所有投票成员启用日志,并使用{w: “majority”}写关注来确保写操作传播到大多数复制集节点,然后再给客户端确认成功。

当writeConcernMajorityJournalDefault设置为false时,MongoDB 不会等待{w:“majority“}节点在需要写入的数据在被写入磁盘之后再给客户端确认。因此,{w:“majority“}写操作可能会在给定副本集中瞬时丢失(崩溃和重启)的事件中回滚,即节点在操作写磁盘之前崩溃,导致内存的瞬时操作日志丢失。

5.2.3、回滚数据的可见性

不论写关注的设置,当其他客户端以“local”或r "available" 级别的读关注读取数据时,其可以读取那些还未对写客户端进行确认的数据。客户端使用“local”或"available" 级别的读关注读取数据会读取那些随后因失败而回滚的数据。

5.2.4、回滚限制

4.2版本后,MongoDB在开始回滚之前等待任何正在进行的索引构建完成。4.0版本后,mongodb不限制回滚数据大小,在早期版本,回滚数据大小不能超过300MB。4.0版本后,回滚时间的限制为默认24小时,可以通过rollbackTimeLimitSecs来修改配置。

6、副本集读写

副本集写关注描述了操作在返回成功之前必须确认写操作的成员(主节点和副节点,但不是仲裁者)的数量。成员只能在收到并成功应用写入后才能确认写入操作。副本集的默认关注级别为只要主节点确认写入即可,用户可设置N的数字,表示只有包含主节点在内的N个节点写入成功,整个写入才算是成功的。

6.1、副本集写关注

写关注是指一定数量的数据节点,在写操作时,这些节点会被同步更新写操作,当这些被同步的节点返回写成功时,整个写操作才算成,并将结果返回给客户端。

副本集的默认写关注配置为{w:1},表示只需要主节点确认写成功即可。用户可以设定一个数字N,当包含主节点在内的N个节点都返回写入成功时,整个写操作才算成功。

当配置{w:"majority"}时表示写操作需要同步给参与投票的大多数。对应分片模式,写关注有效的节点为日志使能的节点,结合{j:true}配置,可以避免写操作的回滚。

写操作通知越多节点,副本集写操作回滚的可能性越小,但比较多的写关注会导致增加写延迟,降低了系统的性能,并且用户必须等待更长的时间以便主节点的写确认。

带写关注的插入示例:

db.products.insert( { item: "envelopes", qty : 100, type: "Clasp" }, { writeConcern: { w: "majority" , wtimeout: 5000 } } )

可以通过在副本集 configuration中设置settings.getLastErrorDefaults设置来修改副本集的默认写入关注。以下命令创建一个 configuration,在返回之前等待写操作在大多数投票成员上完成:

cfg = rs.conf() cfg.settings.getLastErrorDefaults = { w: "majority", wtimeout: 5000 } rs.reconfig(cfg)

如果发出具有特定写入问题的写入操作,则写入操作将使用其自己的写入关注而不是默认值。可以给副本集的成员设置tag标签,并用标签来创建自定义的写入问题。

6.2、客户端读取偏好

读取偏好描述了mongo客户端路由读操作到副本集成员的规则。默认情况下,节点将读取操作重定向到副本集的主节点上。但客户端可以设置读取偏好,将读取操作发送给指定的副节点,读取偏好由读取偏好模式和可选的标签集和maxStalenessSeconds组成。

6.2.1、读偏好模式

MongoDB 支持五种读取偏好模式。

读取偏好模式 描述
节点 默认模式。所有操作都从当前副本集主中读取。
偏好主节点 在大多数情况下,操作从读取,但如果不可用,则从副节点读取操作。
副节点 所有操作都从副本集的副节点中读取。
偏好副节点 在大多数情况下,操作从副节点读取,但如果没有副节点可用,则操作从读取。
最近 无论成员的类型如何,操作都从最小网络延迟的副节点读取。

6.2.2、标签集

如果副本集成员有关联的标签,则可以在读取偏好中指定标记集以定位这些成员。要配置带有标记的成员,请将成员[n] .tags设置为包含标记 name 和 value 对的文档。标签的 value 必须是 string。

{ "<tag1>": "<string1>", "<tag2>": "<string2>",... }

然后,可以在读取偏好中包含标记集以定位标记成员。标记集是标记规范文档的 array,其中每个标记规范文档包含一个或多个 tag/value 对。

[ { "<tag1>": "<string1>", "<tag2>": "<string2>",... }, ... ]

要查找副本集成员,MongoDB 会连续尝试每个文档,直到找到匹配的。

6.2.2、标签匹配顺序

若读偏好中配置了多个标签,mongo会匹配每个标签,直到找到符合的集合。若有符合的标签,则找到对应的副本集成员,而剩余的标签会被忽略。若无副本集成员匹配,则读操作返回错误。为避免读操作错误,可在读偏好的标签集合最后添加{ }作为最后的标签,其会匹配所有的副本集成员,即读取操作会从所有的有效副本集节点中读取。

示例如下:

[ { "region": "South", "datacenter": "A" }, { "rack": "rack-1" }, { } ]

6.2.3、标签集与读偏好模式

标签集与主节点读偏好无法完全兼容,通常标签集与读副节点偏好搭配使用。但在nearest读模式下,当结合标签集偏好时,会选择网络延迟最小的匹配节点,这个节点为主节点或副节点。

| 读取偏好模式 | 说明 |
| 偏好主节点 | 只在选择有效的副节点时,声明的标签偏好才有效 |
| 副节点 | 声明的标签偏好一直有效 |
| 偏好副节点 | 只有选择有效的副节点是,声明的标签偏好才有效 |
| 最近 | 无需选择的有效节点时主节点或副节点,标签都有效 |

6.2.4、配置读取偏好

可以在创建mongo客户端连接时指定全局的读取偏好。在shell下,可使用cursor.readPref()和Mongo.setReadPref()来设置读取偏好。

示例如下:

db.collection.find({}).readPref( "secondary", [ { "region": "South" } ] )

6.3、服务器选择算法

mongo客户端驱动使用服务器选择算法来确定使用副本集的那个成员。

6.3.1、副本集的读偏好

每个读取操作都使用服务器成员的选取算法,此算法受限于读偏好和localThresholdMS配置。MongoDB 3.4 添加maxStalenessSeconds读取首偏好项,其指定副节点可能受到影响且仍有资格进行读取操作的最大复制滞后时间。此选项配置适用于从副节点读取数据的应用,并希望避免从数据远远很暖和落后于主节点的的副节点读取数据。

阅读偏好 择节点
(默认) 驱动程序选择主节点。
次要 该驱动程序汇集了符合条件的辅助成员列表。 maxStalenessSecondstag sets可以进一步限制成员的资格。 如果符合条件的成员列表不为空,则驱动程序确定哪个符合条件的成员是“最近的”(i.e.具有最低平均网络的成员 round-trip-time)并通过添加此“最近”服务器的平均值 round-trip-time 来计算延迟时间窗口和localThresholdMS。驱动程序使用此延迟窗口将符合条件的成员列表减少到属于此窗口的成员。 从这个属于延迟窗口的合格成员列表中,驱动程序随机选择一个符合条件的成员。
最近 驱动程序组装符合条件的成员列表(主要成员和辅助成员)。 maxStalenessSecondstag sets可以进一步限制成员的资格。 如果符合条件的成员列表不为空,则驱动程确定哪个符合条件的成员是“最近的”(i.e.具有最低平均网络的成员 round-trip-time)并通过添加此“最近”服务器的平均值 round-trip-time 来计算延迟时间窗口和localThresholdMS [1]。驱动程序使用此延迟窗口将符合条件的成员列表减少到属于此窗口的成员。 从这个属于延迟窗口的合格成员列表中,驱动程序随机选择一个符合条件的成员。
primaryPreferred 如果主服务器可用,则驱动程序选择主服务器。 否则,服务器选择遵循读取首选项secondary的 process。
secondaryPreferred 在服务器选择 process 之后,对于读取首选项secondary,如果符合条件的辅助成员列表为 non-empty,则驱动程序将选择符合条件的辅助成员。 否则,如果列表为空,则驱动程序选择主要列表。

6.3.2、分片集群的读偏好

如果连接种子列表中有多个mongos实例,则驱动程序确定哪个mongos是“最近的”(i.e.具有最低平均网络的成员 round-trip-time)并通过添加此“最近”的平均 round-trip-time 来计算延迟窗口“mongos实例和localThresholdMS。驱动程序将在延迟窗口内的mongos实例之间随机加载平衡。

对于具有副本集分片的分片群集,mongos在从分片读取时应用读取首选项。服务器选择由阅读偏好和replication.localPingThresholdMs设置控制。

阅读偏好 选择 Process
(默认) mongos选择主要。
次要 mongos汇集了符合条件的辅助成员列表。 maxStalenessSecondstag sets可以进一步限制成员的资格。 如果符合条件的成员列表不为空,则mongos确定哪个符合条件的成员是“最近的”(i.e.具有最低平均网络的成员 round-trip-time)并通过添加此“最近”服务器的平均值 round-trip-time 来计算延迟时间窗口和replication.localPingThresholdMs(或--localThreshold命令 line 选项)。 mongos使用此延迟窗口将符合条件的成员列表减少到属于此窗口的成员。 从这个属于延迟窗口的符合条件的成员列表中,mongos随机选择一个符合条件的成员。
最近 mongos汇集了符合条件的成员列表(主要成员和次要成员)。 maxStalenessSecondstag sets可以进一步限制成员的资格。 如果符合条件的成员列表不为空,mongos确定哪个符合条件的成员是“最近的”(i.e.具有最低平均网络 round-trip-time 的成员)并通过添加此“最近”服务器的平均值 round-trip-time 来计算延迟时间窗口和replication.localPingThresholdMs(或--localThreshold命令 line 选项)[1]mongos使用此延迟窗口将符合条件的成员列表减少到属于此窗口的成员。 从这个属于延迟窗口的符合条件的成员列表中,mongos随机选择一个符合条件的成员。
primaryPreferred 如果主数据库可用,则mongos选择主数据库。 否则,服务器选择遵循读取首选项secondary的 process。
secondaryPreferred 在服务器选择 process 之后,读取首选项secondary,如果符合条件的辅助成员列表为 non-empty,则mongos选择符合条件的辅助成员。 否则,如果列表为空,mongos选择主要列表。
上一篇下一篇

猜你喜欢

热点阅读