首页 > 解决方案 > 如何减少获取 mongodb 模式锁所花费的时间?

问题描述

我们在生产中有一个由 WiredTiger 支持的 mongodb 集群,其中包含一个由一个主节点和两个从节点组成的 3 节点副本集。其中一个从站有另一个服务,该服务位于同一位置,广泛地查询从站。在解决托管服务中的一些缓慢问题时,我看到了很多令人惊讶的缓慢查询。这个耗时 3.3 秒:

  find: "myColl",
  filter: { myField: "myValue" },
  projection: { name: 1 },
  $db: "myDb",
  $clusterTime: { clusterTime: Timestamp(1568198047, 3), signature: { hash: BinData(0, 0000000000000000000000000000000000000000), keyId: 0 } },
  lsid: { id: UUID("2ed823aa-e6af-4898-a4c1-c039d28a32ab") },
  $readPreference: { mode: "secondary" } }
  planSummary: IXSCAN { myField: 1 } keysExamined:0 docsExamined:0 cursorExhausted:1 numYields:0 nreturned:0 reslen:232
  locks:{ Global: { acquireCount: { r: 1 } },
          Database: { acquireCount: { r: 1 } },
          Collection: { acquireCount: { r: 1 } } }
  storage:{ data: { bytesRead: 355, timeReadingMicros: 4 }, timeWaitingMicros: { schemaLock: 3284692 }

对我来说最突出的一行是最后一行,表明它花费了 99.9% 的时间来等待获取称为模式锁的东西。

我检查了这个特定的数据库和集合,结果发现该集合在查询时有 50 个项目。此外,还有一个关于myField.

为什么读取查询等待获取模式锁?我能做些什么来消除这个漫长的等待?

标签: mongodbmongodb-query

解决方案


不久前我一直在研究这个主题,就我而言,我无法在 MongoDB 上进行太多调整,所有索引都在那里,并且我优化了查询数据库的方式。

我调试的方式是首先获取所有数据库统计信息,以便清楚地了解锁和并发:

> db.serverStatus().globalLock
{
    "totalTime" : <num>,
    "currentQueue" : {
        "total" : <num>,
        "readers" : <num>,
        "writers" : <num>
    },
    "activeClients" : {
        "total" : <num>,
        "readers" : <num>,
        "writers" : <num>
    }
}

> db.serverStatus().locks
{
    <type> : {
        "acquireCount" : {
        <mode> : NumberLong(<num>),
        ...
    },
    "acquireWaitCount" : {
        <mode> : NumberLong(<num>),
        ...
    },
    "timeAcquiringMicros" : {
        <mode> : NumberLong(<num>),
        ...
    },
    "deadlockCount" : {
        <mode> : NumberLong(<num>),
        ...
    }
}

如果你有 studio3t,那么分析统计数据并获得一些可视化会更容易。

如果您的系统尚未使用wiredTiger,您可以考虑:https ://docs.mongodb.com/manual/core/wiredtiger/

WiredTiger 使用文档级并发控制进行写入操作。因此,多个客户端可以同时修改一个集合的不同文档。对于大多数读写操作,WiredTiger 使用乐观并发控制。WiredTiger 仅在全局、数据库和集合级别使用意图锁。当存储引擎检测到两个操作之间的冲突时,会引发写入冲突,导致 MongoDB 透明地重试该操作。

在我们的例子中,我们在一些不需要如此快速响应的请求中增加了一些批量大小,并删除了一些在我们的例子中对 inser 有影响的索引。


推荐阅读