如果 MongoDB 中插入过多会发生什么?如何确保存储所有数据?

lum*_*ric 26 mongodb

我使用 MongoDB 来存储定期测量的值。每大约 100 毫秒,就会将一堆值作为文档插入。它工作正常,但我担心性能问题。(我使用安全插入,似乎在 PyMongo 中这是默认设置。)

如果每秒插入的次数超过 mongod 能够保存到硬盘的次数,会发生什么?会不会有任何警告,还是会默默地失败?

有什么方法可以监控写负载?我发现只有db.serverStatus().writeBacksQueued当我调用它时总是设置为 false。如何测试必须插入多少数据才能填满写入队列?

mongostat显示锁。这是我应该担心的事情吗?

insert  query update delete getmore command flushes mapped  vsize    res faults  locked db idx miss %     qr|qw   ar|aw  netIn netOut  conn repl       time 
  *117     *0     *0     *0       0     2|0       0  17.4g  35.3g  3.76g      0     .:6.5%          0       0|0     0|0   124b     6k     2  SLV   09:58:10 
  *111     *0     *0     *0       0     2|0       0  17.4g  35.3g  3.76g      0     .:0.8%          0       0|0     0|0   124b     6k     2  SLV   09:58:11 
  *111     *0     *0     *0       0     2|0       0  17.4g  35.3g  3.76g      0     .:4.2%          0       0|0     0|0   124b     6k     2  SLV   09:58:1
Run Code Online (Sandbox Code Playgroud)

我需要担心写锁吗?在写锁定时间段内插入会发生什么?它是否排队并稍后存储?

我正在考虑使用一个主设备和一个从设备进行简单的复制设置。初始同步或重新同步过程是否锁定了数据库?

(我使用的是 2.4.3 版。)

更新: 我认为已经部分回答了我自己的问题。我设法使用一个简单的 while 循环插入一个小测试文档,每秒插入 12.000 次。但是qr|qw还是显示有读写队列还是空的:

insert  query update delete getmore command flushes mapped  vsize    res faults       locked db idx miss %     qr|qw   ar|aw  netIn netOut  conn repl       time 
 11234     *0      2     *0    1563     1|0       1  21.9g  44.3g  1.22g      0    testdb:58.9%          0       1|0     1|1   797k   980k     6  PRI   10:26:32 
 12768     *0      2     *0    1284     1|0       0  21.9g  44.3g  1.22g      0    testdb:58.0%          0       0|0     0|1   881k     1m     6  PRI   10:26:33 
 12839     *0      2     *0    1231     1|0       0  21.9g  44.3g  1.22g      0    testdb:60.3%          0       0|0     0|1   883k     1m     6  PRI   10:26:34 
 12701     *0      2     *0     910     1|0       0  21.9g  44.3g  1.22g      0    testdb:61.8%          0       0|0     0|1   858k     1m     6  PRI   10:26:35 
 12241     *0      2     *0    1206     1|0       0  21.9g  44.3g  1.22g      0    testdb:56.7%          0       0|0     0|0   843k     1m     6  PRI   10:26:36 
 11581     *0      2     *0    1406     1|0       0  21.9g  44.3g  1.22g      0    testdb:61.8%          0       0|0     0|1   811k     1m     6  PRI   10:26:37 
  8719     *0      2     *0    1210     1|0       0  21.9g  44.3g  1.22g      0    testdb:43.8%          0       0|0     0|1   618k   762k     6  PRI   10:26:38 
 11429     *0      2     *0    1469     1|0       0  21.9g  44.3g  1.22g      0    testdb:60.6%          0       0|0     0|1   804k   993k     6  PRI   10:26:39 
 12779     *0      2     *0    1092     1|0       0  21.9g  44.3g  1.22g      0    testdb:60.2%          0       1|0     0|1   872k     1m     6  PRI   10:26:40 
 12757     *0      2     *0     436     1|0       0  21.9g  44.3g  1.22g      0    testdb:59.7%          0       0|0     0|1   838k   432k     6  PRI   10:26:41 
Run Code Online (Sandbox Code Playgroud)

我想这意味着单独插入不会造成很多麻烦:“如果您在执行大量写入操作以及其他大量写入操作(例如大范围删除)时,队列将趋于激增。” (在这里找到]

