返回归档
💈工程与设计

MongoDB:文档、副本集、分片

MongoDB 是文档数据库,不是「分布式文件存储」。写走 Primary,高可用靠 Replica Set;要把一份数据摊到多台机器上才上 Sharding。WiredTiger 默认,事务要短。

文章目录

MongoDB 是 文档数据库。文档是 BSON,集合里的文档不必同一套字段。它不是分布式文件系统——那是对早期介绍的误译。默认存储引擎是 WiredTiger:文档级锁、压缩、4.0 起副本集上的多文档事务,4.2 起分片集群也能开事务。

SQL MongoDB
库 / 表 / 行 / 列 库 / Collection / Document / Field
主键 _id(常为 ObjectId)
JOIN 嵌入文档,或聚合里的 $lookup

先把数据模型想清楚:经常一起读的嵌进去,一对多很大再拆集合。不要一上来就按第三范式建一堆 $lookup

先 Replica Set,再考虑 Sharding

老的 Master-Slave 已经废弃。现在的高可用是 Replica Set

Replica Set:写只上 Primary,节点之间互相同步心跳

  • 写必须上 Primary,再记进 oplog
  • Secondary 拉 oplog 复制
  • 节点互相心跳,Primary 挂了自动选举
  • 可以加 Arbiter 凑投票数,它不存数据
  • 读偏好 primary 最安全;secondary 能分流,但可能读到落后的数据

驱动自己做拓扑发现:拿种子节点发 hello,之后自己盯着谁是 Primary。中间不必再塞一层代理。

数据大到单副本集的磁盘或写入扛不住,再上 Sharding

mongos + Config Server + 多个 Shard

  • Shard:通常自己就是一个 Replica Set,只存一部分 chunk
  • Config Server:chunk 范围和所在 shard
  • mongos:应用只连它。带 shard key 的查询走单 shard;不带就 scatter-gather
  • Shard key 一旦选定很难改,要选基数高、写入能打散的字段

副本集解决的是「这份数据挂了还能读」。分片解决的是「一份数据放不下、写不进」。先复制,后切开。

聚合是管道,不是另一套 SQL

文档一站一站往下传:$match 过滤,$group 分组,$project 整形,$unwind 拆数组,$lookup 联另一集合。能 $match 的尽早做,少把整表推进后面的阶段。

db.orders.aggregate([
  { $match: { status: "completed" } },
  { $group: { _id: "$user_id", total: { $sum: "$amount" } } }
])

事务、索引、更新时别整单覆盖

多文档事务遵循 ACID,但默认大约 60 秒超时,长事务会拖住 WiredTiger 缓存。集合、索引的创建删除不要放进事务。读关注在事务里常用 snapshot,写关注常用 majority,读偏好必须 primary

更新用 $set / $inc / $push,不要把整份文档当 replacement 传进去,否则没写到的字段会被抹掉。查询找不到文档是 mongo.ErrNoDocuments,要单独判断。

唯一、稀疏、hashed 索引按查询路径建。hashed 索引常给 shard key 用,不能支持范围查询。

一句话:文档模型先定,副本集先上;分片和跨文档事务都是后加的成本,不是默认标配。