【问题标题】:WiredTiger and in-place updatesWiredTiger 和就地更新
【发布时间】:2022-02-21 21:12:31
【问题描述】:

我有一组用户。每个用户都有一个经常更新的“地理位置”字段(每次用户显着移动时)。由于我希望在更新时在文档级别而不是集合级别上实现并发,因此我使用的是 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)。我错过了什么?

【问题讨论】:

  • 你读过那句话之后的那句话吗?它说“将重写整个文件”。这意味着$set WT 将读取文档、应用补丁并覆盖文档,而 mmapv1 只会覆盖该字段。我认为这与压缩有关。
  • “数据库大小会增长得很快吗” - 好问题,但很容易测试。创建一个测试数据库并对其进行几亿次就地更新。前后检查数据库大小。
  • @SergioTulentsev :是的,但我想确认一下,因为我不明白现在大多数(如果不是全部)硬盘驱动器的扇区大小为 4096 字节,你不能写入hardrive 仅 4 个字节(例如),但您必须写入 4096 个字节的完整块(因此先读取它,更新其中的 4 个字节,然后再写入)。由于大多数文档通常小于 4096 字节,这意味着它看起来与 MMAP 中的行为相同……我错过了什么?
  • 你在想一个错误的抽象。 “覆盖这个 10 字节字段”与“将这个脏映射页提交到磁盘”是分开完成的。后者由操作系统完成,与前者关系不大,后者是实际的就地更新。
  • 仅供参考,我回答了一个相关(但有些不同)的问题,恰好出现在侧边栏中:Does performing a partial update on a MongoDB document in WiredTiger provide any advantage over a full document update?

标签: mongodb wiredtiger


【解决方案1】:

使用旧版 MMAPv1 存储引擎(在 MongoDB 4.2 中已删除),就地更新经常被强调为一种优化策略,因为文档的索引直接指向文件位置和偏移量。将文档移动到新的存储位置(特别是如果有许多索引条目要更新)对于 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 自 MongoDB 3.2 以来一直是默认存储引擎,而 MMAPv1 不支持一些较新的产品功能。例如,MMAPv1 不支持Majority Read Concern,这反过来意味着它不能用于Replica Set Config Servers(MongoDB 3.4+ 中的分片所需)或Change Streams(MongoDB 3.6+)。 MMAPv1 在 MongoDB 4.0 和 removed in MongoDB 4.2 中已弃用。

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

存储结果取决于几个因素,包括您的架构设计、工作负载、配置和 MongoDB 服务器的版本。 MMAPv1 和 WiredTiger 使用不同的记录分配策略,但两者都将尝试使用标记为空闲/可重用的预分配空间。一般来说,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 Path To Transactions 系列视频,了解 MongoDB 4.0 中支持多文档事务的功能开发。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    相关资源
    最近更新 更多