MongoDB


关键字

上限集合(Capped Collection)

上限集合类似于定长的循环队列,数据顺序追加到集合的尾部,当集合空间达到上限时,它会覆盖集合中最旧的文档。上限集合的数据将会被顺序写入到磁盘的固定空间内,所以,I/O 速度非常快,如果不建立索引,性能更好。

分片

副本

链式复制、非链式复制

高可用-复制集群

Primary 节点

Secondary 节点

Arbitoer 节点(仲裁节点)

高伸缩-分片集群

MongoDB 的分布式版本,用于提升集群的数据容量,读吞吐量,分散读写压力

configserver:配置服务

shard:分片服务

mongdos:路由服务

分片键(Shard Key):

决定了分片数据在分片中的分布情况

Chunk(块):

分片集群的一个概念,本质上就是一堆 Document 的逻辑数据单元,每个 Chunk 包含一定范围的片键的数据

属于离散数学中的划分概念

均衡器(Balancer) 、再平衡:

chunk 分裂的过程

GridFS:支持超大文件分片存储

写关注(Write Concern):

用来描述数据库写操作返回信息的保证级别,有3种选项,分别为0 - Unacknowledged、1 - Acknowledged、 majority - Replica Acknowledged,

概述

什么是 MongoDB

C++语言编写,基于分布式文件存储的,介于关系数据库与非关系数据库

特点

它是一种面向集合,模式无关的文档型数据库。其中数据以“集合”的方式进行分组,每个集合都有单独的名称并可以包含无限数量的文档。这里的集合同关系型数据库中的表(table)类似,唯一的区别就是它并没有任何明确的schema。 MongoDB以一系列键值对集合的方式存储数据,其中键(Key)是字符串,值(Value)是任何一种数据类型的集合,包括数组和文档。

适用场景

原理

索引类型有哪些?

  • 单字段索引(Single Field Indexes)
  • 复合索引(Compound Indexes)
  • 多键索引(Multikey Indexes)
  • 全文索引(text Indexes)
  • Hash 索引(Hash Indexes)
  • 通配符索引(Wildcard Index)
  • 2dsphere索引(2dsphere Indexes)

索引的限制

额外的开销:

索引是存放在内存中的:当内存不够时,会删掉一些索引

在正则和非操作符($nin、$not 等)、算数操作符、$where 子句中不会使用索引

引擎

MMAP(内存映射)

3.0 版本之前,只有这一种

锁颗粒度较粗

基于填充因子的自适应分配方式(paddingFactor),这种方式下将会基于每个集合计算历史的文档更新平均增长长度,每当新文档插入或者老文档移动,都会基于填充因子推算出额外空间填充进去。MMAP还提供了一种基于usePowerOf2Sizes的预分配方式,这种方式直接为文档分配2的N次方大小的存储空间。

将所有文件、索引存储到了一起,不利于磁盘空间回收

MMAPv1

3.0 版本之后

锁颗粒较细(库级别 -> 集合级别)

将基于usePowerOf2Sizes的预分配方式作为默认的文档空间分配方式

创建集合的时候还可以设置成noPadding标签,关闭空间预分配。

WiredTiger(重点,类 b+树)

锁粒度进一步细化(集合级别 -> 文档级别),类似于 MySQL 中的行锁了

压缩算法

支持对所有集合和索引进行块压缩和前缀压缩,包括journal日志,

  • Snappy(默认):压缩速度快,cpu 开销低,适合大多数业务场景
  • Zlib:压缩率高,但是速度慢
  • none(不压缩)

文件格式:

集合、索引存放到单独的文件中,便于删除后及时释放空间

原理

以 page 为单位向磁盘中写数据,每个 page 是 b+树中的一个节点

官网讲解文档:

https://mongoing.com/archives/category/wiredtiger%e5%ad%98%e5%82%a8%e5%bc%95%e6%93%8e%e7%b3%bb%e5%88%97

写入流程

