MongoDB 之存储引擎

  • Post author:
  • Post category:其他


mongodb主要利用存储引擎来管理数据。mongodb为我们提供了多种存储引擎,我们可以根据不同需求来选择最合适的一个。


一、mongodb存储引擎种类


mongodb主要有3种存储引擎,分别是:

(1) WiredTiger

(2) MMAPv1

(3) In-Memory

下面分别介绍这三种存储引擎。


二、WiredTiger


MongoDB 3.0版本开始启用,64位版本。

MongoDB 3.2 成为默认存储引擎


(1) 文档级别的并发


WiredTiger 对写操作执行文档级别的并发控制,也就是说,在同一时间,可以修改一个集合中的不同文档。

针对大多数的读写操作,WiredTiger采取

乐观

的并发控制机制。WiredTiger 在全局、数据库和集合级别身上仅使用

意向锁

。当存储引擎检测到两个操作产生冲突时,其中

一个操作

会引发一个写冲突,促使mongodb显式的的重新执行该操作。

一些全局的操作,典型的有涉及多个库的短暂操作,需要

实例锁



一些像删除集合的操作,还需要

排他锁


(2) 快照和检查点


WiredTiger 使用多版本的并发控制(MVCC)。

一个操作开始时,WiredTiger 会为事务提供一个实时的数据快照,快照呈现内存中数据的一致性视图。

将数据写入磁盘时,WiredTiger 以一致性的方式将快照中的所有数据写入磁盘。检查点确保数据文件中所有的数据是一致的,并且包含最后一个检查点。检查点可以作为回复数据的点。mongodb配置WiredTiger 来创建检查点(即将快照数据写入磁盘),创建的时机是:每60秒或者当日志文件达到2G。

在写一个新检查点的过程中,上一个检查点仍然是有效的,如果写的过程中出现宕机或者其他异常,一旦重启成功,mongodb会从上一个有效的检查点恢复数据。

当WiredTiger的元数据表关联到新的检查点时,该新的检查点才是可访问和持久的,此时,会释放老检查点的页。


(3) 日志文件系统Journal


默认提交时间间隔为100毫秒。

WiredTiger使用预写事务日志与检查点结合的方式来确保数据持久化。即开启Journal功能,Journal会记录在两个检查点之间的所有修改,当mongodb突然退出并重启之后,WiredTiger会根据Journal中的记录恢复最后一个检查点之后发生的数据修改。

Journal用snappy库压缩。用storage.wiredTiger.engineConfig.journalCompressor指定其他的压缩算法或者不采用压缩策略。WiredTiger 最小的日志记录大小是128字节,如果记录为128字节或者更小,则不会压缩该条记录。

将storage.journal.enabled设置为False,则不会启动Journaling。

对单实例而言,如果禁用journal意味着我们会丢失mongodb异常终止后上一个有效检查点之后的所有数据。对于复制集(主从的mongodb集群)中的一些成员来说,复制过程可能提供充分的持久性保证。


(4) 压缩


使用WiredTiger存储引擎,mongodb支持压缩所有集合和索引。压缩以使用额外的CPU为代价来降低存储消耗。WiredTiger 对集合采用块压缩(使用snappy压缩库或者zlib),对索引采用前缀压缩。可以通过配置来更改压缩方式,换用其他压缩算法或者不进行压缩。再建立一个集合或者一个索引的时候,可以为其制定压缩方式。对于大多数的工作负载,默认的压缩设置会平衡存储效率和处理需求。


(5) 内存使用


使用WiredTiger存储引擎,MongoDB 既会使用WiredTiger的内部缓存,也会使用文件系统的缓存.

从MongoDB3.4开始,WiredTiger 内部缓存会使用下面两个数中的较大者:

a. RAM的50% 减去1 GB

b. 256MB

对于文件系统缓存,MongoDB会自动使用除WiredTiger内部缓存以及其他进程占用内存的所有空闲内存。文件系统中的缓存会被压缩。

想要调整WiredTiger的内部缓存, 可以参考storage.wiredTiger.engineConfig.cacheSizeGB和wiredTigerCacheSizeGB.

避免增加WiredTiger内部缓存的大小超过其默认值。


三、MMAPv1


MMAPv1是MongoDB基于内存映射的最初的存储引擎,它在大量的读写和就地更新的任务上有很好的表现。从3.2版本开始,MMAPv1 不在是默认的存储引擎。

注意:big-endian架构不支持MMAPv1存储引擎,如果在大端机器上采用该存储引擎,会报错。

Endian表示数据在存储器中的存放顺序

,采用大端方式 进行数据存放符合人类的正常思维,而采用小端方式进行数据存放利于计算机处理。大端指低地址存放最高有效字节,小端是指低地址存放最低有效字节。

例如:我们要存储一个16进制的数0x31323334;

小端机器的存储方式为:

低地址 –> 高地址

34 33 32 31

大端机器的存储方式为:

低地址 –> 高地址

31 32 33 34


(1) Journal


为了确保所有的数据都被持久化到磁盘,MongoDB默认将所有修改都保存到磁盘的日志文件中,MongoDB写日志文件要比写数据文件频繁。


storage.syncPeriodSecs

:设置数据文件存储时间间隔,默认60秒。

不要在生产环境设置该参数,在几乎所有场景,你都应该用该默认的参数

,如果将该参数设置为0,MongoDB 将不会同步内存映射文件到磁盘。


storage.journal.commitIntervalMs

