MongoDB-复制(副本集)

目录

一、什么是复制?

二、Mongodb复制原理

三、MongoDB副本集设置

四、docker中部署MongoDB副本集

4.1、基本信息

4.2、启动三个节点

4.3、选择在主节点进行副本集配置

4.4、同步测试

五、节点类型

六、更改节点优先级

七、设置隐藏节点

八、设置仲裁节点

九、设置延迟复制节点

十、设置Secondary-Only节点

十一、设置Non-Voting节点

十二、副本集成员状态

十三、参考


MongoDB复制是 将数据同步在多个服务器的过程。
复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高数据的 可用性,并可以保证数据的 安全性
复制还允许你从硬件故障和服务中断中恢复数据。

一、什么是复制?

  • 保障数据的安全性
  • 数据的高可用性(24*7)
  • 灾难恢复
  • 无需停机维护(如备份、重建索引、压缩)
  • 分布式读取数据,可配置读写分离,主节点负责写操作,从节点负责读操作,将读写压力分开,提高系统稳定性

二、Mongodb复制原理

Mongodb的复制至少需要两个节点:一个主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点的数据。
Mongodb各个节点常见的搭配方式:一主一从、一主多从
主节点记录在其上的所有操作oplog(operation log,它被存储在MongoDB的 local 数据库中,oplog 中的每个文档都代表主节点上执行的一个操作。需要重点强调的是oplog只记录改变数据库状态的操作),从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致
MongoDB复制结构图如下所示:

MongoDB-复制(副本集)_第1张图片

以上结构图中,客户端从主节点读取数据,在客户端写入数据到主节点时, 主节点与从节点进行数据交互保障数据的一致性
副本集概念:
    MongoDB副本集(Replica Set)其实就是具有自动故障恢复功能的主从集群和主从复制最大的区别就是在副本集中没有固定的“主节点;整个副本集会选出一个节点作为“主节点”,当其挂掉后,再在剩下的从节点中选举一个节点成为新的“主节点”,在副本集中总有一个主节点(primary)和一个或多个备份节点(secondary)。
    MongoDB的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点,不会出现宕机的情况。
副本集特征
  • N个节点的集群
  • 任何节点都可以作为主节点
  • 所有写入操作都在主节点上
  • 自动故障转移
  • 自动恢复

三、MongoDB副本集设置

1、启动一个名为rs0的Mongodb实例
    mongod --port 27017 --replSet rs0
    在Mongo客户端使用命令rs.initiate()来启动一个新的副本集。我们可以使用rs.conf()来查看副本集的配置; 查看副本集状态使用 rs.status() 命令
2、多台服务器--副本集添加新成员
    rs.add(HOST_NAME:PORT)
    MongoDB中你只能通过主节点将Mongo服务添加到副本集中, 判断当前运行的Mongo服务是否为主节点可以使用命令rs.isMaster()
    
    rs.remove(HOST_NAME:PORT) 从副本集移除成员
    rs.assArb(HOST_NAME:PORT) 向副本集添加仲裁
    db.printSecondaryReplicationInfo() 查看备份节点的复制信息

四、docker中部署MongoDB副本集

4.1、基本信息

服务器地址:192.168.11.45
副本集名称:rs0
容器节点及端口映射:
    mongo1 27018:27017
    mongo2 27019:27017
    mongo3 27020:27017

4.2、启动三个节点

docker run -d -p 27018:27017 --name mongo1 mongo  --replSet "rs0"
docker run -d -p 27019:27017 --name mongo2 mongo  --replSet "rs0"
docker run -d -p 27020:27017 --name mongo3 mongo  --replSet "rs0"

4.3、选择在主节点进行副本集配置

docker exec -it 65 mongo  # 进入主节点mongo
# 进行副本集配置
> var config={
      _id:"rs0",
      members:[
          {_id:0,host:"192.168.11.45:27018"},
          {_id:1,host:"192.168.11.45:27019"},
          {_id:2,host:"192.168.11.45:27020"}
 ]};
