存储引擎是一个数据库的组成部分,它控制着数据在内存和磁盘中如何存取。在项目开发中,为数据库选择一个好的、适合的存储引擎并深入了解该存储引擎的运作和利弊,对于每个开发者来说也很重要。MongoDB作为时下很流行的一款NoSQL数据库,它也支持了很多种存储引擎,下面简单分析一下它们的特点。
一、MMAPv1
MMAPv1是MongoDB 3.0.0版本之前的默认存储引擎,它是基于内存映射文件存储的。在大批量插入、读取和定向修改方面,性能表现出色。下面从三个方面分析该存储引擎的相关特点:
1、Journal:
为了确保所有数据持久化到硬盘,MongoDB将所有的变动日志都存了下来。MongoDB每60s持久化一次数据,但是存储日志的频率却是0.1s。存储数据的频率和存储日志的频率可以分别在
storage.syncPeriodSecs
和
storage.journal.commitIntervalMs
中设置。MongoDB可以在退出后通过日志恢复数据。
2、Record Storage Characteristics:
在创建一条记录文档的时候,MongoDB会依据所支持的众多记录分配策略,来为文档分配填充空间。由于MongoDB的数据文档在硬盘上是连续存储的,所以这个备用的填充可以减少文档被修改(尤其是增加内存)后重新被分配定位的可能。重新定位比定向修改更低效,而且会产生存储碎片。总之,填充因子以牺牲硬盘空间的方式换来了更高的执行效率和更少的存储碎片。使用
collMod命令或使用
db.createCollection()可以禁用策略。
典型的记录分配策略:
power of 2 sized allocations
3、Memory Use
MongoDB可以自动地把空闲内存转化为自己的缓存,系统资源监控器显示它消耗很大的内存;但它是动态的,当其他应用需要内存时,MongoDB会动态的分给它们。
在技术实现上,其实是操作系统的虚拟内存子系统管理着MongoDBd的内存。这就意味着,MongoDB在能把硬盘转化为内存的情况下,会尽可能多的使用空闲空间。所以,足够的空间使得MongoDB在被使用的过程中表现的很好。
二、WiredTiger
WiredTiger是MongoDB 3.2版本之后的默认存储引擎,而且只要我们不通过参数--storageEngine 或者
storage.engine命令进行相应修改,MongoDB就会在参数--dbpath
或者命令
storage.dbPath所指定的路径下创建数据存储文件。下面从五个方面分析该存储引擎的相关特点:
1、Document Level Concurrency
众所周知,数据在MongoDB中是以文件形式存储的。WiredTiger存储引擎对于MongoDB数据的写操作是做文件级别的并发控制(Document Level Concurrency),因此,不同的客户端可以同时修改同一个表(collection)的不同数据行(document)。
①对于大部分的读和写操作,WiredTiger使用乐观的并发控制。在MongoDB的全局、数据库和表级别,WiredTiger都是用的意向锁(intent locks)。在两个不同的操作间检测到冲突的时候,存储引擎会促使MongoDB令两者中有写相关的操作发起有感知的重试,直到另一个操作完成。
②对于一般的、涉及到多个数据库的全局操作,WiredTiger还会用到实例级别的全局锁。
③对于其他的操作,像删除一个表,WiredTiger还会用到排它锁。
2、Snapshots and Checkpoints
在数据持久化、数据一致性和数据恢复方面,WiredTiger使用的是多版本并发控制(MVCC)。在一个数据库操作开始的时候,WiredTiger会根据数据接下来的操作提供一个即时的快照(Snapshot),该快照和当时内存中的数据是一致的。在往硬盘写数据的时候,WiredTiger也会先在硬盘上对所有的存储数据写一个快照。但是这个并非一层不变(每次快照基本都有修改)的数据,却扮演了一个检查点(Checkpoints)的角色。检查点确保了数据库中的数据能同最后一个Checkpoint中的数据一致且包含最后一个Checkpoint。也就是说,最后一个Checkpoint可以作为MongoDB数据恢复的依据。一旦有新的
checkpoint创建,旧的
checkpoint就会被清除。
自从MongoDB3.6版本以后,每间隔60s会创建一个
checkpoint,即写Snapshot数据到硬盘。
由上可知,在最新的
checkpoint创建之后和下一个
checkpoint创建之前,MongoDB在意外情况下仍然有可能丢数据,所以
journaling不可或缺。
3、Journal
如今大部分数据库都支持先写log再写数据的策略,就是保证数据不先于日志写入磁盘,这种日志称为
write-ahead transaction log。WiredTiger正是在各个checkpoint之间,组合使用了这种策略来保证数据的安全完整性。关于该日志系统具体如何实现的,可以参考
https://docs.mongodb.com/manual/core/journaling/#journal-process
。
WiredTiger使用
snappy
compression library压缩这些日志,最小压缩单位为128 bytes,小于这个大小不会被压缩。也可以使用命令
storage.wiredTiger.engineConfig.journalCompressor来修改压缩算法或者不压缩日志。
可以通过设置
storage.journal.enabled为false来减少维护日志的开销。但是对于独自运行的数据库实例,一旦MongoDB发生宕机等意外,将意味着会失去最新checkpoint之后的数据。
4、Compression
WiredTige为MongoDB的表(collection)和索引都提供了压缩,不过也带来了额外的CPU开销。默认情况下,对于数据是块压缩(
block compression),对于索引是前缀压缩(
prefix compression)。
对于表的压缩,可以使用
zlib,
对于索引的压缩,可以通过命令
storage.wiredTiger.indexConfig.prefixCompression来控制。
对于单个的collection和index的压缩也可以在其创建的时候进行配置,参考
Specify Storage Engine Options
和
db.collection.createIndex() storageEngine option
。
5、Memory Use
对于使用WiredTiger存储引擎的MongoDB,它们不仅采用了WiredTiger内部缓存(
WiredTiger internal cache),还使用了文件系统缓存(
filesystem cache)。自从MongoDB 3.4版本以来,WiredTiger内部缓存的大小是这么决定的:在50% of (RAM - 1 GB)和256 MB中取最大值。
数据在WiredTiger内部缓存和文件系统缓存的呈现形式是不同的:
①数据在文件系统缓存和在磁盘中的格式是一样的;
②索引在WiredTiger内部缓存中加载,不同于磁盘数据中的格式;
③表(collection)数据在WiredTiger内部缓存中是不被压缩的,而且呈现方式不同于磁盘中的数据。
WiredTiger内部缓存的大小可以通过命令
storage.wiredTiger.engineConfig.cacheSizeGB
或 参数
--wiredTigerCacheSizeGB
来调节。
三、In-Memory
自从MongoDB Enterprise version 3.2.6,开始使用了In-Memory Storage Engine。该存储引擎和其它不同的是,除了元数据(
metadata)和诊断数据(
diagnostic data)保存在磁盘意外,其它数据都不保存到磁盘,包括配置、索引和用户认证等。下面从四个方面分析该存储引擎的相关特点:
1、Specify In-Memory Storage Engine
①命令行:mongod --storageEngine inMemory --dbpath <path>
②或者yaml文件中配置:
storage:
engine: inMemory
dbPath: <path>
2、Concurrency
同WiredTiger一样,In-Memory存储引擎对于MongoDB数据的写操作也是做文件级别的并发控制(Document Level Concurrency),因此,不同的客户端可以同时修改同一个表(collection)的不同数据行(document)。
3、Memory Use
In-Memory存储引擎要求它的所有数据必须遵循参数
--inMemorySizeGB或命令
storage.inMemory.engineConfig.inMemorySizeGB所指定的设置。默认情况下,
in-memory storage engine使用的内存是物理内存的50%减去1GB(
50% of physical RAM minus 1 GB)。如果一个写操作占用内存超过了阈值,MongoDB会报如下错误:"WT_CACHE_FULL: operation would overflow cache"。重写设置阈值的命令为
storage.inMemory.engineConfig.inMemorySizeGB或者在YAML文件中配置:
storage:
engine: inMemory
dbPath: <path>
inMemory:
engineConfig:
inMemorySizeGB: <newSize>
或者使用命令行:mongod --storageEngine inMemory --dbpath <path> --inMemorySizeGB <newSize>
4、Durability
in-memory和其它存储引擎不同,它是一个非持久化(
non-persistent)类型的存储引擎,这些数据包括application data and system data, such as users, permissions, indexes, replica set configuration, sharded cluster configuration等等,而且
journal
的概念也没有被用到该引擎当中。
使用该存储引擎的MongoDB建议和使用其它引擎的MongoDB组成副本集联合使用。
四、参考
MongoDB Docs:
https://docs.mongodb.com/
WiredTiger
:
http://wiredtiger.com
Copyright © 2018 Ansel. All rights reserved.