mongoDB -- 复制集

1、复制集作用

复制集可以提供数据冗余备份,提高数据的可用性。
主节点 接收所有的写入操作,将数据写入数据库,并将写入操作写到日志中,如oplog。然后从节点复制这些操作日志,并将写入操作应用在自身数据库上,达到数据复制。数据同步的过程时异步的。
如果,主节点不可用了,会在从节点中重新投票选择一个数据库,作为新的主节点。原来的主节点功能恢复后作为从节点加入复制集。
另外,主节点和从节点都能提供读取操作,满足大量的读取需求。

一个节点,即一个MongoDB实例,包含所有的数据库。

2、复制集的架构

最小复制集的架构需要3台服务器组成,包含一个三成员的复制集。一个主节点,两个从节点;或者是一个主节点,一个从节点,一个仲裁者。仲裁者不存储数据,但可以参与投票。arbiter节点只需要更少的资源,代价是更有限的冗余和容错。
复制集最多可以有 50个副本成员,但最多有7个有投票权,主节点数据库只能有一个,仲裁者可多个。应尽量避免部署仲裁者,最好部署 奇数个 备份数据的节点。

复制集通过replSetInitiate命令(或mongo shell的rs.initiate())进行初始化,初始化后各个成员间开始发送心跳消息,并发起Priamry选举操作,获得『大多数』成员投票支持的节点,会成为Primary,其余节点成为Secondary。
假设复制集内投票成员数量为N,则大多数为大于等于 N/2 + 1,当复制集内存活成员数量低于(N/2 + 1)时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。

在某些情况下,复制集中的两个节点可能暂时认为它们是主节点,但最多有一个节点能够用{w: "majority"}写关注点完成写操作。能够完成{w: "majority"}写操作的节点是当前的主节点,另一个节点是通常由于网络分区的原因而尚未意识到已降级的前主节点。当发生这种情况时,尽管已经请求了读优先级主服务器,连接到前主服务器的客户端可能会观察到过时的数据,并且对前主服务器的新写操作最终将回滚。

默认 数据的读写都是从主服务器中进行的。
从节点可以设置成:1不能参与主节点选举、2不能被读取数据、3只作为数据快照,用于数据恢复。

从4.2版开始(也可以从4.0.6版开始),复制集的次要成员现在记录需要超过慢操作阈值的oplog条目。这些缓慢的oplog消息被记录在REPL组件下的诊断日志中,并应用了文本op: took ms。这些慢速oplog条目仅依赖于慢速操作阈值。它们不依赖于日志级别(系统级别或组件级别)、分析级别或缓慢的操作采样率。分析器不会捕获慢速的oplog条目。

3、从节点数据库

3.1 优先级为0的复制集从节点 priority: 0

Priority 0 的节点不能被选择为primary数据库。能确认写关注为 w : 的写操作。如果写操作的写关注为 w : "majority",priority0成员必须是可投票的,才能确认写操作。

如果某个节点成员远离主数据中心,因此有较高的网络延迟,则可能需要将其priority配置为0。它可以很好地服务于本地读去请求,但由于网络分区延迟,可能不是执行primary服务器职责的理想候选者。

3.2 隐藏复制集从节点 hidden: true

隐藏节点也有主节点的数据冗余,但对于客户端是不可见的。隐藏节点的 priority 必须是 0 ,也不能成为主节点,但 可以参与投票选举主节点。
db.isMaster()方法不显示隐藏的成员.

可使用Hidden节点做一些数据备份、离线计算的任务,不会影响复制集的服务。
延迟的成员应该隐藏起来。 在一个分片集群中,mongos不与隐藏的成员交互。

能确认写关注为 w : 的写操作。如果写操作的写关注为 w : "majority",priority0成员必须是可投票的,才能确认写操作。

3.2 延迟复制集成员 delay

延迟节点也包含主节点数据冗余,但有一定的时间延迟(可配置)。

延迟成员是数据集的“滚动备份”或正在运行的“历史”快照,它们可以帮助操作者从各种人为错误中恢复,如误删,更新错误等。

延迟节点必须是 priority: 0,hidden: true,如果votes: 1 可参与主节点的投票选举。

能确认写关注为 w : 的写操作。如果写操作的写关注为 w : "majority",priority0成员必须是可投票的,才能确认写操作。

在分片集群中,当均衡器启用时,延迟成员的效用有限。因为延迟成员通过延迟复制块迁移,所以如果在延迟窗口期间发生任何迁移,那么分片集群中延迟成员的状态对于恢复到分片集群的前一个状态是没有用的

{
   "_id" : <num>,
   "host" : <hostname:port>,
   "priority" : 0,
   "slaveDelay" : <seconds>,
   "hidden" : true
}

4、操作日志 oplog

https://docs.mongodb.com/manual/core/replica-set-oplog/

oplog(操作日志)是一个特殊的固定大小的集合,它保存所有对数据库数据修改的滚动记录。