# 启动新的副本集
> rs.initiate(config)
{ "ok" : 1 }
此时命令提示符已经发生变化,由原来的 > 变成了 rs:SECONDARY>
# 查看副本集配置信息
rs0:SECONDARY> rs.conf()
{
        "_id" : "rs0",  # 副本集名称
        "version" : 1,
        "term" : 1,
        "protocolVersion" : NumberLong(1),
        "writeConcernMajorityJournalDefault" : true,
        "members" : [
                {
                        "_id" : 0,
                        "host" : "192.168.11.45:27018",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,    # 是否为隐藏节点
                        "priority" : 1,      # 优先级
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),  # 延迟,单位秒
                        "votes" : 1   # 1:可以投票,0:不能投票
                },
                {
                        "_id" : 1,
                        "host" : "192.168.11.45:27019",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "192.168.11.45:27020",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "catchUpTimeoutMillis" : -1,
                "catchUpTakeoverDelayMillis" : 30000,
                "getLastErrorModes" : {
                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                },
                "replicaSetId" : ObjectId("616fb8d3123d0cb36cfa6d4e")
        }
}
# 查看副本集状态
rs0:PRIMARY> rs.status()
{
        "set" : "rs0",
        "date" : ISODate("2021-10-20T06:37:05.142Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "majorityVoteCount" : 2,
        "writeMajorityCount" : 2,
        "votingMembersCount" : 3,
        "writableVotingMembersCount" : 3,
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1634711824, 1),
                        "t" : NumberLong(1)
                },
                "lastCommittedWallTime" : ISODate("2021-10-20T06:37:04.306Z"),
                "readConcernMajorityOpTime" : {
                        "ts" : Timestamp(1634711824, 1),
                        "t" : NumberLong(1)
                },
                "readConcernMajorityWallTime" : ISODate("2021-10-20T06:37:04.306Z"),
                "appliedOpTime" : {
                        "ts" : Timestamp(1634711824, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1634711824, 1),
                        "t" : NumberLong(1)
                },
                "lastAppliedWallTime" : ISODate("2021-10-20T06:37:04.306Z"),
                "lastDurableWallTime" : ISODate("2021-10-20T06:37:04.306Z")
        },
        "lastStableRecoveryTimestamp" : Timestamp(1634711774, 3),
        "electionCandidateMetrics" : {
                "lastElectionReason" : "electionTimeout",
                "lastElectionDate" : ISODate("2021-10-20T06:36:14.279Z"),
                "electionTerm" : NumberLong(1),
                "lastCommittedOpTimeAtElection" : {
                        "ts" : Timestamp(0, 0),
                        "t" : NumberLong(-1)
                },
                "lastSeenOpTimeAtElection" : {
                        "ts" : Timestamp(1634711763, 1),
                        "t" : NumberLong(-1)
                },
                "numVotesNeeded" : 2,
                "priorityAtElection" : 1,
                "electionTimeoutMillis" : NumberLong(10000),
                "numCatchUpOps" : NumberLong(0),
                "newTermStartDate" : ISODate("2021-10-20T06:36:14.297Z"),
                "wMajorityWriteAvailabilityDate" : ISODate("2021-10-20T06:36:15.001Z")
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "192.168.11.45:27018",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",    # 节点类型
                        "uptime" : 683,
                        "optime" : {
                                "ts" : Timestamp(1634711824, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2021-10-20T06:37:04Z"),
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "",
                        "electionTime" : Timestamp(1634711774, 1),
                        "electionDate" : ISODate("2021-10-20T06:36:14Z"),
                        "configVersion" : 1,
                        "configTerm" : 1,
                        "self" : true,
                        "lastHeartbeatMessage" : ""
                },
                {
                        "_id" : 1,
                        "name" : "192.168.11.45:27019",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",  # 节点类型
                        "uptime" : 61,
                        "optime" : {
                                "ts" : Timestamp(1634711814, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1634711814, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2021-10-20T06:36:54Z"),
                        "optimeDurableDate" : ISODate("2021-10-20T06:36:54Z"),
                        "lastHeartbeat" : ISODate("2021-10-20T06:37:04.284Z"),
                        "lastHeartbeatRecv" : ISODate("2021-10-20T06:37:03.289Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "192.168.11.45:27018",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 1,
                        "configTerm" : 1
                },
                {
                        "_id" : 2,
                        "name" : "192.168.11.45:27020",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",  # 节点类型
                        "uptime" : 61,
                        "optime" : {
                                "ts" : Timestamp(1634711814, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1634711814, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2021-10-20T06:36:54Z"),
                        "optimeDurableDate" : ISODate("2021-10-20T06:36:54Z"),
                        "lastHeartbeat" : ISODate("2021-10-20T06:37:04.284Z"),
                        "lastHeartbeatRecv" : ISODate("2021-10-20T06:37:03.289Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "192.168.11.45:27018",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 1,
                        "configTerm" : 1
                }
        ],
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1634711824, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1634711824, 1)
}

4.4、同步测试

在主节点mongo1-27018上新增一条记录,可在mongo2-27019、mongo3-27020上看到
MongoDB-复制(副本集)_第2张图片

五、节点类型

Mongodb的节点类型:主节点(Master或者Primary)、副本节点(Slave或者Secondary)、仲裁节点、Secondary-Only节点、Hidden节点、Delayed节点、Non-Voting节点
  • 仲裁节点:不存储数据,只负责故障转移的群体投票,这样减少了数据复制的压力;
  • Secondary-Only:不能成为primary节点,只能作为secondary副本节点,防止部分性能不高的节点成为主节点
  • Hidden:不能被客户端指定Ip引用,也不能设置为主节点,但是可以投票,一般用于备份数据
  • Delayed:可以指定一个时间延迟从primary节点同步数据,主要用于备份数据。如果实时同步,误删除数据马上同步到从节点。所以延迟复制主要用于避免用户错误
  • Non-Voting:没有选举权的secondary节点,纯粹的备份数据节点

六、更改节点优先级

修改节点的优先级可以触发从新选举,这样可以人工指定主节点。
使用如下命令,在主节点mongo1 192.168.11.45:27018操作,将mongo2 192.168.11.45:27019 提升为Master:
cfg = rs.conf();
cfg.members[0].priority = 1
cfg.members[1].priority = 10
cfg.members[2].priority = 1
rs.reconfig(cfg);
然后查看集群状态:rs.status()

七、设置隐藏节点

隐藏节点可以在选举中投票,但是不能被客户端引用,也不能成为主节点。也就是说这个节点不能用于读写分离的场景。
使用如下命令,在主节点mongo1 192.168.11.45:27018操作,将mongo2 192.168.11.45:27019 设置为隐藏节点:
注意,只有优先级为0的成员才能设置为隐藏节点。如果设置优先级不为0的节点为隐藏节点,则报错
cfg = rs.conf();
cfg.members[0].priority = 1
cfg.members[1].priority # 先设置优先级为0
cfg.members[2].priority = 1
cfg.members[1].hidden 1
rs.reconfig(cfg);
然后查看集群状态:rs.status(),该节点还是SECONDARY状态,但是通过rs.isMaster()rs.conf()可以看到这个节点的变化:
  1. rs.isMaster()的hosts中192.168.11.45:27019节点已经不可见;
  2. rs.conf()显示该节点状态为hidden

八、设置仲裁节点

仲裁节点不存储数据,只是用于投票。所以仲裁节点对于服务器负载很低
节点一旦以仲裁者的身份加入集群,他就只能是仲裁者,无法将仲裁者配置为非仲裁者,反之也是一样
另外一个集群最多只能使用一个仲裁者,额外的仲裁者拖累选举新Master节点的速度,同时也不能提供更好的数据安全性。
初始化集群时,设置仲裁者的配置如下:
> var config={
      _id:"rs0",
      members:[
          {_id:0,host:"192.168.11.45:27018"},
          {_id:1,host:"192.168.11.45:27019",arbiterOnly:true},
          {_id:2,host:"192.168.11.45:27020"}
 ]};
使用仲裁者主要是因为MongoDB副本集需要奇数成员,而又没有足够服务器的情况。在服务器充足的情况下,不应该使用仲裁者节点。

九、设置延迟复制节点

延迟节点的优先级必须为0.这个和hidden节点是一样的。。
cfg = rs.conf();
cfg.members[1].priority # 先设置优先级为0
cfg.members[1].slaveDelay = 3600  # 单位秒
rs.reconfig(cfg);
192.168.11.45:27018节点删除一个集合所有数据,模拟人为失误 db.users.remove({})
192.168.11.45:27020节点查看,发现数据已经完全丢失;
而在192.168.11.45:27019延迟节点,可以看到因为延迟复制的缘故,数据还在。
这个时候千万不要提升延迟节点的优先级。因为这样他会立即应用原主节点的所有操作,并成为新的主节点。这样误操作就同步到了延迟节点。
应该进行如下操作:
  1. 关闭副本集中其他的成员,除了延迟节点。
  2. 删除其他成员数据目录中的所有数据。确保每个其他成员的数据目录都是空的(除了延迟节点)
  3. 重启其他成员,他们会自动从延迟节点中恢复数据。

十、设置Secondary-Only节点

Priority为0的节点永远不能成为主节点,所以设置Secondary-only节点只需要将其priority设置为0.

十一、设置Non-Voting节点

cfg = rs .conf ();
cfg .members [ 1 ]. votes # 设置不能投票
rs .reconfig (cfg );

十二、副本集成员状态

副本集成员状态指的是rs.status()的stateStr字段.
  • STARTUP:刚加入到复制集中,配置还未加载
  • STARTUP2:配置已加载完,初始化状态
  • RECOVERING:正在恢复,不适用读
  • ARBITER: 仲裁者
  • DOWN:节点不可到达
  • UNKNOWN:未获取其他节点状态而不知是什么状态,一般发生在只有两个成员的架构,脑裂
  • REMOVED:移除复制集
  • ROLLBACK:数据回滚,在回滚结束时,转移到RECOVERING或SECONDARY状态
  • FATAL:出错。查看日志grep “replSet FATAL”找出错原因,重新做同步
  • PRIMARY:主节点
  • SECONDARY:备份节点

十三、参考

MongoDB 复制(副本集) | 菜鸟教程 

docker中部署mongodb副本集 - HappyCowboy - 博客园 

你可能感兴趣的:(MongoDB,mongodb,Replica,Set)