MongoDB副本集成员变更操作指南
2023-09-232.8k 阅读
一、MongoDB 副本集简介
MongoDB 副本集是由一组 MongoDB 实例组成的集群,其中包含一个主节点(Primary)和多个从节点(Secondary)。副本集的主要作用是提供数据冗余、高可用性和灾难恢复能力。在副本集中,主节点负责处理所有的写操作,而从节点则复制主节点的数据,并可以处理读操作。如果主节点发生故障,副本集将会自动选举一个从节点成为新的主节点,从而确保服务的连续性。
二、副本集成员类型
- 主节点(Primary):
- 负责处理所有的写操作和大部分的读操作(除非配置了读偏好,让读操作分发到从节点)。
- 主节点会将写操作记录在 oplog(操作日志)中,从节点通过复制 oplog 来保持数据的一致性。
- 从节点(Secondary):
- 从节点复制主节点的 oplog,并应用其中的操作来保持与主节点的数据同步。
- 从节点可以配置为处理读操作,这有助于分担主节点的负载,特别是在读取密集型的应用场景中。
- 仲裁节点(Arbiter):
- 仲裁节点不存储数据,其主要作用是参与选举过程。
- 仲裁节点通过投票来决定哪个从节点将成为新的主节点。在副本集中,仲裁节点的数量通常为奇数个,以避免在选举过程中出现平局的情况。
三、添加副本集成员
- 准备新节点
- 首先,确保新节点安装了与现有副本集成员相同版本的 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
必须与现有副本集的名称一致。
- 启动新节点
- 在新节点上执行以下命令启动 MongoDB 服务:
sudo systemctl start mongod
- 连接到现有副本集主节点
- 使用
mongo
命令行工具连接到现有副本集的主节点:
- 使用
mongo --host <primary_host> --port <primary_port>
- 例如,如果主节点的 IP 地址为
192.168.1.101
,端口为27017
,则命令为:
mongo --host 192.168.1.101 --port 27017
- 添加新成员
- 在连接到主节点的
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
时,应用程序不会自动将读操作路由到该节点。
四、移除副本集成员
- 确认移除成员的状态
- 在移除副本集成员之前,需要确认其状态。连接到副本集主节点,使用
rs.status()
命令查看副本集状态。例如:
- 在移除副本集成员之前,需要确认其状态。连接到副本集主节点,使用
rs.status();
- 从输出结果中找到要移除的成员的
_id
和name
等信息。例如,输出结果中的某个成员部分如下:
{
"_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,name
为192.168.1.102:27017
,如果要移除这个成员,需要用到这些信息。
- 移除成员
- 使用
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 } } }
- 停止并清理移除的节点
- 在移除的节点上,执行以下命令停止 MongoDB 服务:
sudo systemctl stop mongod
- 可以选择清理该节点的数据目录(
/var/lib/mongodb
按照之前的配置),以释放磁盘空间:
sudo rm -rf /var/lib/mongodb
五、提升从节点为新主节点
- 强制选举
- 在某些情况下,例如主节点发生故障且自动选举没有及时生效,或者需要手动干预将某个从节点提升为主节点,可以使用强制选举的方法。
- 连接到希望提升为主节点的从节点,使用
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 } } }
- 正常选举流程(等待自动选举)
- 在主节点发生故障时,副本集通常会自动进行选举。从节点会根据自身的优先级(
priority
)、日志复制进度等因素进行竞争。 - 优先级较高且数据同步较新的从节点更有可能被选举为新的主节点。默认情况下,优先级为 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 } } }
- 修改成员隐藏属性
- 同样先获取副本集配置:
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
节点将被设置为隐藏节点,应用程序不会自动将读操作路由到该节点。
七、常见问题及解决方法
- 添加成员失败
- 问题描述:执行
rs.add()
命令时,出现错误,提示无法添加成员。 - 可能原因:
- 新节点的网络配置问题,例如无法与现有副本集成员通信。可以使用
ping
命令检查网络连接,确保新节点与现有副本集成员之间网络畅通。 - 新节点的 MongoDB 版本与现有副本集成员不兼容。确认新节点安装的 MongoDB 版本与现有副本集成员相同。
- 副本集配置限制,例如副本集成员数量达到上限(默认最多 50 个成员,包括仲裁节点)。检查副本集当前成员数量,如有需要,移除一些不必要的成员后再尝试添加。
- 新节点的网络配置问题,例如无法与现有副本集成员通信。可以使用
- 解决方法:根据具体原因进行相应调整。如修复网络问题、升级或降级 MongoDB 版本、移除多余成员等。
- 问题描述:执行
- 移除成员后副本集异常
- 问题描述:移除某个成员后,副本集出现数据同步问题或选举异常。
- 可能原因:
- 移除的成员在选举过程中有重要作用,例如移除了仲裁节点且导致选举票数不均衡。检查副本集配置,确保仲裁节点数量为奇数且合理分布。
- 数据同步未完成时移除成员,导致部分数据丢失或不一致。在移除成员前,确保该成员的数据已完全同步,可以通过
rs.status()
命令查看成员的同步状态。
- 解决方法:如果是仲裁节点问题,根据需要添加或调整仲裁节点;如果是数据同步问题,尝试重新添加成员并等待数据同步完成,或者从其他正常成员恢复数据。
- 强制选举失败
- 问题描述:执行
rs.elect()
命令进行强制选举时失败。 - 可能原因:
- 网络分区问题,导致节点之间无法正常通信。检查网络连接,确保所有节点之间网络畅通。
- 节点配置问题,例如优先级设置不合理或存在配置冲突。检查副本集配置,确保优先级等配置正确且无冲突。
- 解决方法:修复网络问题,调整节点配置,然后再次尝试强制选举。
- 问题描述:执行
八、总结副本集成员变更操作注意事项
- 备份数据
- 在进行任何副本集成员变更操作之前,强烈建议对数据进行备份。可以使用
mongodump
命令进行备份。例如,备份整个副本集数据:
- 在进行任何副本集成员变更操作之前,强烈建议对数据进行备份。可以使用
mongodump --uri="mongodb://<primary_host>:<primary_port>/admin" --gzip --archive=backup.archive
- 上述命令将副本集的数据备份到
backup.archive
文件中,并进行压缩。
- 监控操作过程
- 在执行成员变更操作时,实时监控副本集状态。可以在另一个终端窗口持续执行
rs.status()
命令,观察副本集成员状态的变化以及数据同步情况。
- 在执行成员变更操作时,实时监控副本集状态。可以在另一个终端窗口持续执行
- 了解配置参数影响
- 在修改成员配置参数(如优先级、隐藏属性等)时,要充分了解这些参数对副本集选举和数据读写的影响。不合理的配置可能导致性能问题或高可用性降低。
- 网络稳定性
- 确保在成员变更操作过程中网络稳定。网络波动或中断可能导致操作失败、数据同步异常等问题。如果在操作过程中出现网络问题,应及时修复并重新评估操作状态,必要时重新执行操作。