在MongoDB副本集架构中,节点权重(priority)是一个至关重要的配置参数,它直接决定了集群的选举行为和故障转移机制。作为一名长期维护金融级MongoDB集群的DBA,我经常需要根据业务需求调整节点权重配置。这个操作看似简单,但其中涉及的原理和注意事项往往被新手忽视。
副本集通过priority值来决定节点在选举中的优先级。这个参数的取值范围是0-1000(默认为1),当主节点不可用时,系统会自动选择priority值最高的节点作为新的主节点。值得注意的是:
在实际生产环境中,调整权重的典型场景包括:
重要提示:任何权重修改操作都会导致集群重新选举,选举期间集群将不可写(通常持续10-30秒),必须安排在业务低峰期执行。
在执行权重修改前,必须完成以下检查项:
bash复制rs.status().members.forEach(member => {
print(`${member.name} - state: ${member.stateStr}, health: ${member.health}`);
});
确保所有节点状态为"PRIMARY"、"SECONDARY"且health为1
bash复制cfg = rs.conf()
cfg.settings.electionTimeoutMillis # 默认10000ms(10秒)
建议临时调大选举超时时间(维护结束后恢复):
bash复制cfg.settings.electionTimeoutMillis = 30000
rs.reconfig(cfg)
以下是经过数百次生产验证的标准操作流程:
javascript复制var cfg = rs.conf() // 必须使用var避免shell会话断开导致配置丢失
javascript复制cfg.members.forEach((member, index) => {
print(`Index: ${index}, ID: ${member._id}, Host: ${member.host}, Priority: ${member.priority}`);
});
javascript复制// 推荐先降低原主节点权重,再提升新主节点权重
cfg.members[0].priority = 50 // 原主节点降权
cfg.members[1].priority = 200 // 新主候选节点
cfg.members[2].priority = 200
// 必须保留至少一个priority>0的节点
javascript复制rs.reconfig(cfg, {force: true})
// force选项在部分节点不可达时仍允许配置变更
bash复制for i in {1..30}; do rs.status() | grep -E '"name"|"stateStr"'; sleep 1; done
# 动态观察30秒内的状态变化
根据我在多个万级QPS集群的操作经验,这些细节至关重要:
bash复制# 在集群节点间执行持续ping测试
for host in "node1:27017" "node2:27017" "node3:27017"; do
mongo --host $host --eval "printjson(db.adminCommand({ping:1}))"
done
javascript复制// rollback_config.js
var oldCfg = {
// 保存当前完整配置
}
rs.reconfig(oldCfg, {force: true});
对于不同硬件配置的集群,推荐采用以下权重模板:
场景1:同构集群(所有节点配置相同)
javascript复制cfg.members[0].priority = 100 // 主节点
cfg.members[1].priority = 100 // 备节点
cfg.members[2].priority = 100 // 备节点
场景2:异构集群(主节点性能更强)
javascript复制cfg.members[0].priority = 200 // 高性能主节点
cfg.members[1].priority = 100 // 标准备节点
cfg.members[2].priority = 50 // 低配备节点
场景3:跨机房部署
javascript复制cfg.members[0].priority = 200 // 主机房节点
cfg.members[1].priority = 150 // 同城灾备
cfg.members[2].priority = 1 // 异地灾备(避免网络延迟影响)
问题1:配置修改后选举失败
现象:执行reconfig后长时间没有新主节点
排查步骤:
bash复制rs.status().members.filter(m => m.health === 1).length >= rs.conf().members.length/2
bash复制db.runCommand({serverStatus:1}).localTime - db.runCommand({isMaster:1}).localTime
问题2:权重修改不生效
现象:执行后priority值未变化
解决方案:
javascript复制rs.reconfig(cfg, {force: true})
bash复制rs.conf().version > originalVersion
对于需要频繁调整权重的场景,我开发了这套自动化脚本模板:
javascript复制// adjust_priority.js
function adjustPriority(targetHost, newPriority) {
const cfg = rs.conf();
const targetMember = cfg.members.find(m => m.host === targetHost);
if(!targetMember) throw Error(`Host ${targetHost} not found`);
// 保留旧配置用于回滚
const oldPriority = targetMember.priority;
targetMember.priority = newPriority;
try {
print(`Changing priority of ${targetHost} from ${oldPriority} to ${newPriority}`);
rs.reconfig(cfg, {force: true});
// 验证变更
assert.eq(rs.conf().members.find(m => m.host === targetHost).priority, newPriority);
print("Priority change successful");
} catch (e) {
// 自动回滚
targetMember.priority = oldPriority;
rs.reconfig(cfg, {force: true});
printErr(`Failed to change priority: ${e}`);
}
}
// 使用示例:adjustPriority("node1:27017", 200)
这个脚本实现了:
我在实际运维中发现,配合MongoDB的tag功能可以实现更精细化的权重控制:
javascript复制// 基于标签的权重分配
cfg.members.forEach(member => {
if(member.tags?.dc === "east") {
member.priority = 300; // 东部机房高权重
} else if(member.tags?.dc === "west") {
member.priority = 100; // 西部机房标准权重
}
});
这种基于标签的权重管理方式特别适合多地域部署的大型集群,可以通过标签实现机房级、机架级的故障转移策略。