MongoDB入门学习教程,从入门到精通,MongoDB 副本集管理完全指南(13)

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副本集管理的核心知识点,包含完整的配置语法、操作命令和实战案例。所有代码都经过详细注释,可直接用于生产环境参考。建议根据实际业务场景调整配置参数和监控阈值。

相关推荐
m0_7411733317 分钟前
如何处理SQL中的NULL值_使用ISNULL或COALESCE函数
jvm·数据库·python
志栋智能32 分钟前
超自动化巡检:解锁运维数据的深层价值
运维·服务器·数据库·自动化
m0_3801138438 分钟前
补单系统搭建及源码分享
数据库·spring boot·mybatis
步辞43 分钟前
css伪类选择器-nth-child应用技巧_循环选择列表或表格行的实现方法
jvm·数据库·python
Joseph Cooper1 小时前
STM32MP157 Linux驱动学习笔记(四):典型总线与设备模型(SPI/USB)
linux·stm32·学习
阿丰资源1 小时前
基于SpringBoot+MySQL的社区团购系统设计与实现(附源码+文档+数据库,直接运行)
数据库·spring boot·mysql
2401_827499992 小时前
数据分析学习05(黑马)-Pandas
学习·数据分析·pandas
2301_803875612 小时前
Python怎么计算NumPy数组的切比雪夫距离_使用abs与max求解
jvm·数据库·python
还是阿落呀2 小时前
第二章 数据类型、表的约束
数据库·mysql
希望永不加班2 小时前
SpringBoot 数据库索引优化:慢查询分析
java·数据库·spring boot·后端·spring