第17章:复制集基础——从单机到高可用
1. 项目背景业务场景本地生活电商上线三个月单台 MongoDB 开始力不从心。某天凌晨 2 点服务器突然宕机——只是普通的内存故障但因为只有一台 MongoDB整个系统直接不可用直到早上 8 点运维重启服务器才恢复。6 小时的停服直接导致 3000 个订单丢失、用户投诉爆表。CTO 拍板必须做高可用。但团队的困扰在于——“MongoDB 的主从复制怎么做一个 Primary 两个 Secondary 够不够如果 Primary 挂了客户端怎么自动切到新 Primary应用代码需要改吗”痛点没有复制集Replica Set的单机 MongoDB任意故障进程崩溃、系统重启、磁盘满、网络断都会导致业务全部中断。更糟糕的是——很多人第一次搭复制集就踩坑节点之间网络不通导致选举死锁writeConcern: majority不懂含义导致写入性能和一致性之间做错取舍误以为读 Secondary 能分摊读压力结果延时导致数据不一致Arbiter 节点不懂其作用直接部署了 3 个数据节点花冤枉钱。2. 项目设计小胖拿着高可用架构图大师我听说过主从复制——一个主库写入从库同步数据。但 MongoDB 不是还搞了个什么复制集吗和 MySQL 的主从复制有啥不同大师区别蛮大的。MySQL 的主从复制是单向的——主库写从库只读主库死了你需要手动把从库提成主库。MongoDB 的复制集是自管理的——节点之间通过心跳Heartbeat互相监控Primary 挂了剩下的节点自动投票选举出新的 Primary整个过程无需人工干预。小胖自动选举这不是跟选班长一样吗——班长不在剩下的同学投票选新班长大师贴切。选举遵循 Raft 协议——MongoDB 的复制集本质上是一个基于 Raft 的分布式一致性集群。每个节点都有 term任期号每次选举 term 加 1获得多数票过半数的节点当选 Primary。技术映射MongoDB 复制集是自管理的分布式状态机——Primary 负责所有写入Oplog 记入日志Secondary 通过拉取 Oplog 不断地重放操作来追赶 Primary 的状态。当 Primary 不可达时存活的节点通过 Raft 共识协议选举新 Primary。小白那复制集有哪几种节点角色我知道 Primary 和 Secondary还有什么 Arbiter、Hidden、Delayed 的各有啥用大师MongoDB 复制集中的 5 种角色角色存储数据参与选举用途Primary是是唯一接收写入的节点Secondary (priority 0)是是同步数据 可参与选举Arbiter仲裁节点否是只投票不存数据打破平票僵局Hidden隐藏节点是否priority0备份 / 报表专用不接收读流量Delayed延迟节点是否priority0, 延迟 slaveDelay 秒误删恢复的后悔药小胖Arbiter 不存数据只投票那不是省了一个服务器的钱我直接用 Arbiter 组一主一从一 Arbiter 不就好了大师Arbiter 确实省钱但也有代价。Arbiter 不存数据意味着——如果 Primary 挂了Secondary 当选但如果 Primary 挂了且 Arbiter 也不可用了Secondary 独自得不到多数票无法成为 Primary。所以 Arbiter 只是用低成本凑足 3 票选举需要超过半数但不增加数据的容灾副本数。技术映射复制集选举要求获得 大多数选票。3 节点2 数据 1 Arbiter的多数是 2任意 1 个数据节点挂掉仍能选举。但 2 个数据节点都挂掉Arbiter 独木难支——因为 Raft 要求 quorum 中必须有包含最新日志的节点。小白追问Oplog 是什么我老是听到这个词但不太理解。大师OplogOperation Log是 MongoDB 复制的核心。你可以把它理解成主节点的施工清单——Primary 执行的每一个写操作insert/update/delete都会生成一条 Oplog 条目Secondary 不断地拉取这个清单在自己的数据库上按顺序重放一遍。Oplog 是一个固定大小的 Capped Collection环形缓冲区大小通过oplogSizeMB设置。如果 Secondary 断开连接太久Oplog 窗口里已经没有它错过的那些操作——此时 Secondary 无法追赶必须做 Initial Sync全量重新同步。技术映射Oplog 窗口 Oplog 大小 / 写入速率。比如 Oplog 2GB写入速率 100MB/h窗口就是 20 小时。因此写入高峰期 Oplog 窗口会缩短需要监控。大师总结复制集是 MongoDB 高可用的最小单元——3 个数据节点PSS 或 PSA是最常见的生产配置。今天记住三点自动选举靠 Raft 协议写入复制靠 Oplog 拉取数据一致性靠 writeConcern 控制。3. 项目实战3.1 环境准备用 Docker Compose 搭建 3 节点复制集PSS 架构# mongodb-lab/replicaset/docker-compose-rs.ymlversion:3.8services:rs1:image:mongo:8.0container_name:mongo-rs1ports:-27017:27017command:mongod--replSet myRS--bind_ip_all--port 27017volumes:-./data/rs1:/data/dbnetworks:-rs-netrs2:image:mongo:8.0container_name:mongo-rs2ports:-27018:27017command:mongod--replSet myRS--bind_ip_all--port 27017volumes:-./data/rs2:/data/dbnetworks:-rs-netrs3:image:mongo:8.0container_name:mongo-rs3ports:-27019:27017command:mongod--replSet myRS--bind_ip_all--port 27017volumes:-./data/rs3:/data/dbnetworks:-rs-netnetworks:rs-net:driver:bridge3.2 分步实现步骤一初始化复制集目标启动 3 个 mongod 并初始化复制集。# 启动容器dockercompose-fdocker-compose-rs.yml up-ddockercomposeps# 进入 rs1 初始化复制集dockerexec-itmongo-rs1 mongosh--eval rs.initiate({ _id: myRS, members: [ { _id: 0, host: rs1:27017, priority: 2 }, { _id: 1, host: rs2:27017, priority: 1 }, { _id: 2, host: rs3:27017, priority: 1 } ] }) # 期望输出: { ok: 1 }// 查看复制集状态rs.status()// 关键字段// members[*].stateStr → PRIMARY / SECONDARY// members[*].health → 1// members[*].optime → 该节点的最新 Oplog 时间步骤二观察复制行为目标在 Primary 上写入数据观察 Secondary 是否实时同步。// 连接到 Primary可能是 rs1 的 27017// 确认当前是 Primaryuse test_rs db.products_rs.insertOne({name:复制集测试商品,price:199,createdAt:newDate()})print(写入成功等待同步...)// 连接到 Secondary27018 或 27019需要先允许从库读// mongosh mongodb://localhost:27018// 从库默认不允许读需要设置db.getMongo().setReadPref(secondary)// 或者在连接串中mongosh mongodb://localhost:27018/?readPreferencesecondaryuse test_rsconstdocdb.products_rs.findOne({name:复制集测试商品})print(从库中的商品:,doc?doc.name:未同步稍等几秒)// 刚插入可能还没同步 50ms 延迟稍等后应出现步骤三模拟 Primary 宕机 自动选举目标停止 Primary 容器观察自动选主过程。# 找到当前 Primarydockerexecmongo-rs1 mongosh--quiet--evalrs.isMaster().primary|grep-v^$# 假设 Primary 是 rs1:27017# 模拟宕机停止 rs1 容器dockerstop mongo-rs1# 查看 rs2 的复制集状态dockerexecmongo-rs2 mongosh--quiet--eval const status rs.status(); print(Primary:, status.members.find(m m.stateStr PRIMARY)?.name || 无); # 期望rs2 或 rs3 中的一个被选举为 Primary# 选举时间通常在 5-12 秒之间// 查看选举日志docker exec mongo-rs2 cat/var/log/mongodb/mongod.log2/dev/null|grepelection|tail-5步骤四恢复宕机节点——重新加入复制集目标将被 Kill 的 rs1 重新启动观察它如何追回数据。# 重启 rs1dockerstart mongo-rs1# 等待 10 秒查看 rs1 的角色dockerexecmongo-rs1 mongosh--quiet--eval const status rs.status(); const me status.members.find(m m.name.includes(rs1)); print(rs1 状态:, me.stateStr); print(rs1 健康:, me.health); # 期望rs1 以 SECONDARY 身份重新加入原 Primary 已降级步骤五配置节点的优先级和延迟目标设置 Hidden 节点和 Delayed 延迟节点。// 在 Primary 上执行// 添加 Hidden 节点不接收客户端读流量rs.add({host:rs4:27017,priority:0,// 0 不能成为 Primaryhidden:true// 隐藏节点})// 添加 Delayed 节点同步延迟 1 小时误删恢复用rs.add({host:rs5:27017,priority:0,hidden:true,secondaryDelaySecs:3600// 1 小时延迟})// 查看配置rs.conf().members.forEach(m{print(${m.host}: priority${m.priority}, hidden${m.hidden||false}, delay${m.secondaryDelaySecs||0}s)})步骤六writeConcern 实战——对比写入确认级别use test_rs// 场景 1w:1只 Primary 确认最快但不安全constt1Date.now()db.orders_rs.insertOne({orderNo:WC_TEST_1,amount:100},{writeConcern:{w:1}})print(w:1 耗时:,Date.now()-t1,ms)// 约 2-5ms// 场景 2w:majority多数成员确认安全但稍慢constt2Date.now()db.orders_rs.insertOne({orderNo:WC_TEST_2,amount:200},{writeConcern:{w:majority,wtimeout:5000}})print(w:majority 耗时:,Date.now()-t2,ms)// 约 10-50ms取决于副本之间的网络延迟// 场景 3w:3所有 3 个数据节点都确认最慢constt3Date.now()db.orders_rs.insertOne({orderNo:WC_TEST_3,amount:300},{writeConcern:{w:3,j:true,wtimeout:5000}}// j:true 需要持久化到 Journal)print(w:3j 耗时:,Date.now()-t3,ms)3.3 完整代码清单文件用途mongodb-lab/replicaset/docker-compose-rs.yml3 节点复制集 Docker 配置mongodb-lab/replicaset/init-rs.js复制集初始化脚本mongodb-lab/replicaset/failover-test.js故障切换验证脚本mongodb-lab/replicaset/writeconcern-demo.jswriteConcern 性能对比3.4 测试验证// 连接到 Primary 运行// 1. 确认复制集状态conststatusrs.status()print(复制集名称:,status.set)print(成员数:,status.members.length)print(Primary:,status.members.filter(mm.stateStrPRIMARY).length1?PASS:FAIL)// 2. 验证写入复制db.test_rs.validation.insertOne({msg:验证复制,ts:newDate()},{writeConcern:{w:majority}})// 在 Secondary 上验证// mongosh mongodb://localhost:27018/?readPreferencesecondary --eval // const doc db.getSiblingDB(test_rs).validation.findOne({msg:验证复制});// print(doc ? PASS: 数据已同步 : FAIL: 未同步);// // 3. 验证自动选举// 记下当前 Primary停掉它// 等待 15 秒在另一个节点查看应有新 Primary// 4. 清理// docker compose -f docker-compose-rs.yml down -v4. 项目总结4.1 复制集 vs 单机 vs 分片集群维度单机复制集分片集群高可用无自动故障切换每分片独立高可用数据冗余无多副本每分片多副本写性能最高略降writeConcern 开销水平扩展读性能单机可读 Secondary 分担多分片并行读部署复杂度低中高适用数据规模 100GB 500GB500GB4.2 适用场景复制集适用所有生产环境——单机仅限本地开发和 CI。需要业务无感知的自动故障转移。读多写少——读写分离读流量分担到 Secondary。异机房容灾——跨机房部署 Secondary 节点。不适用场景单机开发环境——复制集增加 3 倍资源消耗。写入优先且可接受停机的批量处理——单机更快。4.3 注意事项注意事项说明奇数个选举节点3/5/7 个有投票权的节点避免偶数需要过半票Oplog 大小默认是磁盘的 5%生产建议设为 24-48 小时的写入量Secondary 读不是免费的Secondary 追不上 Primary 时会产生读延迟网络分区被隔离的少数派节点无法选举服务不可用rs.stepDown()不是重启会触发安全的 Primary 降级让出位置给其他节点4.4 常见踩坑经验故障案例一偶数节点导致网络分区后无法选举某团队部署了 4 节点2 个完整节点 2 个 Arbiter机房断网后 22 各在一侧每一侧都只有 2 票需要过半 3 票——两侧都无法选举 Primary导致服务完全中断。根因偶数节点 对称分布导致分裂脑Split Brain。解决始终使用奇数个投票节点关键节点放在奇数侧。故障案例二Oplog 窗口太小导致从库追不上某促销期间订单量暴增 10 倍写入速率从 50MB/h 飙升 500MB/h。Oplog 2GB 的窗口从 40 小时压缩到 4 小时。一个做全量备份后重启的从库发现自己需要追 6 小时前的数据但 Oplog 只保留了 4 小时的——必须做 Initial Sync耗时 3 小时。解决增大 Oplog 至 10GB监控 Oplog 窗口时间低于 12 小时告警。故障案例三writeConcern: majority在 2 节点复制集下写不进去某团队用 1 Primary 1 Secondary2 节点设置writeConcern: majority。多数 ceil(3/2)2——需要两个节点都确认。其中一个节点挂了写入因为多数无法达成直接报超时。根因2 节点复制集的多数等于全部任意一个节点故障写入全停。解决始终用至少 3 个数据节点或用writeConcern: 1牺牲一致性保可用性。4.5 思考题如果 Primary 写入 Oplog 后立刻宕机Oplog 还没传到任何 Secondary新选出的 Primary 会丢失这些写入吗对客户端而言这些写入的返回结果是什么Arbiter 节点不存数据为什么也能参与选举如果 Arbiter 被网络隔离到少数派一侧会发生什么答案将在第 18 章末尾揭晓上一章思考题答案两个需要事务的跨集合场景①下单 库存预扣——创建订单和扣减库存必须在同一事务中如果不用事务替代方案是先预扣库存原子$inc 后创建订单订单创建失败后补偿恢复库存Saga 模式代码复杂且补偿失败有数据不一致风险。②订单完成 更新用户统计——订单标记完成和用户总消费金额更新。替代方案是 Change Streams 异步更新统计数据接受短暂的不一致。Spring Boot 自动管理索引spring.data.mongodb.auto-index-creationtrueIndexed的优点开发效率高不需要手写 DDL 脚本风险① 启动时同步建索引会阻塞应用启动大集合建索引需要数分钟② 生产环境Indexed注解的修改会意外地在数据库中创建非预期索引③ 无法控制background/partialFilterExpression等高级参数。推荐方案开发环境用自动建索引快速迭代生产环境关闭自动建索引通过变更管理流程执行索引变更脚本。延伸阅读与资源python入门Rquests从菜鸟脚本到企业级SDK的网络实战圣经Milvus向量数据库实战修炼从 0 到 1精通向量检索与生产落地后端工程师的 AI 转型第一课Ollama 与私有化大模型实战10倍开发者的 Dify 魔法书从零构建全栈 AI 应用后端工程师转型AI第一课-Ollama 与私有化大模型实战大型语言模型(LLM) vLLM 高性能推理落地实战Agent开发之LlamaIndex 实战修炼与源码进阶大语言模型Transformers 实战修炼与源码剖析