:默认值为100毫秒或30毫秒,取值范围是0~500毫秒,取值越低,数据持久性越高,但是会牺牲磁盘性能。

默认日志存储时间间隔为100毫秒。但是如果日志文件被存储在于数据文件不同的区块设备上,例如physical volume, RAID device, or LVM volume,默认日志提交间隔会变为30毫秒,此外, when a write operation with j:true is pending, 提交的时间间隔将要变成设置值的三分之一。

在许多情况下,MongoDB 和操作系统更新数据到磁盘要比设置的时间间隔频繁的多,所以,以上的设置值只是理论上的最大值。

当mongod实例异常退出时,MongoDB 可以根据这些数据文件恢复数据库。


(2) 记录存储特性


所有记录都是连续的存储在磁盘上,当一条记录被更新并且超出原来分配的记录大小,则需要重新分配一个记录,之后将文档移动到新记录中,并且更新与文档相关的所有索引。这显然比原地更新记录要花费更多的时间,同时还会导致存储碎片。

从3.0版本开始,分配策略有所改变。


(3) 记录分配策略


从3.0版本开始,MongoDB使用Power of 2 Sized Allocations策略,将一个文档存储到一条记录中,同时记录中还有额外的空间,这些额外的空间允许更新操作带来的文档大小的增长,使得重新分配内存的可能新降到最低。

不同的分配策略支持不同种类的操作:


the power of 2 allocations

:对insert/update/delete操作更加有效; 采用该策略之后,所有记录的大小均为2的n次幂字节。对于大于

2MB

的文档,分配将要向上取整到2MB的倍数。该策略有以下两个关键特性:

  • 能重新使用释放的记录来减少碎片。
  • 能减少文档移动,但是不能完全消除重新分配的情况。


exact fit allocations(No Padding Allocation Strategy)

:对没有更新和删除操作的集合更理想。

对于那些没有改变文档大小操作或者只有插入操作的集合,我们可以将the power of 2 allocations设置为无效。在3.0版本以前,MongoDB 通过动态计算填充大小来作为文档大小的因素。


(4) 内存使用


采用MMAPv1存储引擎,MongoDB自动使用机器所有空闲的内存作为它的缓存,系统资源监控显示,MongoDB用了许多内存,但是它的使用是动态的,当其他进程需要使用内存时,MongoDB会放弃部分缓存所占用的内存给其他进程。

从技术上来说,操作系统的虚拟内存子系统管理着MongoDB内存,这意味着MongoDB会尽可能多的使用空闲内存,当需要的是有也会切换到磁盘,部署足够的内存来适应工作数据集将会获得做好的性能。


三、In-Memory(内存存储引擎)


(1) 并发性


内存存储引擎使用文档级别的并发控制,可以在同一时刻对不同文档进行更新操作。


(2) 内存使用


内存存储引擎要求它的所有数据必须符合在命令行参数(–inMemorySizeGB)或者在YAML配置文件中设置的内存大小。

默认情况下,内存存储引擎使用物理RAM的50%减去1 GB的内存。

如果一个写操作超出指定的内存大小,mongodb将会报错,错误信息如下:

“WT_CACHE_FULL: operation would overflow cache”


(3) 持久化


内存存储引擎是

非持久性

的,不会持久化数据。非持久化的数据包括应用程序数据,系统数据,例如用户、权限、索引、副本设置配置、分片集群配置等。数据库正常或者异常关闭的情况下,数据均不可恢复。

在采用内存存储引擎,或者其他存储引擎但是关闭了Journal功能是,必须将writeConcernMajorityJournalDefault参数设置为False。


(4) 部署结构


除了作为单实例运行,采用内存存储引擎的mongod实例也可以作为副本集或者分片集群的一部分。

  • 作为副本集的一部分

    例如,一个有三个成员的副本集,其结构可以为:

    两个mongod实例运行在In-Memory存储引擎上

    另外一个mongod实例运行在WiredTiger存储引擎上,并将该实例配置为隐藏成员。

    在该配置结构下,只有采用IN-memory的数据库实例会被选举为最主要者,客户端只会连接到该实例上。即使两个使用In-memory的数据库实例均死机或者重启,他们都会从运行在WiredTiger的实例上同步数据。隐藏的数据库实例会将用户数据、索引和其他复制配置信息都持久化到磁盘上。

  • 作为分片集群的一部分

    例如,一个有三个成员的分片集群,其结构可以为:

    两个mongod实例运行在In-Memory存储引擎上

    另外一个mongod实例运行在WiredTiger存储引擎上,并将该实例配置为隐藏成员。

    为分片加inmem标签。如果该分片的名字为”shardC”,则连接mongos ,然后运行sh.addShardTag(“shardC”, “inmem”),对于其他的分片,分别添加一个persisted 标签,

    sh.addShardTag(“shardA”, “persisted”)

    sh.addShardTag(“shardB”, “persisted”)

    对于每个应该驻留在内存中的分片集合,分配给整块范围的inmem标签。

    sh.addTagRange(“test.analytics”, { shardKey: MinKey }, { shardKey: MaxKey }, “inmem”)

对于每个应该驻留在持久化中的分片集合,分配给整块范围的persisted标签。:

sh.addTagRange(“salesdb.orders”, { shardKey: MinKey }, { shardKey: MaxKey }, “persisted”)

对于内存中的分片,创建一个数据库或者移动一个数据库。



版权声明:本文为u011300968原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。