1.什么是MongoDB

mongoDB是由C++编写,基于分布式架构、面向文档的非关系型数据库,用于存储海量的数据。他的读写效率明显优于关系型数据库,同时又是非关系型数据库中逻辑架构最像关系型数据库的。
mongo同样支持索引、多表联查(嵌入文档)等相关操作

2.MongoDB的特点

  1. mongo是一个面向文档的非关系型数据库,使用起来相对来说比关系型数据库要简单
  2. 文档的具体存储形式为BSON(JSON形式的一种扩展)。BSON支持文档和数据的各种嵌套
  3. mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
  4. mongoDB支持多种主流编程语言。例如:RUBY,PYTHON,JAVA,C++,PHP,C#等
  5. 可以在mongodb记录中设置任何属性的索引来实现更快的排序。
  6. 可以通过本地或者网络创建数据镜像,这使得mongodb含有更强的扩展性。
  7. 如果负载的增加(需要更多的存储空间和更强的处理能力),它可以分布在计算机网络中的其它节点上,这就是所谓的分片。
  8. mongodb中的Map/Reduce主要是用来对数据进行批量处理和聚合操作,Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传递给Reduce函数进行处理。另外Map函数和Reduce函数是使用JavaScript编写的,所以可以通过db.runCommand和mapreduce命令来执行MapReduce操作。
  9. GridFS是mongodb中的一个内置功能,可以用于存放大于16M的文件。
  10. mongodb允许在服务端执行脚本,可以用JavaScript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。

    3.MongoDB的数据逻辑架构

  11. 数据库:mongo中集合的容器,是mongo中的底层数据逻辑,可以类比为关系型数据库中的库。一个mongo容器中可以存储多个数据库

  12. 集合:mongo中文档的容器,可以类比为关系型数据库中的表。但是与关系型数据库不同的是,mongo中的集合并不需要强制定义数据结构
  13. 文档:mongo中的具体数据存储结构,可以类比关系型数据库中的行。每个文档中包含字段的key和value
  14. 字段:类比为关系型数据库中的列,一个文档中包含0至多个字段。
  15. _id:mongo中每个文档必须存在的一个唯一标识符字段,如果文档中没有声明该字段,那么mongo服务器会为文档创建一个24位唯一标识符

如图:
image.png

4.MongoDB与关系型数据库对比

关系型数据库 MongoDB
数据库(Database) 数据库(Database)
表格(Table) 集合(Collection)
行(Row) 文档(Document)
列(Column) 字段(Field)
表联合(Join) 嵌入文档
主键(Primary Key) 主键 (_id)

需要关注的重点就是:Mongo的集合中可以存储不同结构的文档,同时这些文档的结构可以动态改变。这是与关系型数据库最大的不同

5.MongoDB的字段类型

String 字符串,存储数据的常用数据类,在 mangoDB 中 UTF-8 编码的字符串才是合法的
Integer 整型数值,用于存储数值,根据部署的服务器,可以为分 64位和 32位。
Boolean 布尔值,存储布尔值
Double 双精度浮点值,用于存储浮点值
TimeStamp 时间戳,记录文档修改或者添加的具体时间
Date 日期时间,用 UNIX 时间格式存储当前日期或时间。可以自定义日期时间,创建 Date 对象
Object 用于内嵌文档
Array 用于将数组或者列表多个值存储为一个键
Null 用于创建空值
Min、Max keys 将一个值与 BSON (二进制 JSON) 元素的最低值和最高值相比

其实简单理解每个文档可以当成一个JSON对象,JSON对象支持的数据类型,文档也都支持。同时支持数据类型嵌套

6.什么是bson

BSON是一种类JSON的一种二进制形式的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date和BinData类型。
BSON可以做为网络数据传输的一种序列化形式,这个有点类似于Google的Protocol Buffer,但是BSON是一种schema-less的存储形式,它的优点是灵活性高,但它的缺点是空间利用率不是很理想,
BSON有三个特点:轻量性、可遍历性、高效性
MongoDB以BSON做为其持久化和网络数据传输结构的一种重要原因是其可遍历性。

