主题
概念卡片:MongoDB副本集与分片集群
一句话机制:MongoDB 用副本集(Replica Set)解决单点高可用——主节点写、从节点通过 oplog 异步复制,主挂掉靠选举自动切换;用**分片集群(Sharded Cluster)**解决水平扩展——数据按 shard key 切成 chunk 分散到多个 Shard,由 mongos 路由 + config server 元数据协同。
副本集(Replica Set)
复制原理(oplog)
- 主节点记录所有操作到 oplog(
local.oplog.rs),从节点轮询读取并重放到自己的数据副本。 - 从节点同步三步:① 查自己 oplog 最新时间戳 → ② 查主节点 oplog 大于该时间戳的记录 → ③ 插入自己 oplog 并执行。
- oplog 幂等:同一操作执行多次效果等同一次(复制是「先复制数据、再写 oplog」,可能重复)。
- 从节点宕机重启后,自动从 oplog 最后位置续传。
构成与选举
- 最小构成:1 primary + 1 secondary + 1 arbiter;生产常见 primary + 2 secondary。
- 成员数应保持奇数(偶数加 arbiter);arbiter 只投票、不存数据。
- 主节点故障 → 备份节点选举(多数票)成新主,自动故障转移;切换约 10~30 秒,期间写操作与强一致读失败,但可在从节点做最终一致读。
特殊成员类型
| 类型 | 说明 |
|---|---|
| Priority 0 | 优先级 0,不能升主,用于多数据中心 |
| Hidden | 对客户端隐藏,作备份/统计 |
| Delayed | 数据延迟,作滚动备份/历史快照 |
| Vote(arbiter) | 仅投票不存数据 |
分片集群(Sharded Cluster)
架构三组件
| 组件 | 职责 |
|---|---|
| Shard | 存储实际数据块;生产一个 shard 常是一个副本集(防单点) |
| Config Server | 存集群元数据(chunk 信息) |
| Query Router(mongos) | 前端路由,客户端接入,让集群看起来像单库 |
分片策略(shard key 划分)
| 策略 | 原理 | 取舍 |
|---|---|---|
| 范围(Range) | shard key 按值域切成 chunk | 范围查询高效;但易数据不均 |
| 散列(Hash) | 按 hash 值建 chunk | 分布均匀;牺牲范围查询 |
| 自定义标签(Zone) | 打标签关联 shard key 范围,均衡器按标签迁移 | 灵活控制数据分布 |
- chunk 默认 64MB;集合数据只有超过一个 chunk 才会分散到多分片。
- 范围 vs 散列:范围对范围查询友好但易倾斜;散列均匀但牺牲高效范围查询。
数据平衡(拆分 + 平衡)
- 拆分(split):后台进程,chunk 涨到阈值一分为二,纯元数据操作不迁移数据。
- 平衡器(balancer):后台进程,把块多的分片迁移到块少的分片,直到均衡;迁移过程源分片把文档发到目标分片、目标应用变更、更新 config server 元数据。
- 迁移期间:更新立即在旧分片发生,然后复制到新分片;失败自动重试、数据只在新分片出现。
副本集 vs 分片集群(易混)
- 副本集不是为读性能设计的——oplog 复制时读可能被阻塞;它是数据冗余 + 高可用。
- 提高读性能应该用分片 + 索引(读写分散到各 Shard)。
- 副本集局限(分片集群解决的):所有写集中主节点、单副本集上限 12 节点、请求量大内存/磁盘不足、垂直扩展贵。
备份恢复
| 方式 | 说明 |
|---|---|
| 文件快照 | 需文件系统支持快照 + 开启 journal;恢复时 mongod 重放 journal |
| 复制数据文件 | 直接拷数据目录(需先加锁阻止写入);恢复时清空目录拷回 |
| mongodump / mongorestore | 逻辑备份,导出/导入到指定目录 |
不变量(必须成立的约束)
- 写操作只在 primary;从节点只读(且默认不对外)。
- 副本集成员数应为奇数,偶数靠 arbiter 补齐投票。
- 分片基于集合级别 + shard key,不是库级别。
常见误解
- 以为副本集能提升读性能 → 副本集是冗余/高可用,读性能靠分片 + 索引。
- 以为分片和副本是二选一 → 通常叠加:每个 shard 内部又是一个副本集(分片解决扩展,副本解决单点)。
- 以为 MongoDB 写立即落盘 → 默认延迟写(syncPeriodSecs,默认 60s 内),靠 journal 兜底。