从MongoDB4.0开始,oplog 可以存储超过其设置大小的数据量,以免错误删除数据。

MongoDB 4.4 支持以 小时数 指定 oplog 的最小保存时间。此时,只有当oplog 的数据量达到设置的最大值且oplog中的数据早于配置的小时数 才能删除 oplog。
默认情况下,MongoDB 不会设置oplog的最小保存时间,并自动从最老的条目开始截断oplog,以保持配置的最大oplog大小

复制集中的所有成员都通过心跳来保持联系,从节点数据库可以从任何其他的成员获取 oplog 来更新自身数据。
在oplog 中的操作时幂等的,即任何复制集的成员执行多少次这些操作,结果都是一样的,即数据不会重复。

默认的oplog大小,在大多数情况下都是足够的。
For Unix and Windows systems

Storage Engine Default Oplog Size Lower Bound Upper Bound
In-Memory Storage Engine 5% of physical memory 50 MB 50 GB
WiredTiger Storage Engine 5% of free disk space 990 MB 50 GB

For macOS

Storage Engine Default Oplog Size
In-Memory Storage Engine 192 MB of physical memory
WiredTiger Storage Engine 192 MB of physical memory

如果应用有很大的写入、更新操作,则需要较大的oplog以满足需求。oplog 容量太小,就有可能同步数据丢失

在第一次启动 复制集时,可在MongoDB配置文件中 指定 oplog的大小(replication.oplogSizeMB)。但在启动复制集后,只能执行命令 replSetResizeOplog 来重置。

replication:
   oplogSizeMB: <int>
   replSetName: <string>
   enableMajorityReadConcern: <boolean>



db.adminCommand(
  {
    replSetResizeOplog: <int>,
    size: <double>,
    minRetentionHours: <double>
  }
)



5. 数据同步

https://docs.mongodb.com/manual/core/replica-set-sync/#initial-sync

复制集同步数据方式有两种:初始化同步,复制oplog同步。

如果是新节点成员,则需要初始化同步,会将源节点的所有数据库(除local数据库外)的数据都复制到 新节点成员中。数据库中的collection 的索引也会建立。
在复制所有数据的同时,也会复制oplog。

初始化过程中,如果出现了错误,会尝试最多10次的重试。重试的时间间隔可以设置,默认是24小时。 通过设置 mongod 启动参数:initialSyncTransientErrorRetryPeriodSeconds,改变重试时间周期。

初始化源节点 默认是 primary 节点。通过设置 mongod 启动参数 initialSyncSourceReadPreference 改变源节点的选择。

初始化同步数据后,节点就通过 oplog 同步数据了。oplog 也是从源节点获取。

6、主节点选举

选举触发事件:
1、复制集的初始化
2、在复制集中增加新节点
3、在副本集中使用 rs.stepDown() 或 rs.reconfig() 方法
4、所有从节点与主节点的连接超时(10s,默认值),其余从节点开始选举

在主节点选举结果未出来之前,副本集不能接受写入操作,但如果,从节点设置了能够对外读取操作,那数据仍然可以被读取。
默认情况下,选举主节点整个过程的平均时间不能超过12s。这个时间包括,标记主节点不可用,召集从节点,并完成选举。

副本集中的成员节点每2s相互发送心跳。如果某个节点10s内 没有心跳返回,那么其他节点就会将该节点标记为不可用。

成员的priority会影响选举的时间和结果。优先级高度节点会更快进行选举,并更有可能当选主节点。优先级低的成员也有可能在某一时刻当选主节点,但副本集会继续进行选举,直到具有最高优先级的节点中的一个成为主节点。

优先级为 0 的节点不能参与选举。
如果 配置设置 members[n].votes 为 0 ,则 priority 必须为 0。但 priority 为 0 , votes可以为 1(默认值)。
只有当 可参与选举的成员在如下状态下 可进行选举:PRIMARY,SECONDARY,STARTUP2,RECOVERING,ARBITER,ROLLBACK

副本集中最多能有50个成员,7个可选举成员。不可选举成员必须 设置 members[n].votes 为 0 ,priority 为 0。

7、副本集故障切换中的回滚

https://docs.mongodb.com/manual/core/replica-set-rollbacks/

当副本集因故障出现主从切换后,前主节点重新加入副本集时,可能会出现数据回滚。
发生回滚的条件:主节点接受了写操作,但从节点都还没有复制数据,主节点就故障不可用了。当它作为从节点重新加入副本集时,就会将之前的写操作回滚(去除写入操作)以和其他节点数据一致。此时就造成数据丢失。

发生回滚的概率很小,经常是网路分区的造成的。如果从节点跟不上前主节点吞吐量,会使得回滚的数据量变大,影响也就变大。

当回滚发生后,会生成一个 bson 文件。可以将该文件数据手动恢复到 数据库中。
文件位置:

