MongoDB:像搭积木一样存数据
- MongoDB:像搭积木一样存数据
-
- [1. MongoDB是什么?------ 先说个故事](#1. MongoDB是什么?—— 先说个故事)
- [2. 核心概念一:BSON](#2. 核心概念一:BSON)
- [3. 核心概念二:单机存储引擎 WiredTiger](#3. 核心概念二:单机存储引擎 WiredTiger)
- [4. 核心概念三:高可用(副本集 Replica Set)](#4. 核心概念三:高可用(副本集 Replica Set))
- [5. 核心概念四:水平扩展(分片集群 Sharded Cluster)](#5. 核心概念四:水平扩展(分片集群 Sharded Cluster))
- [6. MongoDB 的优缺点](#6. MongoDB 的优缺点)
- [7. 最终总结](#7. 最终总结)
MongoDB:像搭积木一样存数据
当你用MySQL做数据库,每次加个字段都像给运行中的飞机换零件,而MongoDB直接让你把整个机舱拆了重组,还不用停机。
1. MongoDB是什么?------ 先说个故事
假设你是个程序员,老板要你做个游戏平台,支撑十多亿用户的数据。这些数据包括 ID、装备、是否参与过节日活动等字段。功能不断迭代,每次增加活动时,都需要修改 MySQL 表结构------很麻烦。而且为了支持多维度查询,需要为每个可能的属性都预留字段,大多数用不上,浪费空间。
有经验的程序员会告诉你:这个问题,用 MongoDB 来解决。
MongoDB 可以理解为"数据结构灵活点的 MySQL",它把 MySQL 的"多行多列"变成了一堆"文档"(document)。
所以,MongoDB 就是一个存"文档"的数据库。这里的"文档"不是 Word 文件,而是像 JSON 对象那样的数据结构。
核心概念对比:
| MySQL | MongoDB |
|---|---|
| 数据库(Database) | 数据库(Database) |
| 表(Table) | 集合(Collection) |
| 行(Row) | 文档(Document) |
| 列(Column) | 字段(Field) |
MongoDB 的核心思想是:无需提前定义表结构,想加字段随时加,不同的文档可以有不同的字段。
2. 核心概念一:BSON
MongoDB 的文档长得像 JSON,但 JSON 只支持数字、字符串这类基础类型,不支持二进制。MongoDB 扩展了 JSON,让它直接支持二进制等数据类型,这就是 BSON(Binary JSON)。
BSON 文档会被写到磁盘上以 .wt 为后缀名的文件中。集合越大,文件也就越大。为了提高读写效率,数据会被拆成一个个 32KB 的数据页,这样读写时只需要加载相关数据页,而不是整个文件。
3. 核心概念二:单机存储引擎 WiredTiger
数据需要存到磁盘里,这个存取的机制就叫"存储引擎"。
MongoDB 默认的存储引擎是 WiredTiger,它在 MongoDB 3.0 版本引入,3.2 版本后成为默认引擎。
它的工作流程如下:
- 写 Cache:数据修改先写入内存 Cache。
- 写 Journal:同时记录到预写日志(Write Ahead Log, WAL)。
- Checkpoint:大约每 60 秒,将内存 Cache 中的数据持久化到磁盘。
- Cache 管理:若内存 Cache 满,WiredTiger 会基于 LRU-K 淘汰算法将不常用的数据刷出。
WiredTiger 的内部采用 B-Tree 结构来组织数据,并实现了文档级并发控制,多个写操作可以同时修改不同的文档,而不会相互阻塞。
4. 核心概念三:高可用(副本集 Replica Set)
在生产环境,单机数据库存在单点故障风险。解决思路是数据冗余,也就是 副本集(Replica Set)。
副本集是一个"主-从"集群:
- Primary(主节点) :负责所有的写操作,以及默认情况下的读操作,并将数据变更写入
oplog日志。 - Secondary(从节点) :复制 Primary 的
oplog日志并执行,使自身数据和 Primary 保持一致,分担读压力。 - Arbiter(仲裁者):不存储数据,只参与投票,帮助在偶数个节点时选出 Primary。
如果 Primary 节点宕机,剩余节点会通过内部心跳机制 和投票选举出新的 Primary,自动恢复服务。为保证投票能顺利进行,副本集节点数通常为奇数。
5. 核心概念四:水平扩展(分片集群 Sharded Cluster)
当数据量大到单机无法存储,或读写压力超出单机处理能力时,就需要 分片集群(Sharded Cluster)。它把数据拆成多份,分布到多个服务器上,解决海量数据存储和高吞吐量问题。
一个分片集群由三部分组成:
| 组件 | 说明 |
|---|---|
mongos(路由服务器) |
分片集群的总入口,将客户端请求路由到正确的分片。对于包含分片键的查询能精确定位,否则会向所有分片广播。 |
config server(配置服务器) |
存储集群的元数据(分片键范围等)。MongoDB 3.4 版本后必须部署为副本集(至少3个节点)。 |
| Shard(分片) | 真正存储数据的地方,每个 Shard 都必须部署为副本集。 |
分片键(Shard Key) 是数据分片的依据,MongoDB 根据它的值决定数据分布到哪个分片上。选择合适的分片键对集群性能至关重要,需确保数据读写能均匀分布。
6. MongoDB 的优缺点
| 优点 | 说明 |
|---|---|
| 灵活的数据模型 | 无需预定义表结构,开发者可随时添加字段,非常适合快速迭代和需求多变的场景。 |
| 高性能 | 通过内存映射文件、高效的数据结构提供快速的读写操作。WiredTiger 存储引擎提供高效的压缩和缓存机制,减少了 I/O 开销。 |
| 水平扩展能力 | 通过分片集群可实现接近线性的扩展,随着服务器增加,读写吞吐量几乎成比例增长。实测3节点分片集群,写入吞吐量可达单节点的2.8倍。 |
| 丰富的查询与聚合 | 提供完整的 CRUD 操作和强大的聚合管道(Aggregation Pipeline),能实现类似 SQL 的 GROUP BY、JOIN 等复杂数据处理。 |
| 缺点 | 说明 |
|---|---|
| 事务支持的局限性 | 虽支持多文档 ACID 事务,但性能远低于单文档操作。官方数据显示,1000个文档的事务比单文档操作慢8-10倍。金融系统测试中,超过50个文档的事务失败率从0.2%上升至15%。 |
| 内存消耗高 | WiredTiger 默认会用掉 50% 的内存(或1GB的较大值)作为缓存。当工作集(活跃数据+索引)超过物理内存时,会频繁触发磁盘 I/O,导致性能急剧下降。 |
| 复杂查询能力较弱 | 对于递归查询(如树形结构)、窗口函数、公用表表达式等,MongoDB 的原生支持较弱或需要复杂的模拟,开发成本相对较高。 |
| 运维复杂度 | 与 MySQL 等成熟关系型数据库相比,MongoDB 的生态工具、监控体系和运维经验相对不够成熟,分片集群的运维更是挑战。 |
在选型时,推荐 MongoDB + 关系型数据库的混合架构:MongoDB 负责灵活的数据存储(如用户行为日志、商品目录等),关系型数据库(如 MySQL)处理需要强事务和复杂关联查询的核心业务(如订单、账户)。
7. 最终总结
MongoDB 是一个面向文档的 NoSQL 数据库,它的核心竞争力在于:
- 面向文档:以 BSON 格式存储,结构灵活,无需预先定义表结构。
- WiredTiger:基于 B-Tree 的存储引擎,支持文档级锁,高性能。
- 副本集:主从复制,自动故障转移,提供高可用。
- 分片集群:水平扩展,突破单机物理限制。
- 丰富的查询与聚合:内置聚合管道,支持复杂数据处理。
它不是银弹,不适合所有场景,但在敏捷开发、海量数据、快速迭代的现代应用(如电商、内容管理、物联网)中,是一个极具竞争力的选择。
MongoDB 更像一把瑞士军刀------当 MySQL 还在纠结"这把螺丝刀是不是太粗了"时,它已经帮你把整个工具箱拆了重组,还不用停机。