7.MongoDB的应用场景

适用场景

  1. 网站数据:MongoDB 非常适合实时的插入、更新与查询数据,并具备网站实时存储数据所需的复制及高度伸缩的特性;
  2. 缓存:由于性能很高,MongoDB 也适合作为信息基础设施的缓存层,在系统重启之后,由 MongoDB 搭建的持久化缓存层可以避免下层的数据源过载;
  3. 庞大的、低价值的数据:使用传统的关系型数据库存取大量数据时,数据库的运行效率往往并不尽人意,而 MongoDB 的出现使这个问题迎刃而解,MongoDB 非常适合庞大而安全性、准确性求又不是很高数据的存储;例如说大量的网络爬虫数据
  4. 高伸缩性的场景:MongoDB 内置了 MapReduce 引擎,因此非常适合由数十或数百台服务器组成的数据库;
  5. 用于对象及 JSON 数据的存储:MongoDB 的 BSON 数据格式非常适合文档化格式的存储及查询。

    不适用场景

  6. 高度事务性的系统:例如银行或会计系统,传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序;

  7. 传统的商业智能应用:针对特定问题的 BI(全称“Business Intelligence”,中文意思为“商业智慧或商务智能”,指用现代数据仓库技术、线上分析处理技术、数据挖掘和数据展现技术进行数据分析以实现商业价值)数据库会产生高度优化的查询方式,对于此类应用,数据仓库可能是更合适的选择;
  8. 需要复杂 SQL 查询的应用。

    8.MongoDB的数据压缩

    MongoDB 的另外一个比较重要的特性是数据压缩,MongoDB 会自动把客户数据压缩之后再落盘,这样就可以节省存储空间。MongoDB 的数据压缩算法有多种:

  9. Snappy:默认的压缩算法,压缩比 3 ~ 5 倍

  10. Zlib:高度压缩算法,压缩比 5 ~ 7 倍
  11. 前缀压缩:索引用的压缩算法,简单理解就是丢掉重复的前缀
  12. zstd:MongoDB 4.2 之后新增的压缩算法,拥有更好的压缩率

现在推荐的 MongoDB 版本是 4.0,在这个版本下推荐使用 snappy 算法,虽然 zlib 有更高的压缩比,但是读写会有一定的性能波动,不适合核心业务,但是比较适合流水、日志等场景

9.MongoDB的集群部署模式

概述

MongoDB 有三种集群部署模式,分别为主从复制(Master-Slaver)、副本集(Replica Set)和分片(Sharding)模式。

  1. Master-Slaver 是一种主从副本的模式,目前已经不推荐使用。
  2. Replica Set 模式取代了 Master-Slaver 模式,是一种互为主从的关系。Replica Set 将数据复制多份保存,不同服务器保存同一份数据,在出现故障时自动切换,实现故障转移,在实际生产中非常实用。
  3. Sharding 模式适合处理大量数据,它将数据分开存储,不同服务器保存不同的数据,所有服务器数据的总和即为整个数据集。

Sharding 模式追求的是高性能,而且是三种集群中最复杂的。在实际生产环境中,通常将 Replica Set 和 Sharding 两种技术结合使用。

主从复制

