在MongoDB中,最大化写入日常日志文档的性能的策略

jto*_*ron 13 io mongodb nosql

我们有一组日志数据,其中集合中的每个文档都由MAC地址和日历日标识.基本上:

{
  _id: <generated>,
  mac: <string>,
  day: <date>,
  data: [ "value1", "value2" ]
}
Run Code Online (Sandbox Code Playgroud)

每隔五分钟,我们会在当天的文档中向数据数组添加一个新的日志条目.当我们为每个MAC创建一个新文档时,该文档将在午夜UTC结束.

我们已经注意到,IO(按写入的字节数衡量)会整天增加,然后在UTC午夜降回.这不应该发生,因为日志消息的速率是不变的.我们认为意外行为是由于Mongo移动文档,而不是更新其日志数组.对于它的价值,stats()显示paddingFactor是1.0299999997858227.

几个问题:

  1. 有没有办法确认Mongo是否正在更新或移动?我们在慢查询日志中看到了一些动作,但这似乎是轶事证据.我知道我可以db.setProfilingLevel(2),然后db.system.profile.find(),最后寻找"moved:true",但我不确定是否可以在繁忙的生产系统上执行此操作.
  2. 每个文档的大小都是非常可预测和有规律的.假设mongo正在做很多动作,那么找出Mongo能够更准确地预测的原因的最佳方法是什么?或者让Mongo更准确地说明一下?假设上面对问题的描述是正确的,那么调整填充因子似乎不会成功.
  3. 我应该很容易对文档进行预先处理并从Mongo中删除任何猜测.(我知道填充因子文档说我不应该这样做,但我只需要把这个问题放在我身后.)什么是预设文档的最佳方法?编写带有垃圾字节数组字段的文档似乎很简单,然后立即从文档中删除该字段,但是我应该注意哪些问题?例如,我可以想象在删除垃圾字段之前必须在服务器上等待写操作(即执行安全写操作).
  4. 我担心大约在同一时间预先分配所有一天的文档,因为当时这似乎会使磁盘饱和.这是一个有效的问题吗?我应该尝试分摊前一天的预分配费用吗?

jto*_*ron 4

以下组合似乎会导致写入性能急剧下降:

  1. 日记已开启。
  2. 将附加条目写入数组,该数组构成较大文档的大部分

据推测,I/O 已饱和。改变这些因素中的任何一个似乎可以防止这种情况发生:

  1. 关闭日记功能。请改用更多副本。
  2. 使用较小的文档。请注意,此处的文档大小以字节为单位,而不是文档中任何数组的长度。
  3. 在单独的文件系统上记录日志。

此外,这里还有一些提高写入吞吐量的其他技巧。除了分片之外,我们发现改进是增量式的,而我们试图解决“这根本不起作用”之类的问题,但我将它们包含在此处,以防您正在寻求增量式改进。10Gen 人员做了一些测试并得到了类似的结果

  1. 碎片。
  2. 将长数组分解为多个数组,使整体结构看起来更像是嵌套树。如果您使用一天中的小时作为键,那么每日日志文档将变为:
    {"0":[...], "1":[...],...,"23":[...]}
  3. 尝试手动预分配。(这对我们没有帮助。Mongo 的填充似乎像广告中那样工作。我原来的问题被误导了。)
  4. 尝试不同的 --syncdelay 值。(这对我们没有帮助。)
  5. 尝试不进行安全写入。(我们已经对日志数据这样做了,但在很多情况下这是不可能的。而且,这似乎有点作弊。)

您会注意到,为了完整起见,我在这里复制了 10Gen 的一些建议。希望我做得这么准确!如果他们发布了食谱示例,那么我将在此处发布一个链接。