1

考虑到磁盘 i/o 比率,在 Mongo DB 中使用 TTL 索引的最佳策略是什么。

前言

我在集群 mongodb (v2.*) 基础架构上工作,其中每个节点都有大约 1TB 的硬盘。在那里,日志信息会保存 7 天。在那之后,它们不再需要并且应该被删除。有 6 个数据库,每个数据库有 10 个集合,每个集合超过 1000 万个文档。假设我们每天要存储 100GB 的临时数据。

因此,我在 createdAt 字段上创建了一个简单的索引。

  db.my_collection.ensureIndex( { "createdAt": 1 }, { expireAfterSeconds: 604800, background : true });

这将在时间戳记 7 天后删除所有插入此集合的文档createdAt。这对我来说很清楚。但我不确定如何创建将保存到集合中的文档。

背景索引的 mongo 文档状态:

The background task that removes expired documents runs every 60 seconds.

问题

在考虑未来删除时,创建该 TTL 索引的最佳方法是什么。

例如,这里有 3 种方法可以创建要保存的对象。我使用的语法是 php 但没关系。

选项1:

   'createdAt' => new MongoDate(strtotime(date('Y-m-d')))

在这里,今天创建的所有文档都将保存,例如“2015-04-09 00:00:00”的创建时间。这意味着所有文档都将在“2015-04-16 00:00:00”“过期”。

临:

  • 每天午夜后不久,磁盘使用量应减少 100GB。
  • 您可以轻松查看是否存在错误。如果磁盘使用量没有下降,就会出现问题。

缺点:

  • 删除 100GB 的数据将导致巨大的磁盘 io 并可能减慢其他进程。
  • 由于缺少小时和分钟,这些文件的保存时间不到 7 天。

选项 2:

   'createdAt' => new MongoDate(strtotime(date('Y-m-d h:i:s')))

在这里,所有创建的文档都有不同的创建时间,例如“2015-04-09 13:23:45”。这意味着此示例文档将在“2015-04-16 13:23:45”“过期”。

临:

  • 文档将准确保存 7 天。
  • 磁盘 io 将在一整天内几乎保持不变。干扰其他进程的可能性较小。

缺点:

  • 查看是否有错误不像选项 1 那样容易,因为文档将在一天中被删除。磁盘使用量不会有很大的跳跃。

(选项 3):

我认为这应该与选项 2 相同。不过我想在这里提一下。

我们还可以将索引更改为在特定时间后但在特定日期不过期。

db.my_collection.ensureIndex( { "deleteAt": 1 }, { expireAfterSeconds: 0, background : true });

然后以这种方式创建对象:

'deleteAt' => new MongoDate(strtotime("+7 days")),

你认为最好的可能性是什么?有没有人遇到过这样的问题/基础设施?我很想从经验丰富的 mongodb 开发人员那里得到一些反馈。

4

1 回答 1

1

免责声明:我绝不是 PHP 开发人员,所以我不能给你任何 PHP 代码。

这里的问题是您想在一天开始时删除所有数据。因此,当 TTL 任务在 00:00 之后第一次运行时,它会尝试删除所有文档,如您所写

但是,您的假设并不十分精确。如果在今天 16:00 进行日志条目,则保留一周(604800 秒)的确切到期日期将是 2015 年 4 月 16 日星期四16:00

因此,在 TTL 后台进程的 1440 次运行中分散磁盘 IO 的最简单方法是不仅使用日期作为参考,还使用时间。

但是,您很可能只想显示过去六天加上今天的条目。这很容易通过限制查询中的结果来实现。给定一个文档结构,如

{
  _id: <SomeObjectId>,
  entry: "Something happened!"
  createdAt: ISODate("2015-04-02T09:11:27.038Z")
}

您将能够像选择所有相关条目一样简单

db.logentries.find({createdAt:{$gt:ISODate("2015-04-03T00:00:00.000Z") } })

这将返回从现在起六天前加上今天的所有条目。显然,在这种情况下,您必须进行一些日期计算。

于 2015-04-09T13:48:53.270 回答