副本集(Replica Set)是MongoDB的高可用解决方案,通过数据冗余和自动故障转移保证服务的持续可用性。
副本集包含三种节点:
1. Primary(主节点)
- 接收所有写操作
- 记录操作日志(oplog)
- 只能有一个主节点
2. Secondary(从节点)
- 复制主节点的oplog
- 可以处理读请求(需配置)
- 可以有多个从节点
3. Arbiter(仲裁节点)
- 不存储数据
- 只参与选举投票
- 用于打破偶数节点的平局
// 1. 启动三个MongoDB实例
mongod --replSet rs0 --port 27017 --dbpath /data/db1
mongod --replSet rs0 --port 27018 --dbpath /data/db2
mongod --replSet rs0 --port 27019 --dbpath /data/db3
// 2. 连接到第一个实例
mongosh --port 27017
// 3. 初始化副本集
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
})
// 4. 查看副本集状态
rs.status()
// 查看副本集配置
rs.conf()
// 查看副本集状态
rs.status()
// 查看当前节点是否为主节点
rs.isMaster()
// 添加节点
rs.add("localhost:27020")
// 添加仲裁节点
rs.addArb("localhost:27021")
// 删除节点
rs.remove("localhost:27020")
// 查看oplog信息
rs.printReplicationInfo()
// 查看从节点同步状态
rs.printSecondaryReplicationInfo()
// 设置节点优先级(0-1000,默认1)
// 优先级越高,越容易成为主节点
// 优先级为0的节点永远不会成为主节点
cfg = rs.conf()
cfg.members[0].priority = 2 // 高优先级
cfg.members[1].priority = 1 // 默认优先级
cfg.members[2].priority = 0 // 永不成为主节点
rs.reconfig(cfg)
// 隐藏节点不会被客户端发现,用于备份或分析
cfg = rs.conf()
cfg.members[2].priority = 0
cfg.members[2].hidden = true
rs.reconfig(cfg)
// 延迟节点用于数据恢复(防止误删除)
cfg = rs.conf()
cfg.members[2].priority = 0
cfg.members[2].hidden = true
cfg.members[2].secondaryDelaySecs = 3600 // 延迟1小时
rs.reconfig(cfg)
// primary(默认):只从主节点读
db.users.find().readPref("primary")
// primaryPreferred:优先主节点,主节点不可用时从从节点读
db.users.find().readPref("primaryPreferred")
// secondary:只从从节点读
db.users.find().readPref("secondary")
// secondaryPreferred:优先从节点,从节点不可用时从主节点读
db.users.find().readPref("secondaryPreferred")
// nearest:从延迟最低的节点读
db.users.find().readPref("nearest")
// w: 1(默认):写入主节点即返回
db.users.insertOne(
{ name: "张三" },
{ writeConcern: { w: 1 } }
)
// w: "majority":写入大多数节点后返回(推荐)
db.users.insertOne(
{ name: "张三" },
{ writeConcern: { w: "majority" } }
)
// w: 2:写入2个节点后返回
db.users.insertOne(
{ name: "张三" },
{ writeConcern: { w: 2 } }
)
// j: true:写入日志后返回
db.users.insertOne(
{ name: "张三" },
{ writeConcern: { w: 1, j: true } }
)
// local(默认):读取本地最新数据
db.users.find().readConcern("local")
// majority:读取已被大多数节点确认的数据
db.users.find().readConcern("majority")
// linearizable:线性一致性读(最强一致性)
db.users.find().readConcern("linearizable")
// 当主节点故障时:
// 1. 从节点检测到主节点心跳超时(默认10秒)
// 2. 发起选举
// 3. 获得多数投票的节点成为新主节点
// 4. 整个过程通常在10-30秒内完成
// 手动触发选举(主节点降级)
rs.stepDown(60) // 60秒内不参与选举
// 强制重新配置(紧急情况)
cfg = rs.conf()
cfg.version++
rs.reconfig(cfg, { force: true })
// Oplog是一个固定大小的集合,记录所有写操作
// 从节点通过复制oplog来同步数据
// 查看oplog大小
use local
db.oplog.rs.stats()
// 查看oplog中的操作
db.oplog.rs.find().sort({ $natural: -1 }).limit(10)
// 调整oplog大小(需要重启)
mongod --replSet rs0 --oplogSize 2048 // 2GB
// 查看副本集健康状态
rs.status().members.forEach(m => {
print(`${m.name}: ${m.stateStr}, health: ${m.health}`)
})
// 查看复制延迟
rs.printSecondaryReplicationInfo()
// 查看oplog窗口
rs.printReplicationInfo()
// 监控关键指标:
// - 复制延迟(replication lag)
// - oplog窗口大小
// - 节点健康状态
// - 选举次数
// 生产环境推荐配置:3节点副本集
// 节点1:主节点(高配置服务器)
// 节点2:从节点(高配置服务器)
// 节点3:从节点(普通配置服务器)
// 初始化配置
rs.initiate({
_id: "prod-rs",
members: [
{
_id: 0,
host: "mongo1.example.com:27017",
priority: 2
},
{
_id: 1,
host: "mongo2.example.com:27017",
priority: 1
},
{
_id: 2,
host: "mongo3.example.com:27017",
priority: 1
}
]
})
// 应用连接字符串
mongodb://mongo1.example.com:27017,mongo2.example.com:27017,mongo3.example.com:27017/?replicaSet=prod-rs&readPreference=secondaryPreferred&w=majority