5-MongoDB副本集搭建及滚动升级和备份_副本集

副本集配置

官方文档

https://docs.mongodb.com/manual/tutorial/deploy-replica-set/

1.1副本级介绍

两种集群:一种是分片,一种是副本级的
副本集的组成

MongoDB 副本集由一组节点组成,其中包括以下角色:
    1.  主节点(Primary):
    •   唯一能接收写操作的节点。
    •   所有写操作都会记录到主节点的 oplog(操作日志) 中,并同步到从节点。
    2.  从节点(Secondary):
    •   从主节点复制数据,并维持与主节点一致的状态。
    •   可以通过配置允许从节点响应读请求(即读偏好设置)。
    3.  仲裁节点(Arbiter):
    •   不存储数据,仅参与选举以决定新的主节点。
    •   通常在节点数为偶数时加入,以防止选举时票数平分。

1.2工作原理

5-MongoDB副本集搭建及滚动升级和备份_副本集_02

5-MongoDB副本集搭建及滚动升级和备份_副本集_03

5-MongoDB副本集搭建及滚动升级和备份_副本集_04


1.  数据同步:
    •   从节点通过定期拉取主节点的 oplog 日志来同步数据。
    •   如果从节点落后太多,可能需要执行数据恢复(例如全量同步)。
    2.  自动故障转移:
    •   当主节点不可用时,从节点会通过选举机制选出一个新的主节点。
    •   选举过程中会考虑节点优先级、同步延迟等因素。
    3.  读写分离(可选):
    •   默认情况下,所有读操作和写操作都发送到主节点。
    •   可以通过设置读偏好(Read Preference),将读操作分发到从节点。

mongodb有点类似redis他可以单机多实例,就是一个mongod命令指定多个配置文件就是多个实例

1.3 机器规划

IP

主机名

操作系统

192.168.1.31


KylinV10 x86

192.168.1.3


KylinV10 x86

192.168.1.3


KylinV10 x86

1.4 创建mongo目录

#三台机器做同样的操作
[root@mdb1 data]# tar xf mongodb-linux-x86_64-3.4.20.tgz 
[root@mdb1 data]# mv mongodb-linux-x86_64-3.4.20 mongodb
[root@mdb1 data]# mkdir -p /data/mongodb/{conf,logs,pid}
[root@mdb1 data]# mkdir /data/mongodbdata

1.5 创建配置文件

注意 bindIP哪里要写自己的本机的ip。不同机器的ip不同 三个实例ip不一样

[root@mdb1 data]# cat /data/mongodb/conf/mongdb.conf 
systemLog:
  destination: file   # Mongodb 日志输出的目的地,指定一个 file 或者 syslog
  logAppend: true     # 当实例重启时,不创建新的日志文件,在老的日志文件末尾继续添加
  path: /data/mongodb/logs/mongodb.log    # 日志路径

storage:
  dbPath: /data/mongodbdatas    # 数据存储目录
  journal:       # 回滚日志
    enabled: true
  directoryPerDB: true     # 默认 false,不适用 inmemory engine
  wiredTiger:  # 存储引擎
    engineConfig:
      cacheSizeGB: 1       # 将用于所有数据缓存的最大大小
      directoryForIndexes: true # 默认false,索引集合存储在数据单独子目录

processManagement:    # 使用处理系统守护进程的控制处理
  fork: true         # fork and run in background,后台运行
  pidFilePath: /data/mongodb/pid/mongod.pid  # pid 文件的位置

net:
  port: 27017            # 监听端口
  bindIp: 127.0.0.1,192.168.1.31  # 绑定 ip  #这里需要改为本机ip

replication:
  oplogSizeMB: 1024 # 复制操作日志的大小(如果启用复制集,请取消注释并设置)
  replSetName: guoguo  # 副本集名称,同一个副本集的所有主机必须设置相同的名称(如果启用复制集,请取消注释并设置)

