副本集-Replica Sets
MongoDB中的副本集(Replica Set)是一组维护相同数据集的mongod服务。 副本集可提供冗余和高可用性,是所有生产部署的基础。也可以说,副本集类似于有自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异步同步,从而使多台机器拥有同一数据的多个副本,并且当主库当掉时在不需要用户干预的情况下自动切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。



副本集角色介绍
副本集有两种类型三种角色
两种类型:
主节点(Primary)类型:数据操作的主要连接点,可读写。
次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举。
三种角色:
主要成员(Primary):主要接收所有写操作。就是主节点。
副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型。
仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。

搭建一主一副本一仲裁
前置
mongodb搭建不需要很多机器,也不需要下载很多遍软件,只需要在启动命令指定对应的conf文件,以及在每个配置文件都设置好对应的db目录和log目录。
博主已经下载好mongodb-linux-x86_64-4.0.10.tgz,并且已经解压并mv mongodb-linux-x86_64-4.0.10 /usr/local/mongodb移动到对应的文件,这样就可以用/usr/local/mongodb/bin/mongod -f /你自己配置文件的地址/ 来启动服务了。
开始搭建
# 主
mkdir -p /mongodb/replica_sets/myrs_27017/log \ &
mkdir -p /mongodb/replica_sets/myrs_27017/data/db
# 副本
mkdir -p /mongodb/replica_sets/myrs_27018/log \ &
mkdir -p /mongodb/replica_sets/myrs_27018/data/db
# 仲裁
mkdir -p /mongodb/replica_sets/myrs_27019/log \ &
mkdir -p /mongodb/replica_sets/myrs_27019/data/db
vim /mongodb/replica_sets/myrs_27017/mongod.conf
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/mongodb/replica_sets/myrs_27017/log/mongod.log"
# 当mongos或mongod实例重新启动时,会将新条目附加到现有日志文件的末尾
logAppend: true
storage:
# mongod实例存储其数据的目录,默认值为"/data/db"
dbPath: "/mongodb/replica_sets/myrs_27017/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式
fork: true
pidFilePath: "/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:
# 服务实例绑定的IP,默认是localhost
bindIp: "0.0.0.0"
# 绑定的端口,默认是27017
port: 27017
replication:
replSetName: myrs
vim /mongodb/replica_sets/myrs_27018/mongod.conf
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/mongodb/replica_sets/myrs_27018/log/mongod.log"
# 当mongos或mongod实例重新启动时,会将新条目附加到现有日志文件的末尾
logAppend: true
storage:
# mongod实例存储其数据的目录,默认值为"/data/db"
dbPath: "/mongodb/replica_sets/myrs_27018/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式
fork: true
pidFilePath: "/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:
# 服务实例绑定的IP,默认是localhost
bindIp: "0.0.0.0"
# 绑定的端口,默认是27017
port: 27018
replication:
replSetName: myrs
vim /mongodb/replica_sets/myrs_27019/mongod.conf
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/mongodb/replica_sets/myrs_27019/log/mongod.log"
# 当mongos或mongod实例重新启动时,会将新条目附加到现有日志文件的末尾
logAppend: true
storage:
# mongod实例存储其数据的目录,默认值为"/data/db"
dbPath: "/mongodb/replica_sets/myrs_27019/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式
fork: true
pidFilePath: "/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:
# 服务实例绑定的IP,默认是localhost
bindIp: "0.0.0.0"
# 绑定的端口,默认是27017
port: 27019
replication:
replSetName: myrs
启动
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf
初始化配置副本集和主节点
连接和初始化
这个集群不是搭建好就能用的,还需要连接上去做配置
/usr/local/mongodb/bin/mongo --port=27017
# 连接上之后,很多命令都不能使用,比如,show dbs等,必须初始化
# 初始化
rs.initiate()
1)"ok"的值为1,说明创建成功。
2)命令行提示符发生变化,变成了一个从节点角色,此时默认不能读写。稍等片刻,回车,变成主节点。
# 查看当前副本集的配置内容
rs.conf()
rs.config()
{
"_id" : "myrs",
"version" : 1,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "VM-109-112-tencentos: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" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("687792d02d18d0cf71477f3f")
}
}
说明:
1)"_id" : "myrs":副本集的配置数据存储的主键值,默认就是副本集的名字
2)"members":副本集成员数组,此时只有一个:"host" : "180.76.159.126:27017",该成员不
是仲裁节点:"arbiterOnly" : false,优先级(权重值):"priority" : 1,
3)"settings":副本集的参数配置。
提示:副本集配置的查看命令,本质是查询的是 system.replset的表中的数据:
use local
show collections
db.system.replset.find()
{ "_id" : "myrs", "version" : 1, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "VM-109-112-tencentos: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" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("687792d02d18d0cf71477f3f") } }
查看集群状态
rs.status()
{
"set" : "myrs",
"date" : ISODate("2025-07-16T11:58:32.762Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1752667104, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1752667104, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1752667104, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1752667104, 1),
"t" : NumberLong(1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1752667074, 1),
"members" : [
{
"_id" : 0,
"name" : "VM-109-112-tencentos:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 327,
"optime" : {
"ts" : Timestamp(1752667104, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2025-07-16T11:58:24Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1752666832, 2),
"electionDate" : ISODate("2025-07-16T11:53:52Z"),
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
}
],
"ok" : 1,
"operationTime" : Timestamp(1752667104, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1752667104, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
说明:
1)"set" : "myrs":副本集的名字
2)"myState": 1:说明状态正常
3)"members":副本集成员数组,此时只有一个:"name" :"VM-109-112-tencentos",该成员的
角色是"stateStr" : "PRIMARY",该节点是健康的:"health" : 1。
添加从节点

rs.add("21.91.109.112:27018")
{
"ok" : 1,
"operationTime" : Timestamp(1752667344, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1752667344, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
1)"ok" : 1:说明添加成功。
这样添加的是副本节点,添加仲裁节点看下边
添加仲裁节点
rs.add("21.91.109.112:27019",arbiterOnly)
或者
rs.addArb("21.91.109.112:27019")
{
"ok" : 1,
"operationTime" : Timestamp(1752667477, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1752667477, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
这样运行完之后就搭建完成了,可以通过rs.status()命令来查看集群状态或者rs.config()来查看集群的配置信息。
副本集的数据操作
登陆主节点,对主节点进行插入数据。
/usr/local/mongodb/bin/mongo --port 27017
use articledb
switched to db articledb
myrs:PRIMARY> db
articledb
db.comment.insert({
"articleid": "100000",
"content": "今天天气真好,阳光\n明媚",
"userid": "1001",
"nickname": "Rose",
"createdatetime": new Date()
});
然后登陆从节点,尝试查看或插入数据
/usr/local/mongodb/bin/mongo --port 27018
show dbs
2025-07-17T10:02:51.190+0800 E QUERY [js] Error: listDatabases failed:{
"operationTime" : Timestamp(1752717765, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1752717765, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:139:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
发现,不能读取集合的数据。当前从节点只是一个备份,不是奴隶节点,无法读取数据,写当然更不行。
因为默认情况下,从节点是没有读写权限的,可以增加读的权限,但需要进行设置。
rs.slaveOk()
或
rs.slaveOk(true)
该命令是 db.getMongo().setSlaveOk()的简化命令。
此时执行查询命令,成功。
此时在从节点进行插入,发现失败
db.comment.insert({
"_id": "1",
"articleid": "100001",
"content": "我们\n不应该把清晨浪费在手机上,健康很重要,k一杯温水幸福你我\n他。",
"userid": "1002",
"nickname": "相忘于江湖",
"createdatetime": new Date("2019-08-05T22:08:15.522Z"),
"likenum": NumberInt(1000),
"state": "1"
});
WriteCommandError({
"operationTime" : Timestamp(1752718015, 1),
"ok" : 0,
"errmsg" : "not master",
"code" : 10107,
"codeName" : "NotMaster",
"$clusterTime" : {
"clusterTime" : Timestamp(1752718015, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
})
现在可实现了读写分离,让主插入数据,让从来读取数据。
如果要取消作为奴隶节点的读权限:
rs.slaveOk(false)
仲裁者节点,不存放任何业务数据的,可以登录查看
/usr/local/mongodb/bin/mongo --port 27019
