MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

MongoDB副本集成员变更操作指南

2023-09-232.8k 阅读

一、MongoDB 副本集简介

MongoDB 副本集是由一组 MongoDB 实例组成的集群,其中包含一个主节点(Primary)和多个从节点(Secondary)。副本集的主要作用是提供数据冗余、高可用性和灾难恢复能力。在副本集中,主节点负责处理所有的写操作,而从节点则复制主节点的数据,并可以处理读操作。如果主节点发生故障,副本集将会自动选举一个从节点成为新的主节点,从而确保服务的连续性。

二、副本集成员类型

  1. 主节点(Primary)
    • 负责处理所有的写操作和大部分的读操作(除非配置了读偏好,让读操作分发到从节点)。
    • 主节点会将写操作记录在 oplog(操作日志)中,从节点通过复制 oplog 来保持数据的一致性。
  2. 从节点(Secondary)
    • 从节点复制主节点的 oplog,并应用其中的操作来保持与主节点的数据同步。
    • 从节点可以配置为处理读操作,这有助于分担主节点的负载,特别是在读取密集型的应用场景中。
  3. 仲裁节点(Arbiter)
    • 仲裁节点不存储数据,其主要作用是参与选举过程。
    • 仲裁节点通过投票来决定哪个从节点将成为新的主节点。在副本集中,仲裁节点的数量通常为奇数个,以避免在选举过程中出现平局的情况。

三、添加副本集成员

  1. 准备新节点
    • 首先,确保新节点安装了与现有副本集成员相同版本的 MongoDB。可以从 MongoDB 官方网站下载并按照官方文档进行安装。
    • 配置新节点的 mongod.conf 文件。例如,假设新节点的 IP 地址为 192.168.1.100,端口为 27017,配置文件内容如下:
systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true
storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
net:
  port: 27017
  bindIp: 192.168.1.100
replication:
  replSetName: myReplSet
  • 上述配置文件中,replSetName 必须与现有副本集的名称一致。
  1. 启动新节点
    • 在新节点上执行以下命令启动 MongoDB 服务:
sudo systemctl start mongod
  1. 连接到现有副本集主节点
    • 使用 mongo 命令行工具连接到现有副本集的主节点:
mongo --host <primary_host> --port <primary_port>
  • 例如,如果主节点的 IP 地址为 192.168.1.101,端口为 27017,则命令为:
mongo --host 192.168.1.101 --port 27017
  1. 添加新成员
    • 在连接到主节点的 mongo shell 中,使用 rs.add() 方法添加新成员。例如,添加之前准备的新节点 192.168.1.100:27017
rs.add("192.168.1.100:27017");
  • 如果添加成功,会看到类似如下的输出:
{ "ok" : 1, "operationTime" : Timestamp(1661601471, 1), "$clusterTime" : { "clusterTime" : Timestamp(1661601471, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : 0 } } }
  • 如果新节点是一个优先级较低的节点,例如希望其作为一个隐藏节点(不参与读操作且优先级较低),可以使用更详细的配置方式:
rs.add({
  host: "192.168.1.100:27017",
  priority: 0,
  hidden: true
});
  • 上述配置中,priority 表示节点的优先级,取值范围是 0 到 1000,0 表示不参与选举,1 是默认优先级;hidden 表示该节点是否为隐藏节点,设置为 true 时,应用程序不会自动将读操作路由到该节点。

四、移除副本集成员

  1. 确认移除成员的状态
    • 在移除副本集成员之前,需要确认其状态。连接到副本集主节点,使用 rs.status() 命令查看副本集状态。例如:
rs.status();
  • 从输出结果中找到要移除的成员的 _idname 等信息。例如,输出结果中的某个成员部分如下:
{
  "_id" : 2,
  "name" : "192.168.1.102:27017",
  "health" : 1,
  "state" : 2,
  "stateStr" : "SECONDARY",
  "uptime" : 1234,
  "optime" : {
    "ts" : Timestamp(1661601471, 1),
    "t" : 1
  },
  "optimeDate" : ISODate("2022-08-27T12:37:51Z"),
  "lastHeartbeat" : ISODate("2022-08-27T12:37:52Z"),
  "lastHeartbeatRecv" : ISODate("2022-08-27T12:37:52Z"),
  "pingMs" : NumberLong(0),
  "syncingTo" : "192.168.1.101:27017",
  "configVersion" : 1
}
  • 这里 _id 为 2,name192.168.1.102:27017,如果要移除这个成员,需要用到这些信息。
  1. 移除成员
    • 使用 rs.remove() 方法移除成员。例如,移除上述 _id 为 2 的成员:
rs.remove(2);
  • 也可以通过节点名称移除,例如:
rs.remove("192.168.1.102:27017");
  • 如果移除成功,会看到类似如下的输出:
{ "ok" : 1, "operationTime" : Timestamp(1661601471, 1), "$clusterTime" : { "clusterTime" : Timestamp(1661601471, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : 0 } } }
  1. 停止并清理移除的节点
    • 在移除的节点上,执行以下命令停止 MongoDB 服务:
sudo systemctl stop mongod
  • 可以选择清理该节点的数据目录(/var/lib/mongodb 按照之前的配置),以释放磁盘空间:
sudo rm -rf /var/lib/mongodb

五、提升从节点为新主节点

  1. 强制选举
    • 在某些情况下,例如主节点发生故障且自动选举没有及时生效,或者需要手动干预将某个从节点提升为主节点,可以使用强制选举的方法。
    • 连接到希望提升为主节点的从节点,使用 rs.stepDown() 命令让当前主节点退位(如果当前节点是主节点,需要先让其退位)。例如,连接到从节点 192.168.1.102:27017
