我有一组用户。每个用户都有一个“地理位置”字段,该字段经常更新(每次用户显著移动时)。由于我希望在更新时在文档级别而不是集合级别上并发,所以我使用的是WiredTiger存储引擎。
我了解到,使用WiredTiger,文档中的每一个更新都会导致创建一个新文档:
http://learnmongodbthehardway.com/schema/wiredtiger/ WiredTiger不支持就地更新。
然而,本文也指出,“即使WiredTiger不允许就地更新,对于许多工作负载,仍然可以比MMAP表现得更好”。什么意思?当我使用WiredTiger时,我必须知道的确切含义是什么?例如,如果没有就地更新,数据库的大小会快速增长吗?还有其他的事情需要注意吗?
我还了解到,WiredTiger在MongoDB 3.6中增加了存储三角洲的功能,而不是重写整个文档(https://jira.mongodb.org/browse/DOCS-11416)。这到底是什么意思?
注意:我还不明白的是,现在大多数(如果不是全部)硬盘的扇区大小为4096字节,所以您不能只向硬盘写入4个字节(例如),而是必须写入4096字节的完整块(所以首先读取它,更新其中的4个字节,然后写入)。由于大多数文档通常都是< 4096字节,这是否意味着重写整个文档在任何情况下都是必要的(即使使用MMAP)。我错过了什么?
发布于 2018-04-03 06:47:21
使用遗留的MMAPv1存储引擎(在MongoDB 4.2中删除),就地更新经常被突出显示为优化策略,因为文档索引直接指向文件位置和偏移量。将文档移动到新的存储位置(特别是当有许多索引项要更新时),MMAPv1的开销要比只需更新已更改的字段的就地更新要多。
WiredTiger不支持就地更新,因为在内部它使用多版本并发控制,即数据库管理系统常用。与MMAP中的简化视图相比,这是一个重大的技术改进,并允许构建更高级的特性,如隔离水平和事务。WiredTiger的索引有一定程度的间接(引用内部RecordID而不是文件位置和偏移),因此在存储级别上的文档移动不是一个显著的痛苦点。
然而,本文也指出,“即使WiredTiger不允许就地更新,对于许多工作负载,它仍然可以执行比MMAP更好的性能”。
这意味着尽管MMAPv1可能有更有效的就地更新路径,但WiredTiger还有其他优势,比如压缩和改进的并发控制。您也许可以构造一个工作负载,其中只包含对少数文档的就地更新,这些文档在MMAPv1中的性能可能更好,但是实际的工作负载通常会更多变化。确认对给定工作负载的影响的唯一方法是在具有代表性的环境中进行测试。
但是,如果您想为未来做计划,那么MMAPv1与WiredTiger的一般选择是没有意义的:自从MongoDB 3.2以来,WiredTiger一直是默认的存储引擎,而且MMAPv1不支持一些较新的产品特性。例如,MMAPv1不支持多数读为关切,这意味着它不能用于复制集Config服务器 (在MongoDB 3.4+中需要切分)或变更流 (MongoDB 3.6+)。MMAPv1在MongoDB 4.0和在MongoDB 4.2中删除中被否决。
当我使用WiredTiger时,我必须知道的确切含义是什么?例如,如果没有就地更新,数据库的大小会快速增长吗?
存储结果取决于几个因素,包括模式设计、工作负载、配置和MongoDB服务器的版本。MMAPv1和WiredTiger使用不同的记录分配策略,但都将尝试使用标记为空闲/可重用的预先分配的空间。一般来说,WiredTiger在使用存储空间时效率更高,而且它还具有数据和索引压缩的优点。MMAPv1 分配额外的存储空间尝试为就地更新进行优化并避免文档移动,尽管您可以为工作负载不会随时间改变文档大小的集合选择“无填充”策略。
自从WiredTiger首次在MongoDB 3.0中引入以来,在针对不同工作负载的改进和调优方面投入了大量资金,因此我强烈鼓励使用最新的产品发行版系列进行测试,以获得最佳结果。如果您有关于模式设计和存储增长的特定问题,我建议在DBA StackExchange上发布详细信息以供讨论。
我还了解到,WiredTiger在MongoDB 3.6中增加了存储三角洲的功能,而不是重写整个文档(https://jira.mongodb.org/browse/DOCS-11416)。这到底是什么意思?
这是一个实现细节,它为某些用例改进了WiredTiger的内部数据结构。特别是,WiredTiger In MongoDB 3.6+可以更有效地处理大型文档的小更改(与以前的版本相比)。WiredTiger缓存需要能够返回多个版本的文档,只要这些文档被开放的内部会话使用(如前所述,MVCC),因此对于更新较小的大型文档,存储增量列表可能更有效。但是,如果积累了太多的增量(或者增量正在更改文档中的大多数字段),这种方法的性能可能不如维护完整文档的多个副本。
当数据通过检查点提交到磁盘时,仍然需要编写文档的完整版本。如果您想了解更多关于内部机制的信息,可以在MongoDB 事务路径系列视频中开发支持MongoDB 4.0中多文档事务的特性。
另外,我不明白的是,现在大多数(如果不是全部)硬盘驱动器的扇区大小为4096字节,因此您不能只向硬盘写入4个字节(例如),而是必须写入4096字节的完整块(所以首先读取它,更新其中的4个字节,然后写入它)。由于大多数文档通常都是< 4096字节,这是否意味着重写整个文档在任何情况下都是必要的(即使使用MMAP)。我错过了什么?
在不深入讨论实现细节和试图解释所涉及的所有移动部分的情况下,请考虑不同的方法如何应用于正在更新多个文档(而不是在单个文档级别)的工作负载,以及对内存使用的影响(在将文档写入磁盘之前)。根据文档大小和压缩等因素,一个I/O块可以表示从文档的一部分(最大大小为16 on )到多个文档的任何地方。
在MongoDB中,通常的流程是在内存中的视图(例如,WiredTiger缓存)中更新文档,在成为定期刷新到数据文件。之前,以快速附加的日志格式将更改持久化到磁盘。如果O/S只需编写已更改的数据块,则接触较少的数据块需要更少的整体I/O。
https://stackoverflow.com/questions/49596247
复制相似问题