管理和减少 MongoDB 磁盘空间占用的最佳实践

借助这份全面的最佳实践指南,优化您的 MongoDB 磁盘空间使用。了解压缩集合和索引、识别并删除不必要的索引以及利用 WiredTiger 压缩功能的有效策略。探索如何实现数据归档、管理 oplog 大小并主动监控磁盘空间,以防止系统中断并提高性能。本文提供了可操作的见解和实用示例,旨在帮助您的 MongoDB 部署保持精简高效。

35 浏览量

管理和减少 MongoDB 磁盘空间使用的最佳实践

MongoDB 是一个流行的 NoSQL 文档数据库,以其灵活性和可扩展性而闻名。然而,如果缺乏主动管理,磁盘空间使用量可能会快速增长,导致性能下降、系统中断和基础设施成本增加。了解 MongoDB 如何消耗磁盘空间并实施有效的管理策略,对于维护健康高效的数据库环境至关重要。

本文深入探讨了管理和减少 MongoDB 磁盘空间的综合策略。我们将探索实用的技术,例如压缩集合、优化和处理大型索引、配置存储引擎设置以提高效率,以及实施数据生命周期策略。遵循这些最佳实践,您可以防止不必要的磁盘增长,确保操作稳定,并延长您的 MongoDB 部署的寿命。

了解 MongoDB 磁盘空间消耗

MongoDB 将磁盘空间用于以下几个组件:

  • 数据文件(Data Files):存储集合中实际的 BSON 文档。
  • 索引文件(Index Files):存储为支持高效查询执行而创建的 B 树索引。
  • 日志文件(Journal Files (WiredTiger)):在写入操作应用于数据文件之前进行记录,确保数据持久性。这些是预先分配的。
  • 操作日志(Oplog (Operational Log)):副本集中的特殊固定大小集合,用于记录所有写入操作。对复制至关重要。
  • 诊断数据(Diagnostic Data):日志、mongod 进程文件和其他系统相关信息。

随着时间的推移,由于更新、删除和文档增长(填充),集合和索引可能会变得碎片化或包含未使用的已分配空间,从而导致磁盘使用效率低下。即使数据库不再需要这些空间来存放实时数据,操作系统也不会立即回收这些“空白空间”。

减少 MongoDB 磁盘空间的策略

1. 压缩集合和索引

压缩操作通过更有效地重写数据文件和索引文件,帮助回收未使用的磁盘空间。这在大量数据删除或更新后特别有用。

压缩集合

对于 WiredTiger 存储引擎(MongoDB 3.2 之后的默认引擎),compact 主要用于回收已删除文档的可用空间并对集合进行碎片整理。它 不会 像 MMAPv1 的 compact 操作那样从头开始重建集合的数据文件。

db.runCommand({ compact: "myCollection" })

compact 的注意事项:

  • compact 操作会消耗大量资源(CPU、I/O),并且需要相当长的时间,特别是对于大型集合。通常最好在维护窗口期间或在副本集的辅助成员上运行。
  • 它要求有 等于 被压缩集合大小的可用磁盘空间,因为它会在交换之前在一个新位置重建数据。
  • 对于分片集群,请在每个分片上独立运行 compact

重建索引

索引也可能变得碎片化。重建索引可以回收空间,并有可能提高查询性能。

db.myCollection.reIndex()

reIndex() 的注意事项:

  • 从 MongoDB 4.2 开始,reIndex() 是一个在线操作(需要足够的磁盘空间来创建新索引)。对于 4.2 之前的版本,它会对数据库(而不仅仅是集合)施加写锁,从而阻塞所有其他操作。建议首先在辅助成员上运行 reIndex(),然后降级主节点,在新主节点上执行此操作。
  • compact 类似,reIndex() 在操作期间需要额外的磁盘空间。

repairDatabase(离线操作)

对于严重的碎片化或数据损坏,repairDatabase 可以重建所有数据文件。这是一个离线操作,需要停止 mongod 实例。

mongod --repair

警告repairDatabase 应该作为空间回收的最后手段,因为它如果不谨慎处理可能是一个破坏性操作,并且可能需要很长时间。请务必提前进行备份。

2. 优化索引

索引对性能至关重要,但也会消耗大量磁盘空间。未使用或冗余的索引纯粹是开销。

识别和删除不必要的索引

定期审查您的索引,确保它们仍然是必需的。

  1. 列出集合的所有索引:
    javascript db.myCollection.getIndexes()
  2. 监控索引使用情况: 启用数据库性能分析(db.setProfilingLevel(1))或使用 db.collection.stats() 来查看索引利用率。云监控工具通常会提供关于索引使用的深入见解。
  3. 识别重复或冗余的索引: 例如,如果查询可以使用复合索引,则在 { a: 1, b: 1 } 上的索引会使在 { a: 1 } 上的索引变得冗余。对于仅涉及 ab 的查询,{ a: 1, b: 1, c: 1 } 上的索引也会覆盖 { a: 1, b: 1 } 上的索引。

一旦确定,删除未使用的索引:

db.myCollection.dropIndex("indexName")

提示:在将删除索引的操作应用于生产环境之前,务必在预演(staging)环境中测试其影响。

使用部分索引(Partial Indexes)

部分索引仅对满足指定筛选表达式的集合中的文档进行索引。这减少了被索引的文档数量,从而节省了磁盘空间并提高了写入性能。

db.orders.createIndex(
   { customerId: 1, orderDate: -1 },
   { partialFilterExpression: { status: "active" } }
)

如果大多数订单是“非活跃”的,此索引将只包含 status 为“active”的文档,从而大幅减小其大小。