# mongodb 4.4+
<dbpath>/rollback/<collectionUUID>/removed.<timestamp>.bson
<dbpath>/rollback/20f74796-d5ea-42f5-8c95-f79b39bad190/removed.2020-02-19T04-57-11.0.bson


# mongodb 4.0-4.2
<dbpath>/rollback/<db>.<collection>
<dbpath>/rollback/reporting.comments/removed.2019-01-31T02-57-40.0.bson

如果回滚操作是删除集合或删除文档,那么删除收集或删除文档的回滚不会写入回滚数据目录。

如何避免回滚:
将所有的投票节点开启日志,并使用 w: majority 写关注,以保证在给客户端确认应答之前 ,写操作已经传播值大多数节点。

{ writeConcern: { w: "majority" , j: true} }

在MongoDB4.0 开始,回滚对数据的大小没有了限制,但默认只回滚24小时内的数据。

8、复制集中的写关注 write concern

https://docs.mongodb.com/manual/core/replica-set-write-concern/

复制集中的 写关注 描述的是 一个写操作在返回成功之前,必须给出写操作确认的成员个数。这里的成员是指备份数据的成员,即仲裁者除外。

默认在数文档的增、删、改操作中,写关注w:1,就是说只要主节点确认就返回成功。 w 的值最小是1,最大是 副本集中 除仲裁者外节点的总个数。
如果 w 指定 majority,表示在返回成功前,需要大多数成员确认该写操作。这里的大多数是指:所有可投票成员(包括仲裁者)的大多数 和 所有备份数据的成员个数 中的更小的那个数。

需要写操作确认的节点越多,主节点失效后 数据回滚的可能性就越小。但高的写关注确认,会导致写操作延时,即客户端就要等待更多时间完成写操作。

db.products.insert(
   { item: "envelopes", qty : 100, type: "Clasp" },
   { writeConcern: { w: "majority" , wtimeout: 5000 } }   // 指定了超时,表示在等待写操作确认的时间最多是5秒,超时就返回写关注错误。但并不意味着主节点的写操作未完成,有部分节点可能已经有数据了,只是不是大多数。
)

可以 使用 setDefaultRWConcern 命令 来设置默认 写关注
如果 给一个写操作单独指定写关注,那会替换掉 默认值。

可以给复制集中的节点成员打上标签 tag , 用标签创建写关注

复制集的读取设置

https://docs.mongodb.com/manual/core/read-preference/

读取模式 描述
primary 默认模式。只从当前复制集主节点读取
primaryPreferred 大部分情况都从,主节点读取数据。当主节点不可用,从从节点读取
secondary 只从当前复制集的从节点读取数据
secondaryPreferred 大部分情况从 从节点读取,当从节点都不可用,从主节点读取
nearest 从延时最小的节点读取,不管主节点还是从节点

一般设置 secondary 读取模式,以减轻主节点压力,让主节点只进行写操作。
多文档事务的读取操作必须是 primary 模式,因为同一个事务中的所有操作必须在同一个成员上进行。

使用 cursor.readPref(mode, tagSet, hedgeOptions) 来设置读取偏好

## mode 读取模式
## tagSet 标签数组,可选,匹配节点,不兼容 primary 模式
## hedgeOptions 可选,指定是否开启  hedged reads 
cursor.readPref(mode, tagSet, hedgeOptions)


db.collection.find({ }).readPref(
   "secondary",
   [
      { "datacenter": "B" },    // First, try matching by the datacenter tag
      { "region": "West"},      // If not found, then try matching by the region tag
      { }                       // If not found, then use the empty document to match all eligible members
   ]
)

db.collection.find({ }).readPref(
   "secondary",            // mode
   null,                   // tag set
   { enabled: true }       // hedge options
)


## 在实际使用中,可以在连接url 上设置读取偏好
# 连接复制集,读取偏好 secondary
mongo "mongodb://db0.example.com,db1.example.com,db2.example.com/?replicaSet=myRepl&readPreference=secondary&maxStalenessSeconds=120"

## 如果指定了用户名密码和数据库,且账号所在库和实际使用的库不同,则需要指定 认证库authSource 参数
# 账号在 admin 数据库上创建的(并设置有操作其他数据的权限),使用的数据库是 test
mongo "mongodb://username:password@db0.example.com,db1.example.com,db2.example.com/test?replicaSet=myRepl&readPreference=secondary&maxStalenessSeconds=120&authSource=admin"

参考文档

https://www.cnblogs.com/clsn/p/8214345.html#auto_id_0
https://docs.mongodb.com/manual/replication/

复制集配置 官网:https://docs.mongodb.com/manual/reference/replica-configuration/#mongodb-rsconf-rsconf
MongoDB 实例的配置文件: https://docs.mongodb.com/manual/reference/configuration-options/#configuration-file

posted @ 2021-04-19 10:31  zhanglw  阅读(605)  评论(0)    收藏  举报