1.6 启动所有节点

三台机器做同样操作

[root@mdb1 data]# /data/mongodb/bin/mongod -f /data/mongodb/conf/mongodb.conf
[root@mdb1 data]# ss -tnl | grep 27017
LISTEN  0        128         192.168.1.31:27017          0.0.0.0:*              
LISTEN  0        128            127.0.0.1:27017          0.0.0.0:*

1.7 初始化副本集

初始化命令

config = {
_id : "guoguo",
members : [
{_id : 0, host : "192.168.1.31:27017"},
{_id : 1, host : "192.168.1.32:27017"},
{_id : 2, host : "192.168.1.33:27017"},
] }
// ip可以换成主机名 如果换成主机名 三台主机需要都能解析 也就是要写到hosts文件里面

rs.initiate(config)
// 生效配置文件

// 也可以设置权重比如   权重的值范围是0-100
//如果值为0 纳米就不能成为primay
config = {
_id : "guoguo",
members : [
{_id : 0, host : "192.168.1.31:27017",priority:10},
{_id : 1, host : "192.168.1.32:27017",priority:20},
{_id : 2, host : "192.168.1.33:27017",priority:30},
] }

执行过程

[root@mdb1 data]# mongo 192.168.1.31:27017
> config = {
... _id : "guoguo",
... members : [
... {_id : 0, host : "192.168.1.31:27017"},
... {_id : 1, host : "192.168.1.32:27017"},
... {_id : 2, host : "192.168.1.33:27017"},
... ] }
{
        "_id" : "guoguo",
        "members" : [
                {
                        "_id" : 0,
                        "host" : "192.168.1.31:27017"
                },
                {
                        "_id" : 1,
                        "host" : "192.168.1.32:27017"
                },
                {
                        "_id" : 2,
                        "host" : "192.168.1.33:27017"
                }
        ]
}
> rs.initiate(config)
{ "ok" : 1 }

1.8 查看状态

