WiredTiger和就地更新

时间:2018-04-01 08:28:15

标签: mongodb wiredtiger

我有一组用户。每个用户都有一个字段" locationosition"经常更新(每次用户移动时)。由于我希望在更新时在文档级别而不是集合级别上进行并发,因此我使用的是WiredTiger存储引擎。

我了解到,使用WiredTiger,文档中的每次更新都会导致创建新文档:

  

http://learnmongodbthehardway.com/schema/wiredtiger/

     

WiredTiger不支持就地更新

然而,这篇文章也说"即使[WiredTiger]不允许就地更新,对于许多工作负载来说仍然可以比MMAP表现更好"。这是什么意思?当我使用WiredTiger时,我必须注意哪些具体含义?例如,如果没有就地更新,数据库大小会快速增长吗?还有其他事情需要注意吗?

我还了解到MongoDB 3.6中的WiredTiger增加了存储增量的功能,而不是重写整个文档(https://jira.mongodb.org/browse/DOCS-11416)。这究竟是什么意思?

注意:另外我不明白的是,现在大多数(如果不是全部)硬盘驱动器的扇区大小为4096字节,因此您只能写入硬盘驱动器4字节(例如)但必须写入4096字节的完整块(因此首先读取它,更新其中的4个字节然后写入它)。因为大多数文件经常< 4096字节这意味着在任何情况下都需要重写整个文档(即使使用MMAP)。我错过了什么?

1 个答案:

答案 0 :(得分:8)

使用MMAPv1存储引擎,就地更新经常被突出显示为优化策略,因为文档的索引直接指向文件位置和偏移。将文档移动到新的存储位置(特别是如果要更新的索引条目很多),MMAPv1的开销比只需更新更改的字段的就地更新要多。请参阅:Record Storage Characteristics in MMAPv1

WiredTiger不支持就地更新,因为它在内部使用MVCC (Multiversion concurrency control),即commonly used by database management systems。这是对MMAP中简单化视图的重大技术改进,并允许构建更高级的功能,如isolation levels和事务。 WiredTiger的索引具有间接级别(引用内部RecordID而不是文件位置和偏移),因此在存储级别的文档移动不是一个重要的痛点。

  

然而,本文还说"尽管[WiredTiger]不允许就地更新,但对于许多工作负载而言,它仍然可以比MMAP表现更好"。

这意味着尽管MMAPv1可能具有更高效的就地更新路径,但WiredTiger还具有其他优势,例如压缩和改进的并发控制。您可以构建一个工作负载,该工作负载仅包含可能在MMAPv1中执行得更好的一些文档的就地更新,但实际工作负载通常更加多样化。确认给定工作负载的影响的唯一方法是在代表性环境中进行测试。

但是,如果您想要规划未来,MMAPv1与WiredTiger的一般选择没有实际意义:WiredTiger一直是默认存储引擎,因为MMAPv1不支持MongoDB 3.2和一些较新的产品功能。例如,MMAPv1不支持Majority Read Concern,这反过来意味着它不能用于Replica Set Config Servers(MongoDB 3.4+中的分片所需)或Change Streams(MongoDB 3.6+)。 MongoDB(4.0)的下一个主要版本中的MMAPv1 will be deprecated,目前计划在MongoDB 4.2中删除。

  

使用WiredTiger时,我必须注意哪些具体含义?例如,如果没有就地更新,数据库大小会迅速增长吗?

存储结果取决于多种因素,包括架构设计,工作负载,配置和MongoDB服务器版本。 MMAPv1和WiredTiger使用不同的记录分配策略,但两者都会尝试使用标记为free / reusable的预分配空间。通常,WiredTiger在使用存储空间方面更有效,并且还具有压缩数据和索引的优势。 MMAPv1 allocates additional storage space尝试优化就地更新并避免文档移动,尽管您可以选择"无填充"收集策略,其中工作负载不会随着时间的推移而改变文档大小。

自从MongoDB 3.0首次推出WiredTiger以来,为改进和调整WiredTiger进行了大量投资,因此我强烈建议您使用最新的产品发布系列进行测试,以获得最佳结果。如果您对架构设计和存储增长有特定问题,我建议在DBA StackExchange上发布详细信息以供讨论。

  

我还了解到MongoDB 3.6中的WiredTiger增加了存储增量的功能,而不是重写整个文档(https://jira.mongodb.org/browse/DOCS-11416)。这究竟是什么意思?

这是一个实现细节,可以针对某些用例改进WiredTiger的内部数据结构。特别是,MongoDB 3.6+中的WiredTiger可以更有效地处理大型文档的小变化(与之前的版本相比)。 WiredTiger缓存需要能够返回多个版本的文档,只要它们由开放的内部会话(MVCC,如前所述)使用,因此对于具有小更新的大型文档,存储增量列表可能更有效。但是,如果累积的增量太多(或者增量正在改变文档中的大多数字段),则这种方法可能不如维护整个文档的多个副本。

当数据通过检查点提交到磁盘时,仍需要编写完整版本的文档。如果您想了解更多关于内部的内容,那么在开发支持MongoDB 4.0中的多文档事务的功能之后,会有MongoDB Path To Transactions系列视频。

  

另外我不明白的是,现在大多数(如果不是全部)硬盘驱动器的扇区大小为4096字节,所以你不能只写4个字节(例如),而是必须写4096字节的完整块(首先读取它,更新其中的4个字节然后再写入)。因为大多数文件经常< 4096字节这意味着在任何情况下都需要重写整个文档(即使使用MMAP)。我错过了什么?

如果不深入了解实现细节并尝试解释所涉及的所有移动部分,请考虑不同的方法如何应用于更新许多文档(而不是单个文档级别)的工作负载以及对内存的影响用法(在将文档写入磁盘之前)。根据文档大小和压缩等因素,单个I / O块可以表示从文档的一小部分(最大大小为16MB)到多个文档的任何位置。

在MongoDB中,一般流程是在内存视图(例如,WiredTiger缓存)中更新文档,其中更改在periodically flushed to the data files之前以快速仅附加日志格式保留到磁盘。如果O / S只需要写入已更改的数据块,则触摸较少的数据块需要较少的总体I / O.