常见问题:MongoDB 存储

在本页面

本文档解决了 MongoDB 存储系统的常见问题。

存储引擎基础知识

什么是存储引擎?

存储引擎是数据库的一部分,负责管理数据在 memory 和磁盘上的存储方式。许多数据库支持多个存储引擎,其中不同的引擎对特定工作负载的性能更好。例如,一个存储引擎可能为 read-heavy 工作负载提供更好的 performance,而另一个可能支持更高的写操作吞吐量。

也可以看看 存储引擎

你可以在副本集中混合存储引擎吗?

是。您可以拥有使用不同存储引擎的副本集成员。

在设计这些 multi-storage 引擎部署时,请考虑以下事项:

  • 每个成员上的 oplog 可能需要以不同的大小来计算不同存储引擎之间的吞吐量差异。

  • 如果备份从 MongoDB 捕获数据 files,备份恢复可能会变得更加复杂:您可能需要维护每个存储引擎的备份。

WiredTiger 存储引擎

我可以将现有部署升级到 WiredTiger 吗?

是。看到:

WiredTiger 提供多少压缩?

压缩数据与未压缩数据的比率取决于您的数据和使用的压缩 library。默认情况下,WiredTiger 中的集合数据使用Snappy 块压缩; zlib压缩也可用。索引数据默认使用前缀压缩

我应该设置 WiredTiger 内部缓存的大小?

使用 WiredTiger,MongoDB 同时使用 WiredTiger 内部缓存和文件系统缓存。

从 MongoDB 3.4 开始,默认的 WiredTiger 内部缓存大小是以下两者中的较大者:

  • 50%(RAM - 1 GB),或

  • 256 MB。

注意 在某些情况下,例如在容器中运行时,数据库可能具有低于总系统 memory 的 memory 约束。在这种情况下,此 memory 限制而不是总系统 memory 用作可用的最大 RAM。 要查看 memory 限制,请参阅hostInfo.system.memLimitMB

默认情况下,WiredTiger 对所有集合使用 Snappy 块压缩,对所有索引使用前缀压缩。压缩默认值可在 global level 中配置,也可在收集和索引创建期间以 per-collection 和 per-index 为基础进行设置。

WiredTiger 内部缓存中的数据与 on-disk 格式使用不同的表示形式:

  • 文件系统缓存中的数据与 on-disk 格式相同,包括对数据 files 进行任何压缩的好处。操作系统使用文件系统缓存来减少磁盘 I/O。

  • 在 WiredTiger 内部缓存中加载的索引具有与 on-disk 格式不同的数据表示,但仍可利用索引前缀压缩来减少 RAM 使用。索引前缀压缩从索引字段中重复删除 common 前缀。

  • WiredTiger 内部缓存中的集合数据是未压缩的,并使用与 on-disk 格式不同的表示形式。块压缩可以节省大量的 on-disk 存储空间,但数据必须解压缩才能由服务器进行操作。

通过文件系统缓存,MongoDB 自动使用 WiredTiger 缓存或其他进程未使用的所有免费 memory。

要调整 WiredTiger 内部缓存的大小,请参阅storage.wiredTiger.engineConfig.cacheSizeGB--wiredTigerCacheSizeGB。避免将 WiredTiger 内部缓存大小增加到其默认值 value 之上。

注意 storage.wiredTiger.engineConfig.cacheSizeGB 限制了 WiredTiger 内部缓存的大小。操作系统将使用可用的免费 memory 进行文件系统缓存,这允许压缩的 MongoDB 数据文件保留在 memory 中。此外,操作系统将使用任何空闲 RAM 来缓冲文件系统块和文件系统缓存。 为了容纳额外的 RAM 使用者,您可能必须减少 WiredTiger 内部缓存大小。

默认的 WiredTiger 内部高速缓存大小 value 假定每台机器有一个mongod实例。如果单个计算机包含多个 MongoDB 实例,则应减少该设置以容纳其他mongod实例。

如果您在一个容器中运行mongod(e.g. lxccgroups,Docker,etc.),它们无法访问系统中可用的所有 RAM,则必须将storage.wiredTiger.engineConfig.cacheSizeGB设置为小于容器中可用 RAM 量的 value。确切的数量取决于 running 在容器中的其他进程。请参阅memLimitMB

要查看有关缓存和逐出率的统计信息,请参阅serverStatus命令返回的wiredTiger.cache字段。

