MongoDB 副本集管理完全指南
一、单机模式启动成员
1.1 基础启动语法
javascript
// 基础启动命令(Linux/Mac)
mongod --dbpath /data/db --port 27017 --logpath /var/log/mongodb.log --fork
// Windows 环境
mongod --dbpath C:\data\db --port 27017 --logpath C:\data\log\mongodb.log
1.2 单机模式完整配置示例
javascript
// 创建配置文件 single-instance.conf
// 配置文件路径:/etc/mongod.conf
systemLog:
destination: file
path: "/var/log/mongodb/mongod.log" # 日志文件路径
logAppend: true # 追加模式写入日志
logRotate: rename # 日志轮转方式
storage:
dbPath: "/data/mongodb" # 数据存储目录
directoryPerDB: true # 每个数据库独立目录
journal:
enabled: true # 启用日记功能
commitIntervalMs: 100 # 日记提交间隔(毫秒)
wiredTiger:
engineConfig:
cacheSizeGB: 1 # WiredTiger缓存大小
journalCompressor: snappy # 日记压缩算法
net:
port: 27017 # 监听端口
bindIp: 127.0.0.1,192.168.1.100 # 绑定IP地址
maxIncomingConnections: 65536 # 最大连接数
processManagement:
fork: true # 后台运行进程
pidFilePath: "/var/run/mongod.pid" # PID文件位置
security:
authorization: disabled # 暂不启用认证
1.3 启动与验证
bash
# 使用配置文件启动
mongod --config /etc/mongod.conf
# 验证启动状态
ps aux | grep mongod
netstat -tlnp | grep 27017
# 连接测试
mongo --host 127.0.0.1 --port 27017
二、副本集配置
2.1 副本集配置文件示例
javascript
// 副本集成员1配置文件 rs1.conf
// 路径:/etc/mongod_rs1.conf
systemLog:
destination: file
path: "/var/log/mongodb/rs1.log"
logAppend: true
storage:
dbPath: "/data/mongodb/rs1"
journal:
enabled: true
net:
port: 27017
bindIp: 127.0.0.1,192.168.1.101
replication:
replSetName: "myReplicaSet" # 副本集名称
oplogSizeMB: 2048 # opLog大小(MB)
enableMajorityReadConcern: true # 启用多数读关注
processManagement:
fork: true
pidFilePath: "/var/run/mongod_rs1.pid"
2.2 初始化副本集
javascript
// 连接到任意成员
mongo --host 192.168.1.101 --port 27017
// 执行初始化配置
rs.initiate({
_id: "myReplicaSet", // 副本集名称,必须与配置文件一致
version: 1, // 配置版本号
members: [ // 成员列表
{
_id: 0, // 成员ID,唯一标识
host: "192.168.1.101:27017", // 成员地址
priority: 2, // 优先级(0-1000),越高越可能成为Primary
votes: 1, // 投票权,1表示有投票权
arbiterOnly: false, // 是否为仲裁节点
hidden: false, // 是否隐藏节点
buildIndexes: true, // 是否创建索引
slaveDelay: 0, // 从节点延迟时间(秒)
tags: { "dc": "beijing", "role": "primary" } // 标签,用于读写分离
},
{
_id: 1,
host: "192.168.1.102:27017",
priority: 1,
votes: 1,
arbiterOnly: false,
tags: { "dc": "beijing", "role": "secondary" }
},
{
_id: 2,
host: "192.168.1.103:27017",
priority: 1,
votes: 1,
tags: { "dc": "shanghai", "role": "secondary" }
}
],
settings: {
heartbeatTimeoutSecs: 10, // 心跳超时时间(秒)
electionTimeoutMillis: 10000, // 选举超时时间(毫秒)
catchUpTimeoutMillis: 2000, // 追赶超时时间(毫秒)
getLastErrorModes: { // 自定义写关注模式
"multiDC": { "dc": 2 } // 至少两个数据中心确认
},
getLastErrorDefaults: { // 默认写关注
w: "majority", // 多数成员确认
wtimeout: 5000 // 写超时时间(毫秒)
}
}
})
// 查看副本集状态
rs.status()
// 输出示例:
// {
// "set": "myReplicaSet",
// "date": ISODate("2024-01-15T10:30:00Z"),
// "myState": 1, // 1=Primary, 2=Secondary
// "members": [
// {
// "_id": 0,
// "name": "192.168.1.101:27017",
// "state": 1, // 1=PRIMARY
// "stateStr": "PRIMARY",
// "uptime": 3600,
// "optime": { "ts": Timestamp(1705314600, 1) }
// }
// ]
// }
2.3 添加新成员
javascript
// 方法1:使用rs.add()
rs.add({
host: "192.168.1.104:27017",
priority: 0.5, // 较低优先级
votes: 1,
hidden: true, // 隐藏节点
slaveDelay: 3600 // 延迟1小时
})
// 方法2:重新配置副本集
var config = rs.conf()
config.members.push({
_id: 3,
host: "192.168.1.104:27017",
priority: 0.5
})
rs.reconfig(config)
// 删除成员
rs.remove("192.168.1.104:27017")
三、控制成员状态
3.1 成员状态切换命令
javascript
// 1. 将Primary降级为Secondary
// 在Primary节点执行
rs.stepDown(60) // 降级60秒,期间不能成为Primary
// 2. 强制重新选举
rs.stepDown(0) // 立即降级并触发选举
// 3. 冻结节点,防止成为Primary
// 在Secondary节点执行
rs.freeze(300) // 冻结300秒,期间不能成为Primary
// 4. 解冻节点
rs.freeze(0)
// 5. 使节点进入维护模式
// 先在Secondary节点执行
db.adminCommand({ replSetMaintenance: true })
// 退出维护模式
db.adminCommand({ replSetMaintenance: false })
// 6. 重置副本集配置
rs.reconfig(config, { force: true }) // 强制重新配置,用于故障恢复
3.2 读写分离配置
javascript
// 1. 设置读偏好(在客户端连接时)
// 使用Primary读(默认)
db.getMongo().setReadPref("primary")
// 使用Secondary读
db.getMongo().setReadPref("secondary")
// 使用标签选择Secondary
db.getMongo().setReadPref("secondary", [
{ "dc": "beijing", "role": "secondary" }
])
// 2. 设置写关注(在写入操作时)
db.users.insert(
{ name: "张三", age: 25 },
{ writeConcern: { w: "majority", wtimeout: 5000 } }
)
// 3. 自定义写关注模式
// 配置副本集时添加自定义模式
rs.conf().settings.getLastErrorModes = {
"majorityDC": { "dc": 2 } // 要求至少两个数据中心确认
}
// 使用自定义写关注
db.users.insert(
{ name: "李四", age: 30 },
{ writeConcern: { w: "majorityDC", wtimeout: 3000 } }
)
3.3 节点优先级调整
javascript
// 查看当前配置
var cfg = rs.conf()
// 修改节点优先级
cfg.members[0].priority = 3 // 提高优先级
cfg.members[1].priority = 0 // 永不成为Primary
cfg.members[2].priority = 1 // 正常优先级
// 应用新配置
rs.reconfig(cfg)
// 设置为仲裁节点
cfg.members[2].arbiterOnly = true
cfg.members[2].priority = 0
rs.reconfig(cfg)
四、监控复制
4.1 复制状态监控命令
javascript
// 1. 查看副本集整体状态
rs.status()
// 关键字段说明:
// - members[].state: 成员状态码
// - members[].optime: 最后操作时间戳
// - members[].pingMs: 网络延迟(毫秒)
// 2. 查看复制延迟
rs.printSecondaryReplicationInfo()
// 输出示例:
// source: 192.168.1.102:27017
// syncedTo: Thu Jan 15 2024 10:30:05 GMT+0800
// replLag: 0 secs
// 3. 查看opLog信息
use local
db.oplog.rs.find().sort({$natural: -1}).limit(5)
db.oplog.rs.stats()
// 4. 查看opLog大小和可用空间
db.getReplicationInfo()
// 输出:
// {
// "logSizeMB": 2048,
// "usedMB": 1024,
// "timeDiff": 86400,
// "timeDiffHours": 24,
// "tFirst": "Thu Jan 14 2024 10:30:00",
// "tLast": "Thu Jan 15 2024 10:30:00",
// "now": "Thu Jan 15 2024 10:30:05"
// }
4.2 性能监控
javascript
// 1. 查看当前操作
db.currentOp()
// 过滤复制相关操作
db.currentOp({ "op": "query", "ns": "local.oplog.rs" })
// 2. 查看服务器状态
db.serverStatus()
// 复制相关指标
db.serverStatus().repl
// 输出示例:
// {
// "setName": "myReplicaSet",
// "ismaster": true,
// "secondary": false,
// "hosts": ["192.168.1.101:27017", "192.168.1.102:27017"],
// "optimes": {
// "appliedOpTime": { "ts": Timestamp(1705314600, 1) },
// "durableOpTime": { "ts": Timestamp(1705314600, 1) }
// }
// }
// 3. 查看复制延迟详细统计
db.adminCommand({ replSetGetStatus: 1 })
// 计算延迟
var status = db.adminCommand({ replSetGetStatus: 1 })
status.members.forEach(function(member) {
if (member.state === 2) { // Secondary节点
var lag = status.members[0].optime.ts.t - member.optime.ts.t
print(member.name + " 延迟: " + lag + " 秒")
}
})
4.3 监控脚本示例
javascript
// 创建监控脚本 monitor_replication.js
// 定期检查复制状态并告警
var checkReplicationLag = function(thresholdSeconds) {
var status = rs.status()
var primary = null
var secondaries = []
// 找出Primary和Secondary节点
status.members.forEach(function(member) {
if (member.state === 1) {
primary = member
} else if (member.state === 2) {
secondaries.push(member)
}
})
if (!primary) {
print("ERROR: 没有Primary节点!")
return false
}
var hasLag = false
secondaries.forEach(function(secondary) {
var lag = Math.abs(primary.optime.ts.t - secondary.optime.ts.t)
if (lag > thresholdSeconds) {
print("WARNING: " + secondary.name + " 复制延迟 " + lag + " 秒")
hasLag = true
} else {
print("INFO: " + secondary.name + " 复制延迟 " + lag + " 秒")
}
})
return !hasLag
}
// 检查opLog使用率
var checkOplogUsage = function(thresholdPercent) {
var info = db.getReplicationInfo()
var usagePercent = (info.usedMB / info.logSizeMB) * 100
print("opLog使用率: " + usagePercent.toFixed(2) + "%")
if (usagePercent > thresholdPercent) {
print("WARNING: opLog使用率超过阈值!")
return false
}
return true
}
// 执行监控
var lagOk = checkReplicationLag(10) // 延迟超过10秒告警
var oplogOk = checkOplogUsage(80) // opLog使用率超过80%告警
if (!lagOk || !oplogOk) {
// 可在此添加发送告警邮件的代码
print("需要人工介入检查!")
}
4.4 复制性能优化
javascript
// 1. 调整opLog大小
// 方法:重新配置副本集(需要停机维护)
cfg = rs.conf()
cfg.members[0].priority = 0
rs.reconfig(cfg)
// 停止节点,修改oplogSizeMB配置
// 启动节点,重新加入副本集
// 2. 使用流控机制
// 查看流控状态
db.adminCommand({ getParameter: 1, "flowControl": 1 })
// 设置流控阈值
db.adminCommand({
setParameter: 1,
flowControlTargetLagSeconds: 10 // 目标延迟10秒
})
// 3. 优化网络延迟
// 查看节点间网络延迟
rs.status().members.forEach(function(m) {
print(m.name + " pingMs: " + m.pingMs)
})
五、故障恢复实战案例
5.1 主节点故障自动切换
javascript
// 模拟Primary故障(在Primary节点执行)
use admin
db.shutdownServer()
// 在Secondary节点观察选举过程
rs.status()
// 会自动选举新的Primary,通常在10-30秒内完成
// 恢复故障节点
mongod --config /etc/mongod_rs1.conf
// 故障节点会自动同步数据并重新加入
5.2 手动故障转移
javascript
// 场景:需要维护Primary节点
// 1. 连接当前Primary节点
rs.stepDown(120) // 降级120秒
// 2. 等待选举完成(约10秒)
rs.status() // 确认新的Primary产生
// 3. 原Primary变为Secondary后可进行维护
// 4. 维护完成后自动恢复
rs.freeze(0) // 解冻节点,允许重新成为Primary
5.3 数据恢复案例
javascript
// 场景:误删除数据,从延迟节点恢复
// 1. 找到延迟节点(slaveDelay配置)
rs.conf().members.forEach(function(m) {
if (m.slaveDelay > 0) {
print("延迟节点: " + m.host + " 延迟 " + m.slaveDelay + " 秒")
}
})
// 2. 临时提升延迟节点为Primary
var cfg = rs.conf()
cfg.members[0].priority = 0 // 降低原Primary优先级
cfg.members[2].priority = 5 // 提高延迟节点优先级
rs.reconfig(cfg)
// 3. 从延迟节点导出数据
mongodump --host 192.168.1.103 --port 27017 --db mydb --out /backup/
// 4. 恢复数据到Primary
mongorestore --host 192.168.1.101 --port 27017 /backup/mydb
// 5. 恢复原始配置
rs.reconfig(originalCfg)
六、最佳实践建议
6.1 生产环境配置模板
yaml
# production-replica.conf
systemLog:
destination: file
path: "/var/log/mongodb/mongod.log"
logAppend: true
logRotate: reopen
storage:
dbPath: "/data/mongodb"
journal:
enabled: true
commitIntervalMs: 100
wiredTiger:
engineConfig:
cacheSizeGB: 4 # 根据内存调整,通常为内存的60%
directoryForIndexes: true
collectionConfig:
blockCompressor: snappy
indexConfig:
prefixCompression: true
net:
port: 27017
bindIp: 0.0.0.0 # 生产环境建议指定具体IP
tls:
mode: requireTLS
certificateKeyFile: "/etc/ssl/mongodb.pem"
replication:
replSetName: "prodReplicaSet"
oplogSizeMB: 10240 # 10GB,根据业务调整
enableMajorityReadConcern: true
security:
keyFile: "/etc/mongodb/keyfile" # 副本集认证密钥
authorization: enabled
clusterAuthMode: keyFile
processManagement:
fork: true
pidFilePath: "/var/run/mongod.pid"
6.2 日常维护检查清单
javascript
// 健康检查脚本 health_check.js
var healthCheck = {
// 检查所有节点状态
checkStatus: function() {
var status = rs.status()
var healthy = true
status.members.forEach(function(m) {
if (m.health !== 1) {
print("ERROR: " + m.name + " 不健康")
healthy = false
}
if (m.state === 8) { // 8 = DOWN
print("ERROR: " + m.name + " 已宕机")
healthy = false
}
})
return healthy
},
// 检查复制延迟
checkLag: function(maxLag) {
var status = rs.status()
var primary = status.members.find(m => m.state === 1)
if (!primary) return false
var maxLagFound = 0
status.members.forEach(function(m) {
if (m.state === 2) {
var lag = primary.optime.ts.t - m.optime.ts.t
maxLagFound = Math.max(maxLagFound, lag)
if (lag > maxLag) {
print("WARNING: " + m.name + " 延迟 " + lag + " 秒")
}
}
})
return maxLagFound <= maxLag
},
// 检查opLog使用率
checkOplog: function(maxUsage) {
var info = db.getReplicationInfo()
var usage = (info.usedMB / info.logSizeMB) * 100
if (usage > maxUsage) {
print("WARNING: opLog使用率 " + usage + "%")
return false
}
return true
}
}
// 执行检查
print("=== MongoDB副本集健康检查 ===")
print("状态检查: " + (healthCheck.checkStatus() ? "OK" : "FAIL"))
print("延迟检查: " + (healthCheck.checkLag(10) ? "OK" : "FAIL"))
print("opLog检查: " + (healthCheck.checkOplog(80) ? "OK" : "FAIL"))
以上内容涵盖了MongoDB副本集管理的核心知识点,包含完整的配置语法、操作命令和实战案例。所有代码都经过详细注释,可直接用于生产环境参考。建议根据实际业务场景调整配置参数和监控阈值。