guoguo:SECONDARY> rs.status()
{
        "set" : "guoguo",
        "date" : ISODate("2024-11-27T13:36:17.876Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1732714568, 1),
                        "t" : NumberLong(1)
                },
                "appliedOpTime" : {
                        "ts" : Timestamp(1732714568, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1732714568, 1),
                        "t" : NumberLong(1)
                }
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "192.168.1.31:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 474,
                        "optime" : {
                                "ts" : Timestamp(1732714568, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2024-11-27T13:36:08Z"),
                        "syncingTo" : "",
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "could not find member to sync from",
                        "electionTime" : Timestamp(1732714496, 1),
                        "electionDate" : ISODate("2024-11-27T13:34:56Z"),
                        "configVersion" : 1,
                        "self" : true,
                        "lastHeartbeatMessage" : ""
                },
                {
                        "_id" : 1,
                        "name" : "192.168.1.32:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 92,
                        "optime" : {
                                "ts" : Timestamp(1732714568, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1732714568, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2024-11-27T13:36:08Z"),
                        "optimeDurableDate" : ISODate("2024-11-27T13:36:08Z"),
                        "lastHeartbeat" : ISODate("2024-11-27T13:36:16.830Z"),
                        "lastHeartbeatRecv" : ISODate("2024-11-27T13:36:17.672Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncingTo" : "192.168.1.31:27017",
                        "syncSourceHost" : "192.168.1.31:27017",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 1
                },
                {
                        "_id" : 2,
                        "name" : "192.168.1.33:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 92,
                        "optime" : {
                                "ts" : Timestamp(1732714568, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1732714568, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2024-11-27T13:36:08Z"),
                        "optimeDurableDate" : ISODate("2024-11-27T13:36:08Z"),
                        "lastHeartbeat" : ISODate("2024-11-27T13:36:16.830Z"),
                        "lastHeartbeatRecv" : ISODate("2024-11-27T13:36:17.672Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncingTo" : "192.168.1.31:27017",
                        "syncSourceHost" : "192.168.1.31:27017",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 1
                }
        ],
        "ok" : 1
}
guoguo:PRIMARY>   #主节点
guoguo:SECONDARY>  #从节点

到目前为止,副本集已经搭建成功了分别是 192.168.1.32:27017 192.168.1.32:27017 192.168.1.33:27017

不需要关注那个是主那个是从,驱动程序会自动识别

1.9 写入测试数据

现在主节点可以读写数据,从无法读无法写

命令

主节点执行

db.inventory.insertMany( [
{ "item": "journal", "qty": 25, "size": { "h": 14, "w": 21, "uom": "cm" }, "status": "A" },
{ "item": "notebook", "qty": 50, "size": { "h": 8.5, "w": 11, "uom": "in" }, "status": "A" },
{ "item": "paper", "qty": 100, "size": { "h": 8.5, "w": 11, "uom": "in" }, "status": "D" },
{ "item": "planner", "qty": 75, "size": { "h": 22.85, "w": 30, "uom": "cm" }, "status": "D" },
{ "item": "postcard", "qty": 45, "size": { "h": 10, "w": 15.25, "uom": "cm" }, "status": "A" }
]);
#主节点是可以查看的
guoguo:PRIMARY> db.inventory.find()
{ "_id" : ObjectId("6747225a5bb258ec2282b37e"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "status" : "A" }
{ "_id" : ObjectId("6747225a5bb258ec2282b37f"), "item" : "notebook", "qty" : 50, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "A" }
{ "_id" : ObjectId("6747225a5bb258ec2282b380"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }
{ "_id" : ObjectId("6747225a5bb258ec2282b381"), "item" : "planner", "qty" : 75, "size" : { "h" : 22.85, "w" : 30, "uom" : "cm" }, "status" : "D" }
{ "_id" : ObjectId("6747225a5bb258ec2282b382"), "item" : "postcard", "qty" : 45, "size" : { "h" : 10, "w" : 15.25, "uom" : "cm" }, "status" : "A" }

#从节点无法查看
guoguo:SECONDARY> db.inventory.find()
Error: error: {
        "ok" : 0,
        "errmsg" : "not master and slaveOk=false",  #默认从节点无法读数据
        "code" : 13435,
        "codeName" : "NotMasterNoSlaveOk"
}

通过命令配置副本可读

#这条命令
guoguo:SECONDARY> rs.slaveOk();

#可以读了
guoguo:SECONDARY> db.inventory.find()
{ "_id" : ObjectId("6747225a5bb258ec2282b37f"), "item" : "notebook", "qty" : 50, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "A" }
{ "_id" : ObjectId("6747225a5bb258ec2282b382"), "item" : "postcard", "qty" : 45, "size" : { "h" : 10, "w" : 15.25, "uom" : "cm" }, "status" : "A" }
{ "_id" : ObjectId("6747225a5bb258ec2282b380"), "item" : "paper", "qty" : 100, "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "status" : "D" }
{ "_id" : ObjectId("6747225a5bb258ec2282b381"), "item" : "planner", "qty" : 75, "size" : { "h" : 22.85, "w" : 30, "uom" : "cm" }, "status" : "D" }
{ "_id" : ObjectId("6747225a5bb258ec2282b37e"), "item" : "journal", "qty" : 25, "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "status" : "A" }

永久配置从节点可读

[root@mdb2 ~]# cat ~/.mongorc.js 
rs.slaveOk()
#在家目录下 添加这么一行就可以了

1.10 故障转移

将主节点杀掉

[root@mdb1 conf]# killall mongod 
[root@mdb1 conf]# killall mongod 
mongod: 未找到进程

登陆副本查看

[root@mdb3 ~]# /data/mongodb/bin/mongo 192.168.1.33:27017
guoguo:PRIMARY>  
#已经变为主了
#修改下数据
guoguo:PRIMARY> db.test.insert({"name":"zhangya","age":27,"ad":"北京市朝阳区"})
WriteResult({ "nInserted" : 1 })
#可以
guoguo:PRIMARY> db.test.find()
{ "_id" : ObjectId("674725822b6e7875ec0499a3"), "name" : "zhangya", "age" : 27, "ad" : "北京市朝阳区" }
guoguo:PRIMARY>

启动损坏节点

[root@mdb1 conf]# /data/mongodb/bin/mongod -f /data/mongodb/conf/mongodb.conf

登陆查看数据

[root@mdb1 conf]# /data/mongodb/bin/mongo 192.168.1.31:27017
guoguo:SECONDARY> rs.slaveOk()
guoguo:SECONDARY> db.test.find()
{ "_id" : ObjectId("674725822b6e7875ec0499a3"), "name" : "zhangya", "age" : 27, "ad" : "北京市朝阳区" }

1.11 副本集权重调整

如果初始化集群的时候没有设置权重,那么磨人每个接待您的权重都是一样样的,也就是说每个节点都可以竞选主节点

1.11.1 查看集群配置

[root@mdb3 ~]# /data/mongodb/bin/mongo 192.168.1.33:27017

guoguo:PRIMARY> rs.conf()
{
        "_id" : "guoguo",
        "version" : 1,
        "protocolVersion" : NumberLong(1),
        "members" : [
                {
                        "_id" : 0,
                        "host" : "192.168.1.31:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,   #这里是权重  不设置默认是1
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 1,
                        "host" : "192.168.1.32:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "192.168.1.33:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "catchUpTimeoutMillis" : 60000,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                },
                "replicaSetId" : ObjectId("67471ff5bb5e4cccfd7ca964")
        }
}

1.11.2 调整节点权重

cfg = rs.conf();

cfg.members[0].priority = 2    // 提高 192.168.1.31 的优先级
cfg.members[1].priority = 1    // 保持 192.168.1.32 的默认优先级
cfg.members[2].priority = 0    // 设置 192.168.1.33 为只同步节点

rs.reconfig(cfg)   // 应用配置

guoguo:PRIMARY> cfg.members[0].priority = 2    // 提高 192.168.1.31 的优先级
2
guoguo:PRIMARY> cfg.members[1].priority = 1    // 保持 192.168.1.32 的默认优先级
1
guoguo:PRIMARY> cfg.members[2].priority = 0    // 设置 192.168.1.33 为只同步节点
0

1.11.3 主节点主动降级

rs.stepDown()

1.12 增加新节点

为了方便就不开台机器了,就直接用192.168.1.31的命令然后创建个目录直接干

创建新节点目录及启动

#在192.168.1.31 上操作
[root@mdb1 data]# cp -r /data/mongodb /data/mongodb28017
[root@mdb1 data]# mkdir /data/mongodb28017data
[root@mdb1 data]# cat /data/mongodb28017/conf/mongodb.conf 
systemLog:
  destination: file   # Mongodb 日志输出的目的地,指定一个 file 或者 syslog
  logAppend: true     # 当实例重启时,不创建新的日志文件,在老的日志文件末尾继续添加
  path: /data/mongodb28017/logs/mongodb.log    # 日志路径

storage:
  dbPath: /data/mongodb28017data    # 数据存储目录
  journal:       # 回滚日志
    enabled: true
  directoryPerDB: true     # 默认 false,不适用 inmemory engine
  wiredTiger:  # 存储引擎
    engineConfig:
      cacheSizeGB: 1       # 将用于所有数据缓存的最大大小
      directoryForIndexes: true # 默认false,索引集合存储在数据单独子目录

processManagement:    # 使用处理系统守护进程的控制处理
  fork: true         # fork and run in background,后台运行
  pidFilePath: /data/mongodb28017/pid/mongod.pid  # pid 文件的位置

net:
  port: 28017            # 监听端口
  bindIp: 192.168.1.31,127.0.0.1  # 绑定 ip  #这里需要改为本机ip

replication:
  oplogSizeMB: 1024 # 复制操作日志的大小(如果启用复制集,请取消注释并设置)
  replSetName: guoguo  # 副本集名称,同一个副本集的所有主机必须设置相同的名称(如果启用复制集,请取消注释并设置)

#启动
[root@mdb1 data]# /data/mongodb28017/bin/mongod -f /data/mongodb28017/conf/mongodb.conf 
[root@mdb1 data]# /data/mongodb28017/bin/mongo 192.168.1.31:28017

然后去主库 增加新节点。 这里要去主库执行

[root@mdb1 ~]# /data/mongodb/bin/mongo 192.168.1.31:27017
guoguo:PRIMARY> use admin
switched to db admin
guoguo:PRIMARY> rs.add("192.168.1.31:28017")
{ "ok" : 1 }

返回新增节点终端

> 
guoguo:SECONDARY> 
#变成从了

1.13 删除旧节点

主节点操作

guoguo:PRIMARY> rs.remove("192.168.1.32:27017")
{ "ok" : 1 }

查看下线节点终端

[root@mdb2 ~]# /data/mongodb/bin/mongo 192.168.1.32:27017
guoguo:OTHER> 

#退出 可以直接去关闭这个节点了
[root@mdb2 ~]# /data/mongodb/bin/mongo localhost:27017
guoguo:OTHER> use admin
switched to db admin
guoguo:OTHER> db.shutdownServer()

1.14 增加仲裁节点

官网地址

https://docs.mongodb.com/manual/tutorial/add-replica-set-arbiter/

Arbiter节点只参与投票,不能被选为Primary,并且不从Primary同步数据。

他的作用就好比,我们有10台机器,但是呢集群是要奇数,这样就可以在找一台性能差的机器加个仲裁节点,凑个奇数就可以了

上面把192.168.1.32:27017 给剔除副本集了,那么就用它来做仲裁节点

清空数据

[root@mdb2 data]# rm -rf /data/mongodbdata/*

启动

[root@mdb2 data]# /data/mongodb/bin/mongod -f /data/mongodb/conf/mongodb.conf

登陆

[root@mdb2 data]# /data/mongodb/bin/mongod -f /data/mongodb/conf/mongodb.conf

切换主节点,将192.168.1.32:27017 加到仲裁节点

cfg = rs.conf();
#获取当前复制集群配置

#添加仲裁节点  向 cfg.members 添加一个仲裁节点配置,注意 arbiterOnly 应设置为 true:
cfg.members.push({
    _id: 1,  // 节点 ID,确保唯一
    host: "192.168.1.32:27017", // 仲裁节点的 IP 和端口
    arbiterOnly: true
});

#重新应用配置  使用以下命令更新复制集配置: 
rs.reconfig(cfg);

查看仲裁节点状态

> 
guoguo:ARBITER>

升级步骤

升级只是升级命令而已,修改软连接而已

1.首先确保是副本集状态

2.先关闭1 个副本节点 

3.检测数据是否可以升级

4.升级副本节点的可执行文件

5.更新配置文件

6.启动升级后的副本节点

7.确保集群工作正常

8.滚动升级其他副本节点

9.最后主节点降级

10.确保集群 可用

11.关闭降级的老的主节点

12.升级老的主节点

13.重新加入集群

mongodb不会自己主动回收磁盘空间,他会一直增长,比如数据为10G,我删除了8个G,按照正常思维来说,会给我焖空余8个G出来,但是mongodb不会,mongodb一直增长不会收缩,

但是我想释放空间,怎么办?

滚动方式
首先把一个从节点停掉,然后把数据目录清空,然后再从新加入副本集,这时候有多少数据就给你同步多少数据,这样就不会有空余的占用了,然后逐步这样操作就能释放空间。