mongo --host 192.168.1.102 --port 27017
  • mongo shell 中执行:
rs.stepDown();
  • 然后,在同一个从节点的 mongo shell 中执行强制选举命令:
rs.elect();
  • 如果选举成功,该从节点将成为新的主节点。会看到类似如下的输出:
{ "ok" : 1, "operationTime" : Timestamp(1661601471, 1), "$clusterTime" : { "clusterTime" : Timestamp(1661601471, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : 0 } } }
  1. 正常选举流程(等待自动选举)
    • 在主节点发生故障时,副本集通常会自动进行选举。从节点会根据自身的优先级(priority)、日志复制进度等因素进行竞争。
    • 优先级较高且数据同步较新的从节点更有可能被选举为新的主节点。默认情况下,优先级为 1 的节点都有机会参与选举。
    • 自动选举的过程通常在几秒到几十秒内完成,具体时间取决于副本集的配置和网络状况等因素。

六、变更副本集成员配置

  1. 修改成员优先级
    • 连接到副本集主节点,获取当前副本集配置。例如:
var cfg = rs.conf();
  • 查看配置内容,找到要修改优先级的成员。例如,假设要修改 192.168.1.102:27017 节点的优先级:
for (var i = 0; i < cfg.members.length; i++) {
  if (cfg.members[i].host === "192.168.1.102:27017") {
    cfg.members[i].priority = 5;
    break;
  }
}
  • 上述代码将该节点的优先级从默认值(通常为 1)修改为 5。
  • 应用新的配置:
rs.reconfig(cfg);
  • 如果配置成功,会看到类似如下的输出:
{ "ok" : 1, "operationTime" : Timestamp(1661601471, 1), "$clusterTime" : { "clusterTime" : Timestamp(1661601471, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : 0 } } }
  1. 修改成员隐藏属性
    • 同样先获取副本集配置:
var cfg = rs.conf();
  • 找到要修改隐藏属性的成员。例如,修改 192.168.1.103:27017 节点的隐藏属性:
for (var i = 0; i < cfg.members.length; i++) {
  if (cfg.members[i].host === "192.168.1.103:27017") {
    cfg.members[i].hidden = true;
    break;
  }
}
  • 应用新的配置:
rs.reconfig(cfg);
  • 这样,192.168.1.103:27017 节点将被设置为隐藏节点,应用程序不会自动将读操作路由到该节点。

七、常见问题及解决方法

  1. 添加成员失败
    • 问题描述:执行 rs.add() 命令时,出现错误,提示无法添加成员。
    • 可能原因
      • 新节点的网络配置问题,例如无法与现有副本集成员通信。可以使用 ping 命令检查网络连接,确保新节点与现有副本集成员之间网络畅通。
      • 新节点的 MongoDB 版本与现有副本集成员不兼容。确认新节点安装的 MongoDB 版本与现有副本集成员相同。
      • 副本集配置限制,例如副本集成员数量达到上限(默认最多 50 个成员,包括仲裁节点)。检查副本集当前成员数量,如有需要,移除一些不必要的成员后再尝试添加。
    • 解决方法:根据具体原因进行相应调整。如修复网络问题、升级或降级 MongoDB 版本、移除多余成员等。
  2. 移除成员后副本集异常
    • 问题描述:移除某个成员后,副本集出现数据同步问题或选举异常。
    • 可能原因
      • 移除的成员在选举过程中有重要作用,例如移除了仲裁节点且导致选举票数不均衡。检查副本集配置,确保仲裁节点数量为奇数且合理分布。
      • 数据同步未完成时移除成员,导致部分数据丢失或不一致。在移除成员前,确保该成员的数据已完全同步,可以通过 rs.status() 命令查看成员的同步状态。
    • 解决方法:如果是仲裁节点问题,根据需要添加或调整仲裁节点;如果是数据同步问题,尝试重新添加成员并等待数据同步完成,或者从其他正常成员恢复数据。
  3. 强制选举失败
    • 问题描述:执行 rs.elect() 命令进行强制选举时失败。
    • 可能原因
      • 网络分区问题,导致节点之间无法正常通信。检查网络连接,确保所有节点之间网络畅通。
      • 节点配置问题,例如优先级设置不合理或存在配置冲突。检查副本集配置,确保优先级等配置正确且无冲突。
    • 解决方法:修复网络问题,调整节点配置,然后再次尝试强制选举。

八、总结副本集成员变更操作注意事项

  1. 备份数据
    • 在进行任何副本集成员变更操作之前,强烈建议对数据进行备份。可以使用 mongodump 命令进行备份。例如,备份整个副本集数据:
mongodump --uri="mongodb://<primary_host>:<primary_port>/admin" --gzip --archive=backup.archive
  • 上述命令将副本集的数据备份到 backup.archive 文件中,并进行压缩。
  1. 监控操作过程
    • 在执行成员变更操作时,实时监控副本集状态。可以在另一个终端窗口持续执行 rs.status() 命令,观察副本集成员状态的变化以及数据同步情况。
  2. 了解配置参数影响
    • 在修改成员配置参数(如优先级、隐藏属性等)时,要充分了解这些参数对副本集选举和数据读写的影响。不合理的配置可能导致性能问题或高可用性降低。
  3. 网络稳定性
    • 确保在成员变更操作过程中网络稳定。网络波动或中断可能导致操作失败、数据同步异常等问题。如果在操作过程中出现网络问题,应及时修复并重新评估操作状态,必要时重新执行操作。