MongoDB 存储体系初探
文章目录
MongoDB
MongoDB 中的数据模型与 MySQL 很类似,MongoDB 中最基本的元素是 Document 即 MySQL 中的数据行。一组结构相近的 Document 可以组成一个 Collection,类似于 MySQL 中的表。多个 Collection 组成一个 DataBase,DataBase 位于一个确定的 MongoDB 集群中。
MongoDB 支持的索引类型非常丰富,包括单字段/多字段/多Key/GEO/文本/Hash 索引,并且拥有丰富的属性:
- Unique(唯一索引)
- Sparse(稀疏索引) 只包含索引字段存在的文档,跳过索引键不存在的文档
- Partial(部分索引) 只包含满足指定条件的文档
- TTL(超时索引) 当索引上的 TTL 到期后,会自动删除对应的文档
以下对比了 MongoDB 与 MySQL 的各种特性:
MongoDB | MySQL | |
---|---|---|
Schema | 数据模式上 MongoDB 拥有更好的扩展性, 可以处理多样化和复杂的数据结构 |
具有固定的数据模式 |
性能 | 单点查询速度更快 | 范围查询更快 |
事务 | 只支持单文档 | 完全支持 |
JOIN 操作 | 不支持 | 支持 |
查询方式 | 纯 JSON 操作 | SQL |
分布式 | 原生支持 | 需要手动配置和实现分片 |
架构
MongoDB 是一个分布式数据存储系统,能自动对数据进行分片,提高集群的吞吐量。在 MongoDB 的集群中包含 Shard 、 Query Router 、 Config Server 三种组件。一个 Collection 的数据会被自动分片,存储到不同的 Shard 上,通常每个 Shard 都是多副本部署的。
Config Server 存储集群的元数据与配置信息,通常也作为多副本部署。这些元信息反应当前集群中数据的分布情况,比如每个 Shard 上存储的分片列表。同时还会存储一些认证信息、分布式锁,为集群提供基于角色的 ACL 控制。
Query Router 为分片服务和客户端提供接口,作为查询请求的路由。 Router 会缓存 Config Server 的元信息,当集群中的元信息变更后, Router 会重新拉取。
分片
在 MongoDB 中 Shard Key 作为分片的唯一标准,可以支持单字段索引和多字段索引(联合索引)。MongoDB 会把 Shard Key 划分成多个相互不重叠的范围,每一个范围都关联一个 Chunk, MongoDB 会均匀的把 Chunk 分配到集群各个 Shard 中。
对于分片 Collection 来说,只有以下的三种索引能作为唯一索引:
- Shard Key 上的索引
- Shard Key 作为前缀的联合索引
_id
默认是唯一索引,但当_id
不作为 Shard Key 的前缀时,只能保证每个 Shard 内部的唯一
MongoDB 支持 Hash 分片和范围分片两种方式,其中范围分片更有利于相似数据的存储,加快范围查询;对 Hash 分片来说, Shard Key 的基数对各个分片数据的均衡性有很大影响,如果基数太小,可能导致个别分片数据量过大。
MongoDB 支持根据 Shard Key 划分 Zone,每个 Zone 可以关联一个或多个 shard,同时一个 shard 也可以被关联到任意多个 Zone 上。当集群进行 balance 时, Zone 中的 chunk 只会在当前 Zone 关联的 Shard 中进行迁移。 Zone 适用于以下场景:
- 隔离 Collection 的中一部分数据
- 确保数据存储在距离服务器最近的 Shard 上
- 根据分片的物理性能划分数据
Chunk
MongoDB 通过 Shard Key 将数据分片存储到 Chunk 中,每个 Chunk 的大小/文档个数有一定的上限,当达到上限后就会进行分裂。一个 Chunk 可能会分裂成多个 Chunk,插入或更新都可能触发分裂。分裂不会将数据迁移到其他 Shard 上,但可能造成 Chunk 在 Shard 中分布不均匀,因此 balancer 会进行 Chunk 迁移。
balancer 运行在 Config Server 的主节点上,作为后台进程监视着各个 Shard,负责 Chunk 的迁移工作。其中 A 是 Chunk 迁出的 Shard, B 是 Chunk 迁入的 Shard。
- balancer 发送
moveChunk
命令到 A - A 开始内部的迁移操作,在这期间所有对 Chunk 的操作都由 A 负责响应
- B 构建所有 A 需要的索引
- B 从 A 获取 Chunk 的所有数据副本
- 当数据同步复制后,B 开启同步进程,以确保在迁移期间 Chunk 上所有变更都能同步到 B
- 当完全同步后, A 通知 Config Server 修改元信息
- 元信息更新完成并且 A 上的 Chunk 没有在使用中,则 A 删除 Chunk