WiredTiger 写入磁盘的频率如何?

  • 检查点

    • 从 version 3.6 开始,MongoDB 配置 WiredTiger 以 60 秒的间隔创建检查点(i.e.将快照数据写入磁盘)。在早期版本中,MongoDB 设置检查点在 WiredTiger 中以 60 秒的间隔在用户数据上发生,或者在写入 2 GB 的日志数据时,以先发生者为准。
  • 期刊数据

    • MongoDB 根据以下间隔或条件写入磁盘:
  • MongoDB 每隔 50 毫秒将缓冲的日志数据同步到磁盘(从 MongoDB 3.2 开始)

  • 如果写入操作包括j:true的写入问题,则 WiredTiger 强制同步 WiredTiger 日志 files。

  • 由于 MongoDB 使用的日志文件大小限制为 100 MB,因此 WiredTiger 大约每 100 MB 数据创建一个新的日志文件。当 WiredTiger 创建新的日志文件时,WiredTiger 会同步以前的日志文件。

如何在 WiredTiger 中回收磁盘空间?

WiredTiger 存储引擎在删除文档时维护数据 files 中的空记录列表。此空间可以由 WiredTiger 重用,但除非在非常特定的情况下,否则不会返回到操作系统。

可供 WiredTiger 重用的空白空间量反映在标题wiredTiger.block-manager.file bytes available for reuse下的db.collection.stats()输出中。

要允许 WiredTiger 存储引擎将此空白空间释放到操作系统,您可以 de-fragment 您的数据文件。这可以使用紧凑命令来实现。有关其行为和其他注意事项的更多信息,请参阅紧凑

MMAPv1 存储引擎

什么是 memory 映射 files?

memory-mapped 文件是一个文件,其中包含操作系统通过mmap()系统调用放置在 memory 中的数据。 mmap()因此 maps 文件到虚拟 memory 的区域。 Memory-mapped files 是 MongoDB 中 MMAPv1 存储引擎的关键部分。通过使用 memory 映射 files,MongoDB 可以将其数据 files 的内容视为 memory。这为 MongoDB 提供了一种访问和操作数据的极快且简单的方法。

memory 映射 files 如何工作?

MongoDB 使用 memory 映射的 files 来管理和交互所有数据。

Memory 映射将 files 分配给具有直接 byte-for-byte 相关性的虚拟 memory 块。 MongoDB memory maps 数据 files 到 memory 访问文档时。未访问的数据未映射到 memory。

映射后,file 和 memory 之间的关系允许 MongoDB 与文件中的数据进行交互,就好像它是 memory 一样。

MMAPv1 写入磁盘的频率如何?

MMAPv1 存储引擎的默认 configuration 中,MongoDB 每隔 60 秒写入磁盘上的数据 files,并且大约每 100 毫秒写入日志 files。

要更改写入数据 files 的间隔,请使用storage.syncPeriodSecs设置。对于期刊 files,请参阅storage.journal.commitIntervalMs设置。

这些值表示完成写入操作与 MongoDB 写入数据 files 或 journal files 之间的最大 time 时间。在许多情况下 MongoDB 和操作系统更频繁地将数据刷新到磁盘,因此上述值代表理论上的最大值。

为什么我的数据目录中的 files 大于数据库中的数据?

数据目录中的数据 files(默认配置中的/data/db目录)可能大于插入数据库的数据集。考虑以下可能的原因:

预分配数据 files

MongoDB 预先分配其数据 files 以避免文件系统碎片,因此,这些 files 的大小不一定反映数据的大小。

storage.mmapv1.smallFiles选项将减小这些 files 的大小,如果磁盘上有许多小型数据库,这可能很有用。

oplog

如果此mongod是副本集的成员,则数据目录包含oplog.rs文件,该文件是local数据库中的预分配上限集合

默认分配大约是 64-bit 安装上磁盘空间的 5%。在大多数情况下,您不需要调整 oplog 的大小。有关更多信息,请参见Oplog 大小调整

日记

数据目录包含 journal files,在 MongoDB 将数据应用于数据库之前,它们会在磁盘上执行 store 写操作。见日记

空记录

MMAPv1 存储引擎在删除文档和集合时维护数据 files 中的空记录 lists。此空间可以在同一数据库中重新用于新的 record 分配,但默认情况下,MMAPv1 不会将此空间返回给操作系统。

要允许 MMAPv1 存储引擎更有效地重用空记录中的空间,您可以您的数据。要 de-fragment,请使用紧凑命令。 紧凑需要最多 2 千兆字节的额外磁盘空间来运行。如果磁盘空间严重不足,请不要使用紧凑。有关其行为和其他注意事项的更多信息,请参阅紧凑

紧凑仅从集合中的 MongoDB 数据 files 中删除碎片,并且不会向操作系统返回任何磁盘空间。要_返回操作系统的磁盘空间,请参阅如何回收磁盘空间?

如何回收磁盘空间?

