如何自动杀死慢速MongoDB查询?

时间:2012-11-27 12:07:23

标签: mongodb performance nosql

有没有办法可以保护我的应用程序免受MongoDB中的慢查询? 我的应用程序有很多过滤器的可能性,我正在监视所有这些查询,但同时我不想因为缺少索引定义而影响性能。

5 个答案:

答案 0 :(得分:2)

' notablescan'正如@ghik所提到的,选项将阻止您运行由于不使用索引而导致查询速度慢的查询。但是,该选项对于服务器是全局的,并且不适合在生产环境中使用。除了表扫描之外,它还不会保护您免受任何其他慢查询的影响。

不幸的是,我认为没有办法直接做你想做的事。有一个JIRA票据建议添加$ maxTime或$ maxScan查询参数,听起来它会对你有帮助,所以请投票给它:https://jira.mongodb.org/browse/SERVER-2212

答案 1 :(得分:2)

现在版本为2.6,这是可能的。在他们的press release中,您可以看到以下内容:

  

使用MaxTimeMS运算符和开发人员可以指定自动取消   查询,提供更好的资源利用控制;

因此,使用MaxTimeMS,您可以指定允许执行查询的时间。例如,我不希望特定查询运行超过200毫秒。

db.collection.find({
  // my query
}).maxTimeMS(200)

有什么好处,你可以为不同的操作指定不同的超时。

在评论中回答OP的问题。这没有全球性的设定。一个原因是不同的查询可以具有不同的最大容忍时间。例如,您可以通过它的ID查找userInfo。这是非常常见的操作,应该超级快速运行(否则我们做错了)。所以我们不能容忍它运行超过200毫秒。

但我们也有一些聚合查询,我们每天运行一次。对于此操作,可以运行4秒。但是我们不能忍受它超过10秒。所以我们可以把10000作为maxTimeMS。

答案 2 :(得分:2)

客户端侧有可用选项(从2.6版本开始的maxTimeMS)。

在服务器端,没有吸引人的全局选项,因为它会影响所有数据库和所有操作,甚至是系统需要长时间运行以进行内部操作的那些操作(例如,为复制拖尾oplog)。此外,您的某些查询可能会因设计而长时间运行。

解决此问题的正确方法是通过脚本监视当前正在运行的查询并终止长时间运行用户/客户端启动的查询 - 然后可以构建查询的异常长期按设计运行,或者对不同的查询/集合/等具有不同的阈值。

然后,您可以使用db.currentOp() method(在shell中)查看当前正在运行的所有操作。字段“secs_running”表示操作已运行多长时间。注意不要杀死任何未由应用程序/客户端启动的长时间运行操作 - 这可能是必要的系统操作,例如分片集群中的块迁移(仅作为一个示例)。

答案 3 :(得分:0)

我猜目前没有支持通过传递时间参数来查询查询。虽然在开发方面,您可以将分析器级别设置为2.它将记录已发出的每个查询。从那里你可以看到哪些查询花了多少时间。我知道它不是你想要的,但它有助于深入了解所有查询的内容,然后在你的app逻辑中,你可以通过某种方式优雅地处理这些查询可能来源的情况。我通常采用这种方法,这有帮助。

答案 4 :(得分:0)

只是把它放在这里,因为我已经为此苦苦挣扎了一段时间:

这是你如何在 python3 中做到这一点 在 mongo 4.0 版和 pymongo 3.11.4 版上测试

import pymongo

client = pymongo.MongoClient("mongodb://mongodb0.example.com:27017")
admin_db = client.get_database("admin")

milliseconds_running = 10000

query = [
    {"$currentOp": {"allUsers": True, "idleSessions": True}},
    {
        "$match": {
            "active": True,
            "microsecs_running": {
                "$gte": milliseconds_running * 1000
            },
            "ns": {"$in": ["mydb.collection1", "mydb.collection2"]},
            "op": {"$in": ["query"]},
        }
    },
]

ops = admin_db.aggregate(query)

count = 0

for op in ops:

    admin_db.command({"killOp": 1, "op": op["opid"]})

    count += 1

logging.info("ops found: %d" % count)

我为它编写了一个更强大且可配置的脚本here。 它还有一个 Dockerfile 文件,以防有人想将其用作容器。我目前将此用作定期运行的清理任务。