MongoDB 集群
下面是一份 MongoDB 集群(Replica Set + Sharding)完整详解,从架构原理、部署方式、运行机制到最佳实践,一次讲全,适合做知识库或工作文档。
MongoDB 的集群由两种核心机制组成:
提供:
- 自动故障转移
- 自动选主
- 多副本冗余
- 数据安全
提供:
- 分布式存储
- 分布式查询
- 扩展至 PB 级数据
完整的 MongoDB 集群(即 Sharded Cluster)由:
Clients -> mongos(路由) -> Shards(多个 Replica Set) -> Config Servers(元数据)
一个典型的复制集有:
- Primary(主节点)
- Secondary(从节点)x N
- Arbiter(仲裁节点,可选)
结构示例:
+-------------+
| Primary |
+-------------+
/ | \
/ | \
+----------+ +----------+ +----------+
| Secondary| | Secondary| | Arbiter |
+----------+ +----------+ +----------+
Arbiter 仅参与选主,不保存数据。
写入流程:
Client -> 写 Primary -> Primary 记录 opLog -> Secondary 拉取 opLog -> 应用到自己数据集
Secondary 同步主节点的 oplog(操作日志),形成最终一致性。
当 Primary 挂掉:
-
Secondary 之间投票选举新的 Primary
-
要求多数节点存活(majority)
-
选举基于:
- freshness(oplog 最新)
- priority(优先级)
- 心跳机制
自动完成,无需人工干预。
Primary + Secondary + Secondary
Primary + Secondary + Arbiter
用于更高的高可用保证。
默认:强一致(读写 Primary)
readPreference = primary
可选:从节点读(弱一致)
readPreference = secondary
用于高读负载场景。
如果数据量 TB〜PB,或读写请求极大,就必须使用分片。
一个典型分片集群由:
Shard1 = ReplicaSet
Shard2 = ReplicaSet
Shard3 = ReplicaSet
存储集群元数据:
- 分片键
- chunk 分布
- 数据路由规则
必须为复制集。
应用所有读写请求都发给 mongos,它负责分发到具体分片。
整体架构:
+-----------+
| Clients |
+-----+-----+
|
+--+--+
|mongos|
+--+--+
|
---------------------------------
| | |
+------+ +------+ +------+
|Shard1| |Shard2| |Shard3|
+------+ +------+ +------+
| | |
ReplicaSet ReplicaSet ReplicaSet
决定数据分布方式,决定性能成败。
使用:
sh.shardCollection("test.users", { user_id: 1 })
MongoDB 默认将数据集合切成 64MB 的块(chunk)。
Chunk 会自动:
- 均衡(balancer)
- 迁移(moveChunk)
(1)哈希分片(hashed)——最推荐
自动均匀分布,防止热点。
{ user_id: "hashed" }
适合:
- 高写入
- 日志、监控、订单等
(2)范围分片(range)
按顺序排列数据,例如:
{ timestamp: 1 }
优点:
- 范围查询特别快
缺点:
- 时间戳会造成写入热点
(3)复合索引分片(compound)
例如:
{ country: 1, user_id: 1 }
适合跨区部署。
路由流程:
Client -> mongos -> Config Server -> Shard
MongoDB 自动决定查询是否需要:
- 单分片
- 多分片
- 聚合合并
开发者无需修改查询逻辑。
⭐ 推荐企业级架构(高可用 + 扩展性 + 性能)
- Config Servers: 3 节点 ReplicaSet
- Shards: 至少 2 Shard,每个是 3 节点 ReplicaSet(3×2=6)
- mongos: 多个,负载均衡
总计:3 (ConfigRS) + 6 (Shards) + 2 (mongos) = 11 个节点
非常可靠、可扩展到 PB 级数据。
查看集群状态
rs.status()
sh.status()
手动迁移 chunk
sh.moveChunk()
添加分片
sh.addShard()
重新平衡
sh.startBalancer()
- primary 频繁切换 -> 网络问题 / 心跳延迟
- secondary 落后 -> oplog 太小
- 同步失败 -> 磁盘 IO、网络问题
- 分片键选择错误 -> 热点写入
- chunk 积压 -> balancer 被关掉
- 查询跨分片太多 -> 分片键设计错误
避免脑裂。
太多 Shard = 管理成本高。
要避免:
- 单调递增字段(如时间戳)
- 热点字段
建议:
- 使用哈希分片
避免 Secondary 落后重同步。
使用 Nginx / LVS / HAProxy。
Config Server 是全局元数据库。
满足任意条件即可:
- 单节点磁盘容量不足(>1TB)
- QPS 非常高(> 20k/s)
- 写入量非常大(日志、订单、行为)
- 数据热点强烈
- 集群开始出现性能瓶颈