WiredTiger的写操作会先写入Cache,并持久化到WAL(Write ahead log),每60s或log文件达到2GB时会做一次Checkpoint,将当前的数据持久化,产生一个新的快照。Wiredtiger连接初始化时,首先将数据恢复至最新的快照状态,然后根据WAL恢复数据,以保证存储可靠性。

写关注(Write Concern):

用来描述数据库写操作返回信息的保证级别,有3种选项,分别为0 - Unacknowledged、1 - Acknowledged、 majority - Replica Acknowledged

修改流程

原理是修改的时候,会生成新的节点,不修改原有的节点

会导致 b+树越来越大,但是写入性能强(空间换时间)

MongoRocks

基于 facebook 开源的 rocksDB 实现的存储引擎

最大的特点:支持高并发随机写入和读取

压缩算法更多:

Snappy、Zlib和LZ4等压缩算法

In-Memory(官方企业版)

其他特殊版本

架构

副本集群

支持数据一致性要求强、要求不强的场景

即 MongoDB 的高可用解决方案

通过 opLog 的复制来实现数据同步和最终一致性

类似 MySQL 的 binlog,但 binLog 是二进制文件;但是 opLog 是 MongoDB 的一个特殊集合,叫capped collection

这种集合在创建初期就设置其大小或者文档最大数量,后续按照LRU(Least Recently Used)规则和插入顺序进行 age-out。

opLog 的特点:

  • 可插入和更新,更新不能超出文档大小,否则更新失败;
  • 不可以删除文档,只能删除整个集合;
  • 32bit系统上大小有限制,而64bit系统则无文件大小限制;
  • 在这个集合上无法进行分片;

副本集的特点:

  • MongoDB副本集拥有具备各种功能的多种角色,比如投票节点、隐藏从库、延迟从库等;
  • MongoDB可配置每个成员的优先级(priority)和投票数(votes),以此来建设异地容灾集群,比如我就指定某地域只能选主,其他地域只提供读服务;
  • 结合强大的MongoDB驱动实现读写分离、强一致。

分片集群

水平扩容的一种

支持自动分片、手动分片

自动预分片支持:如果分片集群选用 hash 分片策略,则支持 shardCollection 时提前对片建进行自动预备分片。

手动预分片支持:hash 分片策略和范围分片策略都可以通过 mongodb 自有的 splitAt 等接口进行手动人工预分片,分片接口的支持确保预分片更加弹性自由。

组成

  • Config Servers:配置服务器,本质上是一个 MongoDB 的副本集,负责存储集群的各种元数据和配置,如分片地址、Chunks 等
  • Mongos:路由服务,不存具体数据,从 Config 获取集群配置讲请求转发到特定的分片,并且整合分片结果返回给客户端。
  • Shard:每个分片是整体数据的一部分子集,从 MongoDB3.6 版本开始,每个 Shard 必须部署为副本集(replica set)架构

分片键:

要求得是文档的字段

且是一个索引(不能是多索引、文本索引、地理空间索引)

5.0 之后,分片键实时可变

大小不能超过 512 字节

选择要求:

  • 取值基数 取值基数建议尽可能大,如果用小基数的片键,因为备选值有限,那么块的总数量就有限,随着数据增多,块的大小会越来越大,导致水平扩展时移动块会非常困难。 例如:选择年龄做一个基数,范围最多只有 100 个,随着数据量增多,同一个值分布过多时,导致 chunck 的增长超出 chuncksize 的范围,引起 jumbo chunk,从而无法迁移,导致数据分布不均匀,性能瓶颈。
  • 取值分布 取值分布建议尽量均匀,分布不均匀的片键会造成某些块的数据量非常大,同样有上面数据分布不均匀,性能瓶颈的问题。
  • 查询带分片 查询时建议带上分片,使用分片键进行条件查询时,mongos 可以直接定位到具体分片,否则 mongos 需要将查询分发到所有分片,再等待响应返回。
  • 避免单调递增或递减 单调递增的 sharding key,数据文件挪动小,但写入会集中,导致最后一篇的数据量持续增大,不断发生迁移,递减同理。