相关新闻

G-Helper终极指南:三步释放华硕笔记本隐藏性能的免费轻量工具

G-Helper终极指南:三步释放华硕笔记本隐藏性能的免费轻量工具

G-Helper终极指南:三步释放华硕笔记本隐藏性能的免费轻量工具 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenb…

2026/7/21 19:41:39 阅读更多 →
Ccache:编译加速器的幕后英雄,如何让开发者的等待时间减少90%

Ccache:编译加速器的幕后英雄,如何让开发者的等待时间减少90%

Ccache:编译加速器的幕后英雄,如何让开发者的等待时间减少90% 【免费下载链接】ccache ccache – a fast compiler cache 项目地址: https://gitcode.com/gh_mirrors/cc/ccache 作为一名C/C开发者,你是否曾盯着终端屏幕上缓慢滚动的编…

2026/7/21 9:47:29 阅读更多 →
3步免费激活IDM:解锁完整下载功能的终极指南

3步免费激活IDM:解锁完整下载功能的终极指南

3步免费激活IDM:解锁完整下载功能的终极指南 【免费下载链接】IDM-Activation-Script IDM Activation & Trail Reset Script 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script 还在为Internet Download Manager(IDM&#…

2026/7/21 15:59:35 阅读更多 →

最新新闻

“VLA-TVA”协同架构:打造具身智能“执行力”闭环(9)

“VLA-TVA”协同架构:打造具身智能“执行力”闭环(9)

前沿技术探索:AI智能体视觉(TVA,Transformer-based Vision Agent)是依托Transformer架构与“因式智能体”理论所构建的颠覆性工业视觉技术,是集深度强化学习(DRL)、卷积神经网络(CNN…

2026/7/23 21:33:59 阅读更多 →
AI数字人交互体验断层?95%企业忽略的3毫秒延迟阈值、眼动追踪校准、多模态意图纠错机制全披露

AI数字人交互体验断层?95%企业忽略的3毫秒延迟阈值、眼动追踪校准、多模态意图纠错机制全披露

更多请点击: https://kaifayun.com 第一章:AI数字人交互体验断层的本质诊断 AI数字人正从“能说会动”的演示型应用,加速迈向真实业务场景中的深度交互角色。然而,用户普遍反馈存在显著的体验断层:语音响应延迟、情感…

2026/7/23 21:33:59 阅读更多 →
2026武汉黄金回收白银回收铂金回收价格高无损耗专业鉴定本地人常去门店联系方式推荐

2026武汉黄金回收白银回收铂金回收价格高无损耗专业鉴定本地人常去门店联系方式推荐

2026武汉黄金白银铂金回收实测榜单|公安工商双备案无损测金无折旧费门店推荐 武汉三镇贵金属回收店铺遍地丛生,行业套路层出不穷,不少市民变现遭遇虚高报价、克扣损耗、未经同意熔金压价等问题。为帮助本地居民规避消费陷阱,小编实…

2026/7/23 21:33:59 阅读更多 →
“VLA-TVA”协同架构:打造具身智能“执行力”闭环(10)

“VLA-TVA”协同架构:打造具身智能“执行力”闭环(10)

前沿技术探索:AI智能体视觉(TVA,Transformer-based Vision Agent)是依托Transformer架构与“因式智能体”理论所构建的颠覆性工业视觉技术,是集深度强化学习(DRL)、卷积神经网络(CNN…

2026/7/23 21:33:59 阅读更多 →
Python agate-lookup 包详解:功能、安装、语法与实战案例

Python agate-lookup 包详解:功能、安装、语法与实战案例

1. 引言在 Python 数据处理生态中,agate 是一个轻量级、纯 Python 实现的表格数据处理库,而 agate-lookup 是其官方扩展包,专门用于在 agate 表格中实现类似 Excel VLOOKUP 的查找与合并功能。本文将从功能、安装、语法参数、实际案例和常见错…

2026/7/23 21:33:59 阅读更多 →
精密零件CNC加工选厂指南:三坐标检测是必备能力还是可选服务?

精密零件CNC加工选厂指南:三坐标检测是必备能力还是可选服务?

在精密零件CNC加工领域,很多采购在筛选供应商时,把三坐标检测当作"锦上添花"的加分项,觉得有更好,没有也能接受。但实际经验告诉我们:没有检测能力做支撑的精密加工,本质上是在"凭感觉出货&…

2026/7/23 21:32:58 阅读更多 →

日新闻

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:25 阅读更多 →
AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

更多请点击: https://codechina.net 第一章:AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析 在对2,346篇跨行业AI生成文案的A/B测试数据进行聚类分析后,我们发现&#xff1…

2026/7/23 0:01:26 阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:01:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