MongoDB体系结构
MongoDB是一个基于分布式文件存储的数据库,由 C++ 编写,可以为 WEB 应用提供可扩展、高性能、易部署的数据存储解决方案,同时MongoDB是一个介于关系型数据库和非关系型数据库之间的产品,是非关系型数据库中功能最丰富的,最像关系型数据库的,在高负载的情况下,通过添加更多的节点,可以保证服务器的性能。结构体系图如下所示:
从上图中可以看出MongoDB一个实例可以对应多个数据库,数据库里存放的也是文档,如果要以关系型数据库的概念去理解这些概念名词,可以看下表:
| database数据库 | database数据库 |
|---|---|
| table表 | collection集合 |
| row行 | document BSON文档 |
| column列 | field字段 |
| index 唯一索引、主键索引 | index 支持地理位置索引、全文索引、哈希索引 |
| join 主外键关联 | embedded Document 嵌套文档 |
| primary key 指定1至N个列做主键 | primary key 指定_id field作主键 |
BSON
在上面提到了一个概念,也就是BSON,而BSON其实就是一种类似于JSON的一种二进制的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有着一些JSON没有的数据类型,BSON可以作为网络数据交换的一种存储形式,是一种schema-less存储形式,它的优点是灵活性高,但是它的缺点是空间利用率不是很理想。
BSON有着三个很重要的特点:轻量性、可遍历性、高效性。
MongoDB索引
索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。可以理解为索引其实就是书的目录,可以根据目录中的页码可以快速找到对应的内容,相反,如果没有索引,也就相当于没有书的目录,想要查询一些数据,只能翻整本书,也就是进行全表查询,数据量很大时严重降低了查询效率。
默认情况下,MongoDB在一个集合创建时,自动的对集合的_id创建了唯一索引。
索引类型
- 单键索引 (Single Field)
MongoDB支持所有数据类型中的单个字段索引,并且可以在文档的任何字段上定义。
对于单个字段索引,索引键的排序顺序无关紧要,因为MongoDB可以在任一方向读取索引。
特殊的单键索引 过期索引 TTL ( Time To Live)
TTL索引是MongoDB中一种特殊的索引, 可以支持文档在一定时间之后自动过期删除,目前TTL索引
只能在单字段上建立,并且字段类型必须是日期类型。 - 复合索引(Compound Index)
通常我们需要在多个字段的基础上搜索表/集合,这是非常频繁的。 如果是这种情况,我们可能会考虑在MongoDB中制作复合索引。 复合索引支持基于多个字段的索引,这扩展了索引的概念并将它们扩展到索引中的更大域。
制作复合索引时要注意的重要事项包括:字段顺序与索引方向。 - 多键索引(Multikey indexes)
针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引,Multikey indexes支持strings,numbers和nested documents - 地理空间索引(Geospatial Index)
针对地理空间坐标数据创建索引。
2dsphere索引,用于存储和查找球面上的点
2d索引,用于存储和查找平面上的点 - 全文索引
MongoDB提供了针对String内容的文本查询,Text Index支持任意属性值为String或String数组元素的索引查询。注意:一个集合仅支持最多一个Text Index,中文分词不理想 推荐ES。 - 哈希索引 Hashed Index
针对属性的哈希值进行索引查询,当要使用Hashed index时,MongoDB能够自动的计算hash值,无需程序计算hash值。注:hash index仅支持等于查询,不支持范围查询
MongoDB 索引底层实现原理分析
MongoDB是文档型数据库,它使用的是BSON格式保存的数据,比关系型数据库更加方便。比如在MySQL中,表和表之间的关联关系,是十分复杂的,关联性强,区间访问是常见的一种情况,但是BSON可以把这一条数据和这条数据对应的数据存入一个BSON对象中。
比如在MySQL中的底层索引数据结构使用的是B+树,B+树的特点是所有的数据都存储在叶子节点上,并且通过指针串在一起,这样就很容易的进行区间遍历,甚至是全部遍历,而MongoDB使用的是B-树,它与B+树最大的不同就是B-树的所有节点上都有Data域,只要找到索引就可以进行访问,单次查询上从结构上来看会比MySQL快。
MongoDB架构
MongoDB的逻辑架构
MongoDB的架构和MySQL中的架构差不多,底层都是使用了可插拔的存储引擎以满足用户的不同需求,用户可以根据程序的数据特征选择不同的存储引擎,MongoDB默认是使用WiredTiger作为默认的存储引擎,WiredTiger提供了不同粒度的并发控制和压缩机制,能够为不同种类的应用提供最好的性能和存储率。
MongoDB的数据模型
- 内嵌
内嵌的方式指的是把相关联的数据保存在同一个文档结构之中。MongoDB的文档结构允许一个字段或者一个数组内的值作为一个嵌套的文档。
- 引用
引用方式通过存储引用信息来实现两个不同文档之间的关联,应用程序可以通过解析这些数据引用来访问相关数据。
那么如何去进行选择数据模型呢?下面给出一些建议:
- 选择内嵌:
- 数据对象之间有包含关系 ,一般是数据对象之间有一对多或者一对一的关系 。
- 需要经常一起读取的数据。
- 有 map-reduce/aggregation 需求的数据放在一起,这些操作都只能操作单个 collection。
- 选择引用:
- 当内嵌数据会导致很多数据的重复,并且读性能的优势又不足于覆盖数据重复的弊端 。
- 需要表达比较复杂的多对多关系的时候 。
- 大型层次结果数据集 嵌套不要太深。
MongoDB存储引擎
存储引擎概述
存储引擎是MongoDB的核心组件,它是负责管理数据如何将存储在硬盘和内存上的,MongoDB支持的存储引擎有MMAPv1,WiredTiger和InMemory,但是在MongoDB4.X版本就不再支持MMAPv1存储引擎了。
WiredTiger存储引擎
从MongoDB3.2开始,WiredTiger就已经是MongoDB默认的存储引擎了。
文档级并发
WiredTiger使用文档级并发控制进行写操作。多个客户端可以同时修改集合的不同文档。
对大多数读取和写入操作,WiredTiger使用乐观并发控制。WiredTiger仅在全局,数据库和集合使用意图锁。当存储引擎检测到两个操作存在冲突的时候,将引发写冲突,从而导致MongoDB透明地重试该操作。
一些全局操作(通常是涉及多个数据库的短暂操作)仍然需要全局“实例范围”锁。某些其他操作仍然需要排他数据库锁定。
快照和检查点
WiredTiger使用MVCC机制,在操作开始的时候,WiredTiger为操作提供数据的时间点快照,快照提供了内存数据的一致视图。写入磁盘时,WiredTiger将所有数据文件中的快照中的所有数据以一致的方式写入磁盘。现在持久的数据充当数据文件中的检查点。该检查点可确保数据文件直到最后一个检查点(包括最后一个检查点)都保持一致,即检查点可以充当恢复点。
从版本3.6开始,MongoDB将WiredTiger配置以60s的间隔创建检查点(即,将快照数据写入到磁盘中)。在早期版本,MongoDB将检查点设置为在WiredTiger中以60s的间隔或在写入2GB日记数据时对用户数据进行检查,以先到者为准。
在写入新检查点期间,先前的检查点仍然有效,这样在MongoDB写入新检查点终止时,或者遇到错误时,在重新启动的时候,MongoDB可以在上一个检查点中进行恢复。
日志
WiredTiger将预写日志(即日志),与检查点结合以确保数据的持久性。
WiredTiger日志保留检查点之间的所有数据修改。如果MongoDB在检查点之间退出,它将使用日志重播上一个检查点依赖修改的所有数据。
压缩
使用WiredTiger,MongoDB支持对所有的集合和索引进行压缩。压缩可以最大程度的减少存储使用量,但是会增加CPU的开销。