有没有一种方法可以保护我的应用程序免受 MongoDB 中慢速查询的影响?我的应用程序有很多过滤器的可能性,我正在监视所有这些查询,但同时我不想因为缺少索引定义而影响性能。
5 回答
现在有了版本,2.6
这是可能的。在他们的新闻稿中,您可以看到以下内容:
使用 MaxTimeMS 操作员和开发人员可以指定自动取消查询,从而更好地控制资源利用率;
因此,您可以使用MaxTimeMS指定允许执行查询的时间。例如,我不希望特定查询运行超过 200 毫秒。
db.collection.find({
// my query
}).maxTimeMS(200)
最酷的是,您可以为不同的操作指定不同的超时时间。
在评论中回答 OP 的问题。没有针对此的全局设置。一个原因是不同的查询可以有不同的最大容忍时间。例如,您可以通过 ID 查找 userInfo 的查询。这是非常常见的操作,应该运行得非常快(否则我们做错了什么)。所以我们不能容忍它运行超过 200 毫秒。
但是我们也有一些聚合查询,我们每天运行一次。对于此操作,运行 4 秒即可。但我们不能容忍它超过 10 秒。所以我们可以把 10000 作为 maxTimeMS。
正如@ghik 提到的,“notablescan”选项将阻止您运行由于不使用索引而导致的缓慢查询。但是,该选项对服务器来说是全局的,不适合在生产环境中使用。除了表扫描之外,它也不会保护您免受任何其他缓慢查询的影响。
不幸的是,我认为现在没有办法直接做你想做的事。有一张 JIRA 票建议添加 $maxTime 或 $maxScan 查询参数,这听起来对你有帮助,所以请投票给它:https ://jira.mongodb.org/browse/SERVER-2212 。
客户端有可用的选项(maxTimeMS 从 2.6 版本开始)。
在服务器端,没有吸引人的全局选项,因为它会影响所有数据库和所有操作,甚至是系统需要长时间运行以进行内部操作的操作(例如拖尾 oplog 进行复制)。此外,您的某些查询可以按设计长时间运行。
解决此问题的正确方法是通过脚本监视当前正在运行的查询并杀死那些长时间运行和用户/客户端启动的查询 - 然后您可以为设计上长时间运行的查询构建异常,或者具有不同的阈值不同的查询/集合/等。
然后,您可以使用db.currentOp() 方法(在 shell 中)查看所有当前正在运行的操作。字段“secs_running”表示操作已经运行了多长时间。注意不要杀死任何不是由您的应用程序/客户端启动的长时间运行的操作 - 这可能是一项必要的系统操作,例如分片集群中的块迁移(仅作为一个示例)。
我想目前不支持通过传递时间参数来终止查询。尽管在您的开发方面,您可以将探查器级别设置为 2。它将记录已发出的每个查询。从那里你可以看到哪些查询需要多少时间。我知道这不是您真正想要的,但它有助于深入了解所有查询是胖的,然后在您的应用程序逻辑中,您可以有一些方法来优雅地处理这些查询可能起源的情况。我通常采用这种方法,它会有所帮助。
只是把它放在这里,因为我一直在苦苦挣扎:
这是在 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)
我在这里为它写了一个更健壮和可配置的脚本。它还有一个 Dockerfile 文件,以防有人想将它用作容器。我目前将其用作定期运行的清理任务。