考虑到 ttl 和磁盘 i/o 创建 mongo 文档的最佳方式
Optimal way to create mongo documents with a ttl and disk i/o in mind
考虑到磁盘 i/o 比率,在 Mongo 数据库中使用 TTL 索引的最佳策略是什么。
前言:
我在集群 mongodb (v2.*) 基础设施上工作,其中每个节点都有大约 1TB 的硬盘。
在那里,日志信息会保存 7 天。在那之后,它们就不再需要了,应该被删除。有 6 个数据库,每个数据库有 10 个馆藏,每个馆藏超过 1000 万份文件。假设我们每天存储 100GB 的临时数据。
因此我在 createdAt 字段上创建了一个简单的索引。
db.my_collection.ensureIndex( { "createdAt": 1 }, { expireAfterSeconds: 604800, background : true });
这将删除在放入 createdAt
的时间戳后 7 天插入此集合的所有文档。这对我来说很清楚。但我不确定如何创建将保存到集合中的文档。
后台索引的 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”上 "expired"。
亲:
- 每天午夜过后不久,磁盘使用量应下降 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”上 "expired"。
亲:
- 文档保存正好 7 天。
- 磁盘 io 将在一整天内几乎保持不变。干扰其他进程的可能性较小。
缺点:
- 查看是否有错误不像选项 1 那样容易,因为文件将在一天内被删除。
磁盘使用量不会大幅增加。
(选项 3):
我想这应该和选项2一样。不过我想在这里提一下。
我们还可以将索引更改为在特定时间后但在特定日期不会过期。
db.my_collection.ensureIndex( { "deleteAt": 1 }, { expireAfterSeconds: 0, background : true });
然后这样创建对象:
'deleteAt' => new MongoDate(strtotime("+7 days")),
你认为最好的可能性是什么?有没有人有过这样的经验 problem/infrastructure ?我很想从经验丰富的 mongodb 开发人员那里得到一些反馈。
免责声明:我绝不是PHP开发者,所以我不能给你任何PHP代码。
这里的问题是你想删除一天开始时的所有数据。因此,当 TTL 任务在 00:00 之后第一次运行时,它会尝试删除所有文档,正如您所写的那样
但是,您的假设并不十分准确。如果日志条目是今天 16:00 创建的,那么保留一周(604800 秒)的确切到期日期将是 2015 年 4 月 16 日星期四 16:00 .
因此,将磁盘 IO 分散到 TTL 后台进程的 1440 次运行中的最简单方法是不仅使用日期作为参考,还使用时间作为参考。
但是,您很可能只想显示 过去六天加上今天的条目。这很容易通过限制查询中的结果来实现。给定一个文档结构,如
{
_id: <SomeObjectId>,
entry: "Something happened!"
createdAt: ISODate("2015-04-02T09:11:27.038Z")
}
您可以select所有相关条目就像
一样简单
db.logentries.find({createdAt:{$gt:ISODate("2015-04-03T00:00:00.000Z") } })
这将 return 从现在开始六天前的所有条目加上今天的条目。显然,在这种情况下你必须做一些日期计算。
考虑到磁盘 i/o 比率,在 Mongo 数据库中使用 TTL 索引的最佳策略是什么。
前言:
我在集群 mongodb (v2.*) 基础设施上工作,其中每个节点都有大约 1TB 的硬盘。 在那里,日志信息会保存 7 天。在那之后,它们就不再需要了,应该被删除。有 6 个数据库,每个数据库有 10 个馆藏,每个馆藏超过 1000 万份文件。假设我们每天存储 100GB 的临时数据。
因此我在 createdAt 字段上创建了一个简单的索引。
db.my_collection.ensureIndex( { "createdAt": 1 }, { expireAfterSeconds: 604800, background : true });
这将删除在放入 createdAt
的时间戳后 7 天插入此集合的所有文档。这对我来说很清楚。但我不确定如何创建将保存到集合中的文档。
后台索引的 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”上 "expired"。
亲:
- 每天午夜过后不久,磁盘使用量应下降 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”上 "expired"。
亲:
- 文档保存正好 7 天。
- 磁盘 io 将在一整天内几乎保持不变。干扰其他进程的可能性较小。
缺点:
- 查看是否有错误不像选项 1 那样容易,因为文件将在一天内被删除。 磁盘使用量不会大幅增加。
(选项 3):
我想这应该和选项2一样。不过我想在这里提一下。
我们还可以将索引更改为在特定时间后但在特定日期不会过期。
db.my_collection.ensureIndex( { "deleteAt": 1 }, { expireAfterSeconds: 0, background : true });
然后这样创建对象:
'deleteAt' => new MongoDate(strtotime("+7 days")),
你认为最好的可能性是什么?有没有人有过这样的经验 problem/infrastructure ?我很想从经验丰富的 mongodb 开发人员那里得到一些反馈。
免责声明:我绝不是PHP开发者,所以我不能给你任何PHP代码。
这里的问题是你想删除一天开始时的所有数据。因此,当 TTL 任务在 00:00 之后第一次运行时,它会尝试删除所有文档,正如您所写的那样
但是,您的假设并不十分准确。如果日志条目是今天 16:00 创建的,那么保留一周(604800 秒)的确切到期日期将是 2015 年 4 月 16 日星期四 16:00 .
因此,将磁盘 IO 分散到 TTL 后台进程的 1440 次运行中的最简单方法是不仅使用日期作为参考,还使用时间作为参考。
但是,您很可能只想显示 过去六天加上今天的条目。这很容易通过限制查询中的结果来实现。给定一个文档结构,如
{
_id: <SomeObjectId>,
entry: "Something happened!"
createdAt: ISODate("2015-04-02T09:11:27.038Z")
}
您可以select所有相关条目就像
一样简单db.logentries.find({createdAt:{$gt:ISODate("2015-04-03T00:00:00.000Z") } })
这将 return 从现在开始六天前的所有条目加上今天的条目。显然,在这种情况下你必须做一些日期计算。