分片策略

  • 基于 hash 分片

  • 基于范围分片

Chunk

分片集群不会记录每条数据在哪个分片上,而是记录 Chunk 在哪个分片上一级这个 Chunk 包含哪些数据。

默认情况下,一个 Chunk 的最大值默认为 64MB(可调整,取值范围为 1~1024 MB。如无特殊需求,建议保持默认值),进行数据插入、更新、删除时,如果此时 Mongos 感知到了目标 Chunk 的大小或者其中的数据量超过上限,则会触发 Chunk 分裂

数据的增长会让 Chunk 分裂得越来越多。这个时候,各个分片上的 Chunk 数量可能会不平衡。Mongos 中的 均衡器(Balancer) 组件就会执行自动平衡,尝试使各个 Shard 上 Chunk 的数量保持均衡,这个过程就是 再平衡(Rebalance)。默认情况下,数据库和集合的 Rebalance 是开启的。

优点

  • 架构简单
  • 没有复杂的连接
  • 深度查询能力,<font style="color:rgb(255, 80, 44);background-color:rgb(255, 245, 245);">MongoDB</font>支持动态查询。
  • 容易调试
  • 容易扩展
  • 不需要转化/映射应用对象到数据库对象
  • 使用内部内存作为存储工作区,以便更快的存取数据。

MongoDB 本身可能存在的问题

1、opLog 循环复制问题

集团的 MongDB 打了补丁,修改了 opLog 的格式

2、opLog 不支持 回滚?

给 opLog 加上了全镜像功能

与其他产品的对比

形式 MongoDB MySQL
数据库模型 非关系型 关系型
存储方式 虚拟内存+持久化
查询语句 独特的MongoDB查询方式 传统SQL语句
架构特点 副本集以及分片 常见单点、M-S、MHA、MMM等架构方式
数据处理方式 基于内存,将热数据存在物理内存中,从而达到高速读写 不同的引擎拥有自己的特点
使用场景 事件的记录,内容管理或者博客平台等数据大且非结构化数据的场景 适用于数据量少且很多结构化数据
形式 MongoDB redis
内存管理机制 MongoDB 数据存在内存,由 linux系统 mmap 实现,当内存不够时,只将热点数据放入内存,其他数据存在磁盘 Redis 数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的 LRU 算法删除数据
支持的数据结构 MongoDB 数据结构比较单一,但是支持丰富的数据表达,索引 Redis 支持的数据结构丰富,包括hash、set、list等
性能 mongodb依赖内存,TPS较高 Redis依赖内存,TPS非常高。性能上Redis优于MongoDB
可靠性 支持持久化以及复制集增加可靠性 Redis依赖快照进行持久化;AOF增强可靠性;增强可靠性的同时,影响访问性能
数据分析 mongodb内置数据分析功能(mapreduce) Redis不支持
事务支持情况 只支持单文档事务,需要复杂事务支持的场景暂时不适合 Redis 事务支持比较弱,只能保证事务中的每个操作连续执行
集群 MongoDB 集群技术比较成熟 Redis从3.0开始支持集群

参考

1、https://juejin.cn/post/6844903965629349895

2、MongoDB在集团的使用

3、【【驳斥八股文系列】别瞎分析了,MongoDB 使用的是 B+ 树,不是你们以为的 B 树】https://zhuanlan.zhihu.com/p/519658576

4、https://javaguide.cn/database/mongodb/mongodb-questions-02.html#%E5%88%86%E7%89%87%E9%9B%86%E7%BE%A4

5、【一文读懂 MongoDB chunk 迁移

https://mongoing.com/archives/77479

6、https://zhuanlan.zhihu.com/p/122287797


文章作者: 王利康
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 王利康 !
  目录