我的悬而未决的问题:如果写入队列长期增加,我的数据会怎样?

Ada*_*m C 27

您已经在这里回答了您自己的一些问题,特别是您对等式的写锁方面有一个不错的想法 - 12,000 次插入/秒可让您获得约 60% 的写锁。这是获得一致性能的合理水平——你会遇到一些争用,有些操作会慢一点,但你真的想开始担心大约 80%——就像很多事情一样,当你开始超过 80% 可用时容量,您将开始更频繁地遇到问题。

就其他瓶颈而言,特别是写入磁盘的速度——这可能会导致问题,但随着时间的推移查看相关统计数据,我建议使用munin-node 插件安装MMS,以便为您提供硬件和 IO 统计信息除了 MongoDB 统计数据。

有了这些后,您需要关注的指标是:

  • 平均刷新时间(这是 MongoDB 定期同步到磁盘所花费的时间)
  • 硬件选项卡中的 IOStats(特别是 IOWait)
  • 页面错误(如果您的磁盘忙于写入并且您需要读取数据,它们将竞争稀缺资源)

这有点复杂,但这里有一个基本的想法:

  • 当平均冲洗时间开始增加时,请担心
  • 如果它进入多秒范围,您可能处于极限(尽管这取决于写入的数据量和磁盘速度)
  • 如果它接近 60 秒,您将看到性能严重下降(刷新每 60 秒发生一次,因此它们基本上会排队)
  • 高 IOWait 也会影响性能,特别是如果你必须在任何时候从磁盘读取
  • 因此,查看页面错误级别也很重要

这个难题的另一部分,我们还没有提到,是期刊。这也将数据持久化到磁盘(默认情况下每 100 毫秒),因此如果它在同一卷上,它将增加磁盘的负载。因此,如果您发现磁盘利用率很高,那么将日志移到另一个磁盘将是一个好主意。

没有真正的“神奇数字”可待,在大多数情况下,这都是相对的,因此请为您的正常流量设定一个良好的基准,检查是否有上升趋势,并进行负载测试以了解您的限制是什么以及何时发生开始退化,你会处于良好状态。

在所有的序言之后,关于你的一些问题:

如果每秒插入的次数超过 mongod 能够保存到硬盘的次数,会发生什么?会不会有任何警告,还是会默默地失败?

如果您开始对磁盘施加上述压力,最终一切都会变慢,并且在某个时候(这取决于超时、硬件的性能、处理异常的方式)您的写入将失败 - 如果您使用的是最新版本的 pymongo,那么默认情况下您将使用安全写入,然后这些写入将失败。如果你希望多一点偏执,你可以偶尔做一个j:true的写关注,它会等待返回 OK 直到写到日志(即在磁盘上)。当然,这会比正常的安全写入慢,但它会立即表明与磁盘容量相关的问题,您可以使用它来阻止/排队其他操作,并基本上充当节流阀以防止您的数据库被不知所措。

我正在考虑使用一个主设备和一个从设备进行简单的复制设置。初始同步或重新同步过程是否锁定了数据库?

我想我在开始时涵盖了整体锁定,但要具体回答这篇文章:首先,确保您使用的是副本集,而不是主/从。不推荐使用主/从实现,一般不推荐使用。至于初始同步会在读取方面为主要增加一些负载,但不会在写入方面增加一些负载,因此您在锁定方面应该没问题。

如果写入队列长期增加,我的数据会怎样?

正如您可能从上面的解释中得知的那样,答案在很大程度上取决于您编写应用程序的方式、您选择确认写入的方式以及您有多少可用容量。从本质上讲,在写入 MongoDB 上的磁盘时,您可以随心所欲地保持安全,但正如j:true上面的讨论中提到的那样,存在性能权衡。

通常,您想弄清楚您的限制因素 - 无论是锁定、磁盘速度等,然后随着时间的推移跟踪级别并在达到硬限制并查看性能问题之前向外扩展(分片)或向上扩展(更好的硬件)。

最后一件事,db.serverStatus().writeBacksQueued实际上是一个在分片环境中永远不会为零的指标,它与确保在迁移期间对块的写入得到适当处理(由写回侦听器处理)有关。因此,它本质上是一个红鲱鱼 - 与一般写入量无关。