注意 您无需为 MongoDB 回收磁盘空间以重用已释放的空间。有关重用空闲空间的信息,请参见空记录

对于副本集的辅助成员,可以通过停止辅助成员重新同步,从成员的数据目录中删除所有数据和子目录,然后重新启动辅助成员来执行重新同步成员。有关详细信息,请参阅重新同步副本集的成员

通过dropDatabase删除未使用的数据库也将删除关联的数据 files 并释放磁盘空间。

什么是工作集?

工作集表示 application 在正常操作过程中使用的数据总体。通常这是总数据大小的子集,但工作集的特定大小取决于数据库的实际 moment-to-moment 使用。

如果您运行需要 MongoDB 扫描集合中每个文档的查询,工作集将展开以包含每个文档。根据物理存储器大小,这可能会导致工作集中的文档“分页”,或者被操作系统从物理 memory 中删除。下一个 time MongoDB 需要访问这些文件, MongoDB 可能会导致硬页面错误。

为了获得最佳性能,大多数 active 集应该适合 RAM。

什么是页面错误?

使用 MMAPv1 存储引擎时,页面错误可能会发生,因为 MongoDB 从数据读取数据或将数据写入当前未位于 physical memory 中的部分数据文件。相反,当物理 memory 耗尽且物理 memory 页面交换到磁盘时,会发生操作系统页面错误。

如果有 free memory,那么操作系统可以在磁盘上找到该页面并直接将其加载到 memory。但是,如果没有 free memory,操作系统必须:

  • 在 memory 中找到陈旧或不再需要的页面,并将该页面写入磁盘。

  • 从磁盘读取请求的页面并将其加载到 memory。

在 active 系统上,此 process 可能需要 long time,特别是与读取已存在于 memory 中的页面相比。

有关更多信息,请参见页面错误

软页面和硬页面错误有什么区别?

当具有 MMAP 存储引擎的 MongoDB 需要访问当前不在 active memory 中的数据时,会发生页面错误。 “硬”页面错误是指 MongoDB 必须访问磁盘才能访问数据的情况。相反,“软”页面错误仅将 memory 页面从一个列表移动到另一个列表,例如从操作系统文件缓存移动。

有关更多信息,请参见页面错误

我可以手动填充文档以防止更新期间的移动吗?

更改了 version 3.0.0.

使用MMAPv1 存储引擎时,如果文档的大小增加,更新可能会导致文档在磁盘上移动。为了最小化文档移动,MongoDB 使用填充

您不必手动填充,因为默认情况下,MongoDB 使用2 大小分配的力量添加自动填充2 大小分配的力量确保 MongoDB 以 2 的幂大小分配文档空间,这有助于确保 MongoDB 可以有效地重用文档删除或重定位创建的可用空间,并在许多情况下减少重新分配的发生。

但是,如果必须手动填充文档,则可以向文档添加临时字段,然后$unset字段,如下面的示例所示。

警告 不要手动填充上限集合中的文档。将手动填充应用于上限集合中的文档可以 break 复制。此外,如果您 re-sync MongoDB 实例,则不会保留填充。

var myTempPadding = [ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"];

db.myCollection.insert( { _id: 5, paddingField: myTempPadding } );

db.myCollection.update( { _id: 5 },
                        { $unset: { paddingField: "" } }
                      )

db.myCollection.update( { _id: 5 },
                        { $set: { realField: "Some text that I might have needed padding for" } }
                      )

也可以看看 Record 分配策略

数据存储诊断

如何查看集合的大小?

要查看集合的统计信息(包括数据大小),请使用mongo shell 中的db.collection.stats()方法。以下示例为orders集合发出db.collection.stats()

db.orders.stats();

MongoDB 还提供以下方法来_retret 集合的特定大小:

以下脚本打印每个数据库的统计信息:

db.adminCommand("listDatabases").databases.forEach(function (d) {
   mdb = db.getSiblingDB(d.name);
   printjson(mdb.stats());
})

以下脚本打印每个数据库中每个集合的统计信息:

db.adminCommand("listDatabases").databases.forEach(function (d) {
   mdb = db.getSiblingDB(d.name);
   mdb.getCollectionNames().forEach(function(c) {
      s = mdb[c].stats();
      printjson(s);
   })
})

如何检查集合的各个索引的大小?

要查看为每个索引分配的数据大小,请使用db.collection.stats()方法并检查返回文档中的indexSizes字段。

如果索引使用前缀压缩(即WiredTiger 的默认值),则该索引的返回大小将反映压缩大小。

如何获取有关数据库存储使用的信息?

mongo shell 中的db.stats()方法返回“active”数据库的当前 state。有关返回字段的说明,请参阅dbStats 输出