这种方式比单节点的可用性好很多,可用于备份、故障恢复、读扩展等。集群中的主从节点均运行 MongoDB 实例,完成数据的存储、查询与修改操作。
主从复制时mongo中最简单的部署架构,有一个主节点(读写节点)和多个从节点(只读节点)构成
如图:
image.png
特点:

  1. 主从复制模式的集群中只能有一个主节点,主节点提供所有的增、删、查、改服务,从节点不提供任何服务,但是可以通过设置使从节点提供查询服务,这样可以减少主节点的压力
  2. 每个从节点要知道主节点的地址,主节点记录在其上的所有操作,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。
  3. 在主从复制的集群中,当主节点出现故障时,只能人工介入,指定新的主节点,从节点不会自动升级为主节点。同时,在这段时间内,该集群架构只能处于只读状态。

    副本集

    副本集情况下的集群拥有一个主节点和多个从节点,这一点与主从复制模式类似,且主从节点所负责的工作也类似,但是副本集与主从复制的区别在于:当集群中主节点发生故障时,副本集可以自动投票,选举出新的主节点,并引导其余的从节点连接新的主节点,而且这个过程对应用是透明的。
    可以说,MongoDB 的副本集是自带故障转移功能的主从复制。
    如图:
    image.png
    特点:

  4. 在副本集中,任何节点都可作为主节点,但为了维持数据一致性,只能有一个主节点。

  5. 主节点负责数据的写入和更新,并在更新数据的同时,将操作信息写入名为 oplog 的日志文件当中。主节点还负责指定其他节点为从节点,并设置从节点数据的可读性,从而让从节点来分担集群读取数据的压力。从节点会定时轮询读取 oplog 日志,根据日志内容同步更新自身的数据,保持与主节点一致。
  6. 副本集中还有一个额外的仲裁节点(不需要使用专用的硬件设备),负责在主节点发生故障时,参与选举新节点作为主节点,不存储数据
  7. 副本集中的各节点会通过心跳信息来检测各自的健康状况,当主节点出现故障时,多个从节点会触发一次新的选举操作,并选举其中一个作为新的主节点。为了保证选举票数不同,副本集的节点数保持为奇数。

    分片

    副本集可以解决主节点发生故障导致数据丢失或不可用的问题,但遇到需要存储海量数据的情况时,副本集机制就束手无策了。
    副本集中的一台机器可能不足以存储数据,或者说集群不足以提供可接受的读写吞吐量。这就需要用到 MongoDB 的分片(Sharding)技术,这也是 MongoDB 的另外一种集群部署模式。
    分片是指将数据拆分并分散存放在不同机器上的过程。有时也用分区来表示这个概念。将数据分散到不同的机器上,不需要功能强大的大型计算机就可以存储更多的数据,处理更大的负载。
    MongoDB 支持自动分片,可以使数据库架构对应用程序不可见,简化系统管理。对应用程序而言,就如同始终在使用一个单机的 MongoDB 服务器一样。
    MongoDB 的分片机制允许创建一个包含许多台机器的集群,将数据集合分散在集群中,每个分片维护着一个数据集合的子集。与副本集相比,使用集群架构可以使应用程序具有更强大的数据处理能力。
    分片集群部署架构如图:
    image.png
    构建一个 MongoDB 的分片集群,需要三个重要的组件,分别是分片服务器(Shard Server)、配置服务器(Config Server)和路由服务器(Route Server)。

    Shard Server

    每个 Shard Server 都是一个 mongo 数据库实例,用于存储实际的数据块。整个数据库集合分成多个块存储在不同的 Shard Server 中。
    在实际生产中,一个 Shard Server 可由几台机器组成一个副本集来承担,防止因主节点单点故障导致整个系统崩溃。

    Config Server

    这是独立的一个 mongo 进程,保存集群和分片的元数据,在集群启动最开始时建立,保存各个分片包含数据的信息。可以理解为一个注册中心

    Route Server

    这是独立的一个 mongo 进程,Route Server 在集群中可作为路由使用,客户端由此接入,让整个集群看起来像是一个单一的数据库,提供客户端应用程序和分片集群之间的接口。
    Route Server 本身不保存数据,启动时从 Config Server 加载集群信息到缓存中,并将客户端的请求路由给每个 Shard Server,在各 Shard Server 返回结果后进行聚合并返回客户端。

    10.ObjectId

    Object ID 类似于关系型数据库中的主键 ID,在 MongoDB 中 Object ID 由 12 字节的字符组成,其中:
  • 前 4 个字节表示当前的 Unix 时间戳;
  • 之后的 3 个字节是当前设备的机器标识码;
  • 再之后的 2 个字节是 MongoDB 服务器的进程 id;
  • 最后 3 个字节为计数器,计数器的起始值随机获得。

image.png

11.MongoDB的架构

