如果MongoDB中的插入过多,会发生什么情况?如何确保所有数据都已存储?


24

我使用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

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

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

(我使用的是版本2.4.3。)

更新: 我认为部分回答了我自己的问题。我使用循环插入一个小的测试文档的简单循环设法每秒获得多达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 

我想这意味着仅插入一项不会带来很多麻烦:“如果您与其他大量写入操作(例如大范围删除操作)一起执行大量写入操作,则队列将趋于高峰。” (在这里找到)

我的公开问题是:如果写入队列长期增加,对我的数据会有什么影响?

Answers:


25

您已经在这里回答了一些自己的问题,特别是您对等式的写锁定方面有一个不错的想法-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实际上是一个在分片环境中永远不会为零的度量标准,它与确保在迁移期间对块的写入得到适当处理(由回写侦听器处理)有关。因此,它在这里本质上是一个红鲱鱼-与一般的写入量无关。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.