意外 mongodb 更新被阻止

Unexpected mongodb update blocked

我正在对分片 mongo 集群(5 个分片)执行查询和更新操作,遇到了一个相当不寻常的问题(我什至难以清楚地描述)。这是应用程序设置:

主分片上的典型后台负载如下所示(使用 mongostat):

insert query update delete getmore command % dirty % used flushes vsize   res qr|qw ar|aw netIn netOut conn set repl     time
     4  3120    785     *0     172   577|0     0.9   80.7       0 72.7G 40.9G   0|1   2|7    2m   163m 3420 rs0  PRI 15:46:29
     4  2324    475     *0     129   417|0     1.3   80.9       0 72.7G 40.9G   0|0   3|2    1m   124m 3420 rs0  PRI 15:46:30
     1  2503    425     *0     121   290|0     1.4   81.0       0 72.7G 40.9G   0|1   1|6    1m   114m 3420 rs0  PRI 15:46:31
     4  2322    469     *0     194   371|0     1.6   81.1       0 72.7G 40.9G   0|2   1|1    1m    86m 3420 rs0  PRI 15:46:32
     4  3349    435     *0     194   443|0     1.8   81.2       0 72.7G 40.9G   0|0   1|1    2m    83m 3420 rs0  PRI 15:46:33
     2  3071    474     *0     159   338|0     2.2   81.6       0 72.7G 40.9G   0|0   1|0    1m    87m 3420 rs0  PRI 15:46:34
     2  2661    394     *0     119   239|0     2.3   81.6       0 72.7G 40.9G   0|0   1|8  925k    81m 3420 rs0  PRI 15:46:35

与主分片的连接数:

rs0:PRIMARY> db.serverStatus().connections
{
        "current" : 3388,
        "available" : 47812,
        "totalCreated" : NumberLong(338643)
}

RS0 资源统计:

希望这已经定下了场景。然后我有两个应用程序服务器与同一个数据库交互但不同的集合:

我最近向应用程序服务器 B 添加了一个新的 $set 更新操作,它似乎有一个不幸的副作用,即显着降低应用程序服务器 A 上的更新性能(这样以前花费 < 1 秒的操作现在计时在 ~60 秒)。

我相信情况就是这样,因为应用服务器 A 的 newrelic CPU 分析产生了以下结果,而应用服务器 B 上的设置操作是 运行:

并且在应用程序服务器 B 上没有设置操作 运行 的探查器中的同一节点:

我注意到,在新的 SET 操作(在应用程序服务器 B 上)期间,mongo 更新操作(在应用程序服务器 A 上)消耗了总 CPU 时间的 ~25%。虽然 SET 操作不是 运行,但等效操作仅消耗 ~5%。

我最初的假设是我在 mongo 集群上遇到了某种性能瓶颈。我考虑过各种原因:

这是 RS0 的 mongostat 输出,而应用程序服务器 B 上的 SET 操作是 运行:

insert query update delete getmore command % dirty % used flushes vsize   res qr|qw ar|aw netIn netOut conn set repl     time
    *0  1405      1     *0      19   132|0     0.0   80.0       0 72.1G 40.9G   0|0   1|0  153k    11m 3419 rs0  PRI 15:46:08
    *0  1340     *0     *0      18   121|0     0.0   80.0       0 72.1G 40.9G   0|0   1|0  144k     7m 3419 rs0  PRI 15:46:09
    *0  1677     *0     *0      27   263|0     0.0   80.1       0 72.1G 40.9G   0|0   1|0  230k     9m 3419 rs0  PRI 15:46:10
    *0  1415      4     *0      35   198|0     0.0   80.0       0 72.1G 40.9G   0|0   1|0  183k     9m 3419 rs0  PRI 15:46:11
    *0  1350     *0     *0      17   123|0     0.0   80.0       0 72.1G 40.9G   0|0   1|0  143k    14m 3419 rs0  PRI 15:46:12
    *0  1036     *0     *0      21   141|0     0.0   80.0       0 72.1G 40.9G   0|0   1|0  130k     9m 3419 rs0  PRI 15:46:13
     1  1099     *0     *0      20   139|0     0.0   80.0       0 72.1G 40.9G   0|0   2|0  132k     8m 3419 rs0  PRI 15:46:14

我注意到负载显着下降。 AWS 系统指标显示了类似的情况,CPU 负载和网络 IN/OUT.

下降

是否是SET操作时进入节点的连接数:

rs0:PRIMARY> db.serverStatus().connections
{
        "current" : 3419,
        "available" : 47781,
        "totalCreated" : NumberLong(338788)
}

是的,连接数量有所增加,但没有达到我认为是问题所在的程度。

然后我考虑到 SET 操作可能会很慢,所以我启用了 2 秒的 slowMS 阈值的数据库分析。在 SET 操作期间,慢查询日志只获得了一个条目(这是由于应用程序服务器 A 上已知的慢操作),所以也没有帮助。

然后我查看了配置为使用实例 SSD 存储的日志卷的性能,使用 iostat:

iostat -x 5 -t

这同样显示了与 mongostat 相似的画面,即当我看到应用程序服务器 A 上的缓慢 down/blocking 更新时,负载似乎减少了,而 SET 操作是 运行 在应用程序服务器 B 上是 运行。

不幸的是,那是我 运行 没有想法和调试想法的地方。如果能进一步帮助解决此问题,我将不胜感激。

看来这个问题的原因是:

  • 如果副本开始滞后,使用多数写关注会阻止任何其他数据库操作进入同一 mongo 集群。
  • 延迟的原因是我们使用了 $push,这在特定分片的 oplog 中创建了热点,请参阅 https://jira.mongodb.org/browse/SERVER-9784 了解更多信息。