image.png
如图,mongoDB的架构与Mysql类似,引擎层都分为了多种搜索引擎以便用户根据需求进行使用。
从MongoDB 3.2开始,WiredTiger存储引擎是默认的存储引擎。在这之前,默认的存储引擎为MMAPV1
Mongodb4.2版本不再支持MMAPv1存储引擎

MMAPV1引擎

顾名思义,mmapv1引擎是基于内存映射机制实现的数据读写,也正是因为如此,mmapv1不支持数据压缩。因此如果所有的数据全部都存储在内存当中,那么mmapv1引擎的效率会很高
直到2.6版本MMAPV1都是采用读-写 [1] 锁进行并发控制,即允许并发读访问一个数据库,但是对于相同库的单个写操作之间只能是排他性的【库级别锁】。这就意味着当有一个读锁存在的时候,任意其他读操作也能共用该读锁。而当一个单个写操作持有写锁的时候,其他任何读或写操作都不能共用该写锁,故只能等待。
从3.0版本开始,MMAPv1存储引擎采用集合级别锁,这也是对早期版本的改进,早期版本中,库锁是最细粒度的锁。因此mmapv1引擎对于并发的支持并不是很友好
mmap引擎将会使用机器所有的空闲内存作为自己的缓存。系统资源监控会显示MongoDB使用了大量的内存,但是这样的使用是动态的。假如有一个其他的进程突然想申请机器一半的内存,此时MonoDB将会让出自己的缓存内存给该进程使用。
从技术层面讲,MMAPV1引擎下的MongoDB内存由操作系统的虚拟内存子系统来管理。这就意味着MongoDB将使用尽可能多的空闲内存,并根据需要交换到磁盘。故给MongoDB足以覆盖所有热数据的内存容量将会使得MongoDB获得最佳的性能。

WiredTiger引擎

WiredTiger引擎支持的锁粒度比mmapv1更细,可以具体到文档级别。在大多数的读写场景下,WiredTiger都是使用乐观并发控制。多个客户端可以在同一时间同时修改一个集合中的多个文档
在大多数工作负载下,WiredTiger的性能要比MMAPV1高很多。WiredTiger引擎为现代多核系统量身定制,更好地发挥多核系统的处理能力。
WIredTiger引擎同样会进行数据的压缩,通常来讲有snappy(3~5)、zlip(5~7)、前缀压缩,zstd压缩四种算法。其中前缀压缩算法是针对索引而言的压缩算法

12.MongoDB数据的读写原理

以下所有均默认存储引擎为WiredTiger

写操作

  1. 在写操作时,首先会将对应的写操作记录写入journal日志(事务日志)的内存buffer中
  2. 之后会根据对应的写操作变更内存中的数据
  3. journal日志默认每个100毫秒将内存buffer中的数据同步磁盘一次,同步的方式为顺序写,每100M数据生成一个新的journal文件,journal默认使用了snappy压缩
  4. wiredTiger每隔60秒(默认)或者journal日志待写入的数据达到2G时,mongodb将对journal文件提交一个checkpoint来将数据变更刷新到磁盘
  5. checkpoint创建后,此前的journal日志即可清除。
  6. 当内存存储超过一定阈值时,mongo会触发内存淘汰机制淘汰掉部分数据释放内存

checkpoint:检测点,将内存中的数据变更flush到磁盘中的数据文件中,并做一个标记点,表示此前的数据表示已经持久存储在了数据文件中,此后的数据变更存在于内存和journal日志。
上述描述的数据持久化方案称为延迟持久化,延迟持久化可以提升磁盘效率,如果在提交checkpoint之前,mongodb异常退出,此后再次启动可以根据journal日志恢复数据。

读操作

通过内存映射(mmap)的方式,将磁盘中的数据映射到内存中,读取操作都是基于内存的。
由此可见,通过基于内存的数据读取。延迟持久化数据到磁盘的方式,mongo实现了在读写方面的性能最大化。
mongoDB的数据持久化最终是落在磁盘上的,只不过在读取数据时,通过内存映射方式将数据映射到内存中进行读写操作,所以个人认为mongoDB本质上更像一个硬盘数据库
mongo系统详细信息介绍:点击这里