
副本集配置
官方文档
https://docs.mongodb.com/manual/tutorial/deploy-replica-set/1.1副本级介绍
两种集群:一种是分片,一种是副本级的
副本集的组成
MongoDB 副本集由一组节点组成,其中包括以下角色:
1. 主节点(Primary):
• 唯一能接收写操作的节点。
• 所有写操作都会记录到主节点的 oplog(操作日志) 中,并同步到从节点。
2. 从节点(Secondary):
• 从主节点复制数据,并维持与主节点一致的状态。
• 可以通过配置允许从节点响应读请求(即读偏好设置)。
3. 仲裁节点(Arbiter):
• 不存储数据,仅参与选举以决定新的主节点。
• 通常在节点数为偶数时加入,以防止选举时票数平分。1.2工作原理



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/mongodbdata1.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 为只同步节点
01.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一直增长不会收缩,
但是我想释放空间,怎么办?
滚动方式
首先把一个从节点停掉,然后把数据目录清空,然后再从新加入副本集,这时候有多少数据就给你同步多少数据,这样就不会有空余的占用了,然后逐步这样操作就能释放空间。
















