如何监控MongoDB的性能
作为 Write for DOnations 计划的一部分,作者选择了 Open Internet/Free Speech Fund 来接受捐赠。
介绍
监控是数据库管理的关键部分,因为它可以让您了解数据库的性能和整体健康状况。 通过监控数据库的性能,您可以更好地了解其当前容量,观察其工作负载如何随时间变化,并在数据库开始接近其极限时提前计划扩展数据库。 它还可以帮助您发现潜在的硬件问题或异常行为,例如数据库使用中的意外高峰。 最后,监控可以帮助诊断使用数据库的应用程序的问题,例如导致瓶颈的应用程序查询。
MongoDB 安装了各种工具和实用程序,您可以使用它们来观察数据库的性能。 在本教程中,您将学习如何使用内置命令和工具按需监控数据库指标。 您还将熟悉 MongoDB 的数据库分析器,它可以帮助您检测优化不佳的查询。
先决条件
要遵循本教程,您将需要:
- 具有
sudo
权限的常规非 root 用户和配置了 UFW 的防火墙的服务器。 本教程使用运行 Ubuntu 20.04 的服务器进行了验证,您可以按照此 Ubuntu 20.04 初始服务器设置教程来准备您的服务器。 - MongoDB 安装在您的服务器上。 要进行此设置,请按照我们关于 如何在 Ubuntu 20.04 上安装 MongoDB 的教程进行操作。
- 通过启用身份验证和创建管理用户来保护服务器的 MongoDB 实例。 要像这样保护 MongoDB,请按照我们关于 如何在 Ubuntu 20.04 上保护 MongoDB 的教程进行操作。
- 熟悉查询 MongoDB 集合和过滤结果。 要了解如何使用 MongoDB 查询,请按照我们关于 如何在 MongoDB 中创建查询的指南进行操作。
注意:有关如何配置服务器、安装 MongoDB 和保护 MongoDB 安装的链接教程参考 Ubuntu 20.04。 本教程专注于 MongoDB 本身,而不是底层操作系统。 只要启用了身份验证,它通常适用于任何 MongoDB 安装,无论操作系统如何。
第 1 步——准备测试数据
为了解释如何监控 MongoDB 的性能,此步骤概述了如何打开 MongoDB shell 以连接到本地安装的 MongoDB 实例并在其中创建示例集合。
要创建本指南中使用的示例集合,请以您的管理用户身份连接到 MongoDB shell。 本教程遵循先决条件 MongoDB 安全教程 的约定,并假设此管理用户名为 AdminSammy,其身份验证数据库为 admin
。 如果不同,请务必在以下命令中更改这些详细信息以反映您自己的设置:
mongo -u AdminSammy -p --authenticationDatabase admin
输入安装期间设置的密码以访问 shell。 输入密码后,您会看到 >
提示符。
注意: 在新连接上,MongoDB shell 默认会连接到 test
数据库。 您可以安全地使用此数据库来试验 MongoDB 和 MongoDB shell。
或者,您可以切换到另一个数据库来运行本教程中给出的所有示例命令。 要切换到另一个数据库,请运行 use
命令,后跟数据库名称:
use database_name
在处理小型数据集时,数据库监控不是很实用或有用,因为数据库系统只需要为任何给定的查询扫描几条记录。 为了说明 MongoDB 的性能监控功能,您需要一个包含足够数据的数据库,以便 MongoDB 花费大量时间来执行查询。
为此,本指南中的示例引用了一个名为 accounts
的示例集合,其中包含大量文档。 每个文档代表一个具有随机生成的帐户余额的个人银行帐户。 集合中的每个文档都将具有如下结构:
银行账户文件示例
{ "number": "1000-987321", "currency": "USD", "balance": 431233431 }
此示例文档包含以下信息:
number
:此字段表示给定帐户的帐号。 在此集合中,每个帐号都有一个前缀1000-
,后跟一个递增的数字标识符。currency
:该字段表示每个账户的余额存储在哪种货币中。 每个帐户的currency
值将是USD
或EUR
。balance
:显示每个给定银行账户的余额。 在这个示例数据库中,每个文档的balance
字段都会有一个随机生成的值。
无需手动插入大量文档,您可以执行以下 JavaScript 代码同时创建一个名为 accounts
的集合并将一百万个此类文档插入其中:
for (let i = 1; i <= 1000000; ++i) { db.accounts.insertOne({ "number": "1000-" + i, "currency": i > 500000 ? "USD" : "EUR", "balance": Math.random() * 100000 }) }
此代码执行一个连续运行一百万次的 for
循环。 每次循环迭代时,它都会在 accounts 集合上执行 insertOne()
方法以插入新文档。 在每次迭代中,该方法为由 1000-
前缀组成的 number
字段提供一个值,该值保存在该迭代的 i
值中。 这意味着该循环第一次迭代时,number
字段值将设置为 1000-1
; 最后一次迭代时,它将被设置为 1000-1000000
。
对于数字高于 500000 的账户,货币始终表示为 USD
,对于数字低于该数字的账户,货币始终表示为 EUR
。 balance 字段使用 Math.random()
函数生成一个介于 0 和 1 之间的随机数,然后将该随机数乘以 100000 以提供更大的值。
注意: 执行此循环可能需要很长时间,甚至超过 10 分钟。 让操作运行直到完成是安全的。
输出将通知您成功并返回插入的最后一个文档的 ObjectId
:
Output{ "acknowledged" : true, "insertedId" : ObjectId("61a38a4beedf737ac8e54e82") }
您可以通过运行不带参数的 count()
方法来验证文档是否正确插入,该方法将检索集合中的文档计数:
db.accounts.count()
Output1000000
在此步骤中,您已成功创建示例文档列表,这些文档将用作本指南中使用的测试数据,以解释 MongoDB 为性能监控提供的工具。 在下一步中,您将学习如何检查基本的服务器使用统计信息。
第 2 步 — 检查服务器使用统计信息
MongoDB 自动跟踪许多有用的性能统计数据,定期检查这些数据是监控数据库的基本方法。 请注意,这些统计数据不会提供对数据库正在发生的事情的实时洞察,但它们对于确定数据库的执行情况以及是否存在任何迫在眉睫的问题很有用。
警告:本指南中概述的 MongoDB 监控命令返回有关您的数据库及其性能的潜在敏感信息。 因此,其中一些命令需要高级权限。
具体来说,此步骤中概述的 serverStatus()
方法以及下一步中突出显示的 mongostat
和 mongotop
命令都要求用户已被授予 [X181X ] 角色以运行它们。 同样,步骤 4 中概述的 setProfilingLevel()
方法需要 dbAdmin
角色。
假设您遵循 How To Secure Ubuntu on Ubuntu 20.04 上的先决条件教程,并以您在该指南中创建的管理用户身份连接到您的 MongoDB 实例,您将需要授予它这些额外的角色以跟随本指南中的示例。
首先,切换到用户的身份验证数据库。 这是以下示例中的 admin
,但如果不同,则连接到您自己用户的身份验证数据库:
use admin
Outputswitched to db admin
然后运行 grantRolesToUser()
方法并在创建 accounts
集合的数据库上授予用户 clusterMonitor
角色以及 dbAdmin
角色。 以下示例假设 accounts
集合在 test
数据库中:
db.grantRolesToUser( "AdminSammy", [ "clusterMonitor", { role : "dbAdmin", db : "test" } ] )
请注意,通常认为拥有专用于特定目的的用户配置文件更安全。 这样,任何用户都不会拥有不必要的广泛权限。 如果您在生产环境中工作,您可能需要一个专用用户,其唯一目的是监视数据库。
以下示例创建一个名为 MonitorSammy 的 MongoDB 用户,并授予他们所需的角色,以便您按照本教程中的示例进行操作。 请注意,它还包括 readWriteAnyDatabase
角色,它将允许此用户读取和写入数据到集群中的任何数据库:
db.createUser( { user: "MonitorSammy", pwd: passwordPrompt(), roles: [ { role : "dbAdmin", db : "test" }, "clusterMonitor", "readWriteAnyDatabase" ] } )
授予用户适当的角色后,导航回存储 accounts
集合的数据库:
use test
Outputswitched to db test
首先通过执行 stats()
方法检查整体数据库统计信息:
db.stats(1024*1024)
此方法的参数 (1024*1024
) 是比例因子,并告诉 MongoDB 返回以兆字节为单位的存储信息。 如果你忽略它,这些值都将以字节表示。
stats()
方法返回一个简短的输出,其中包含与当前数据库相关的一些重要统计信息:
Output{ "db" : "test", "collections" : 3, "views" : 0, "objects" : 1000017, "avgObjSize" : 80.8896048767171, "dataSize" : 77.14365005493164, "storageSize" : 24.109375, "indexes" : 4, "indexSize" : 9.9765625, "totalSize" : 34.0859375, "scaleFactor" : 1048576, "fsUsedSize" : 4238.12109375, "fsTotalSize" : 24635.703125, "ok" : 1 }
此输出概述了此 MongoDB 实例正在存储的数据。 此输出中返回的以下键可能特别有用:
objects
键显示数据库中的文档总数。 您可以使用它来评估数据库的大小,并随着时间的推移观察其增长情况。avgObjectSize
显示了这些文档的平均大小,可以深入了解数据库是在处理大型复杂文档还是小型文档。 无论您是否指定比例因子,此值始终以字节为单位显示。collections
和indexes
键表示当前在数据库中定义了多少集合和索引。totalSize
键表示数据库在磁盘上占用了多少存储空间。
stats()
方法返回的此信息可以帮助您了解数据库中当前存储了多少数据,但不能深入了解其性能或现有问题。 为此,更详细的 serverStatus()
方法派上用场:
db.serverStatus()
此方法的输出很长,并提供了大量有关服务器使用情况的信息:
Output{ "host" : "ubuntu-mongo-rs", "version" : "4.4.6", "process" : "mongod", "pid" : NumberLong(658997), "uptime" : 976, . . . "ok" : 1 }
尽管所有这些信息都可能有用,但本指南将特别关注三个部分。 首先,找到此输出的 connections
部分:
Output . . . "connections" : { "current" : 4, "available" : 51196, "totalCreated" : 4, "active" : 2, "exhaustIsMaster" : 1, "exhaustHello" : 0, "awaitingTopologyChanges" : 1 }, . . .
每个数据库服务器一次只能支持这么多连接。 current
键显示当前连接到数据库的客户端数,而 available
是数据库可用的剩余未使用连接数。 totalCreated
值保存从服务器启动时使用的连接数。
大多数应用程序旨在重用现有连接,并且不会经常打开多个连接。 因此,如果没有预料到,大量连接可能是客户端访问服务器方式配置错误的警告信号。
如果根据所执行工作负载的特性预计会有大量连接,您可能会考虑将一个或多个分片添加到分片集群中,以在多个 MongoDB 实例之间分配流量。
接下来,找到输出的 globalLock
部分。 本节与整个数据库服务器的全局锁有关:
Output . . . "globalLock" : { "totalTime" : NumberLong(975312000), "currentQueue" : { "total" : 0, "readers" : 0, "writers" : 0 }, "activeClients" : { "total" : 0, "readers" : 0, "writers" : 0 } },
MongoDB 在执行多个操作时使用锁定来保证数据的一致性,保证没有两个查询会同时修改相同的数据。 在频繁使用的服务器上,锁定可能会导致瓶颈,一个或多个查询在执行之前等待锁定释放。
currentQueue.total
值显示了等待释放锁以便执行它们的查询数。 如果此值较高,则表示数据库的性能受到影响,查询将需要更长的时间才能完成。
这通常源于许多长时间运行的持有锁的查询,并且可能表明索引的无效使用或设计不良的查询以及其他可能性。
最后,找到 opcounters
部分:
Output "opcounters" : { "insert" : NumberLong(10000007), "query" : NumberLong(6), "update" : NumberLong(6), "delete" : NumberLong(0), "getmore" : NumberLong(0), "command" : NumberLong(1298) },
serverStatus()
输出的这一部分可以帮助您了解数据库服务器是否主要用于读取或写入,或者它的使用是否均衡。 在此示例中,插入测试文档后,insert
操作的计数器远高于 query
操作。 在现实生活中,这些值可能会有所不同。
通过 分片 进行水平扩展可以使写入繁重的数据库受益。 同样,读取量大的 MongoDB 数据库通常会受益于 复制 。
这些统计数据可以总体了解服务器的使用方式以及访问它们时是否存在诸如长锁定队列等性能问题。 但是,它们没有提供有关如何使用服务器的任何实时信息。 为此,mongostat
和 mongotop
命令是有用的工具。
第 3 步 — 使用 mongostat
和 mongotop
获取实时数据库统计信息
虽然用于访问 MongoDB 的服务器统计信息的命令可以提供对服务器使用情况的回顾,但它们无法提供有关当前最活跃使用哪些集合或正在执行哪种查询的实时信息。
MongoDB 为实时监控提供了两个有用的系统工具,用于分析数据库活动并不断刷新它们提供的信息:mongostat
和 mongotop
。 mongostat
提供 MongoDB 实例当前状态的简要概述,而 mongotop
跟踪实例在读写操作上花费的时间。 这两个工具都是从命令行而不是 MongoDB shell 运行的。
要使用 mongostat
,请保持您当前的 MongoDB shell 连接,并打开另一个终端窗口以访问您的服务器 shell。 在第二个服务器 shell 中,运行 mongostat
命令:
mongostat -u AdminSammy --authenticationDatabase admin
如前所述,mongostat
需要高级权限。 如果您在 MongoDB 实例上启用了身份验证并设置了具有适当角色的用户,那么您必须通过提供用户名和身份验证数据库(如本示例所示)以该用户身份进行身份验证,然后在出现提示时输入他们的密码.
在默认配置中,mongostat
以一秒的间隔打印当前执行的查询的计数器:
Outputinsert query update delete getmore command dirty used flushes vsize res qrw arw net_in net_out conn time *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.4k 7 Nov 28 15:40:40.621 *0 *0 *0 *0 0 2|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 224b 84.8k 7 Nov 28 15:40:41.619 *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.5k 7 Nov 28 15:40:42.621 *0 *0 *0 *0 0 3|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 365b 85.0k 7 Nov 28 15:40:43.619
如果 mongostat
输出显示给定查询类型的值为 0
,则表明数据库没有运行该类型的任何操作。 此示例输出显示每种查询类型的 0
,这意味着当前没有任何查询正在运行。
你应该仍然打开你的第一个终端窗口并连接到你的 MongoDB shell。 在 accounts
集合中插入更多测试文档并检查 mongostat
是否会注意到该活动:
for (let i = 1; i <= 10000; ++i) { db.accounts.insertOne({ "number": "2000-" + i, "currency": "USD", "balance": Math.random() * 100000 }) }
这是一个 for
循环,类似于您在步骤 1 中运行的循环。 不过,这一次,循环只插入了 10000 个条目。 帐号以2000
为前缀,货币始终为美元。
在插入新文档时,检查 mongostat
输出:
Output. . . *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 112b 42.5k 4 Nov 28 15:50:33.294 *0 *0 *0 *0 0 0|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:34.295 755 *0 *0 *0 0 1|0 0.1% 38.8% 0 1.54G 210M 0|0 1|0 154k 79.4k 4 Nov 28 15:50:35.294 2853 *0 *0 *0 0 0|0 0.4% 39.1% 0 1.54G 211M 0|0 1|0 585k 182k 4 Nov 28 15:50:36.295 2791 *0 *0 *0 0 1|0 0.7% 39.4% 0 1.54G 212M 0|0 1|0 572k 179k 4 Nov 28 15:50:37.293 2849 *0 *0 *0 0 0|0 1.0% 39.7% 0 1.54G 213M 0|0 1|0 584k 182k 4 Nov 28 15:50:38.296 745 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 153k 79.2k 4 Nov 28 15:50:39.294 *0 *0 *0 *0 0 0|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:40.295 *0 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 167b 42.7k 4 Nov 28 15:50:41.293 . . .
查询运行时,mongostat
返回的新行开始显示 0
以外的值。 在显示将新数据插入数据库的查询数量的 insert
列中,值在几秒钟内较高。 由于 mongostat
以一秒为间隔显示数据,因此您不仅可以了解插入相对于其他类型的数据库操作的比例,还可以了解数据库插入新数据的速度。 在此示例中,服务器每秒实现了近 3000 次插入。
您可以使用 mongostat
监控数据库服务器的当前工作负载,按查询类型分组。 MongoDB 附带的第二个工具——mongotop
——显示了按集合分组的数据库服务器活动。
按 CTRL + C
停止 mongostat
在您的第二个终端窗口中运行。 然后在同一个终端中运行 mongotop
。 同样,如果您启用了身份验证,您将需要以具有适当权限的用户身份进行身份验证:
mongotop -u AdminSammy --authenticationDatabase admin
mongotop
输出数据库中所有集合的列表,以及时间窗口内的读取、写入和总计花费的时间。 与 mongostat
类似,输出每秒刷新一次:
Output2021-11-28T15:54:42.290+0000 connected to: mongodb://localhost/ ns total read write 2021-11-28T15:54:43Z admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms test.accounts 0ms 0ms 0ms . . .
尝试在数据库中插入更多文档以查看活动是否在 mongotop
中注册。 在 MongoDB shell 中,执行以下 for
循环; 这样做之后,观察运行 mongotop
的终端窗口:
for (let i = 1; i <= 10000; ++i) { db.accounts.insertOne({ "number": "3000-" + i, "currency": "USD", "balance": Math.random() * 100000 }) }
这一次,活动将在 mongotop
统计中可见:
Output. . . ns total read write 2021-11-28T15:57:27Z test.accounts 127ms 0ms 127ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms ns total read write 2021-11-28T15:57:28Z test.accounts 130ms 0ms 130ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms . . .
这里,mongotop
表明所有数据库活动都发生在 test
数据库中的 accounts
集合中,并且时间窗口内的所有操作都是写操作。 所有这些都应该与您执行的 for
循环操作一致。
与 mongostat
一样,您可以通过按 CTRL + C
来停止 mongotop
的运行。
在峰值负载期间观察时,您可以使用 mongotop
监控数据库活动如何在不同的集合中传播,以帮助您更好地了解您的架构和扩展计划。 它还提供了对集合使用是更多读还是写更多的洞察。
第 4 步 — 使用 MongoDB 的数据库分析器来识别慢查询
数据库性能瓶颈可能来自许多来源。 尽管扩展数据库(水平或垂直)通常是性能瓶颈的解决方案,但它们的原因实际上可能不是数据库的限制,而是模式或查询设计的问题。
如果查询运行时间过长,原因可能是索引使用无效或查询本身出现错误。 在应用程序开发过程中,长时间运行的查询通常会受到关注,通常是因为测试数据集太小或条件与生产环境不同。
您可以通过手动执行测试查询并检查哪些查询表现不佳来潜在地找到罪魁祸首,尽管这将非常乏味。 幸运的是,MongoDB 的数据库分析器工具可以自动执行此操作。
MongoDB 的数据库分析器可以在匹配某些条件时记录有关其执行的查询和统计信息。 这些条件中最重要的是查询的执行时间:如果查询的执行时间超过指定的时间,分析器将自动将该查询标记为有问题。 使用分析器,您可以确定哪些查询性能不佳,然后专注于解决这些特定问题。
在使用分析器之前,请执行以下查询。 此查询将检索您插入的一个帐户,尽管它并不像乍看起来那么简单:
db.accounts.find({"number": "1000-20"})
该命令将检索您请求的确切帐户:
Output{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }
您可能已经注意到查询没有立即执行,MongoDB 花了一两分钟才找到帐户。 在实际应用程序中,可能有多种查询性能不佳,您可能不会注意到它们在实践中的性能不佳。
您可以配置 MongoDB 以帮助您查明哪些查询花费的时间比预期的要长。 为此,首先通过执行以下命令启用探查器:
db.setProfilingLevel(1, { slowms: 100 })
setProfilingLevel()
方法有两个参数。 首先是分析级别,可以是 0
、1
或 2
:
0
禁用分析器1
仅对满足条件的慢查询启用分析器2
为所有查询启用分析器
在此示例中,分析器将分析运行时间超过 100 毫秒的查询,由第二个参数 { slowms: 100 }
定义。
注意: 使用分析器会降低性能,因为 MongoDB 现在除了执行查询之外还必须分析查询。 在监控性能瓶颈时应谨慎使用。
可以通过将探查器配置为仅分析特定百分比的查询或按查询类型过滤来进一步定制探查器将记录的查询子集。 要了解更多关于如何更好地控制分析器的信息,请参阅 官方文档 。
此方法将返回成功消息:
Output{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
从现在开始,数据库分析将启用,MongoDB 将主动监控您执行的每个查询,以查找任何需要超过 100 毫秒才能完成的查询。
通过执行几个不同的查询来试试这个。 首先,使用 count
命令查找 accounts
集合中的文档数:
db.accounts.count()
此命令将快速返回集合中的文档数:
Output1020000
然后,尝试查找出现在集合中的前三个银行帐户:
db.accounts.find().limit(3)
同样,数据库将快速返回结果:
Output{ "_id" : ObjectId("61ef40640f2ba52efc56ee17"), "number" : "1000-1", "currency" : "EUR", "balance" : 25393.132960293842 } { "_id" : ObjectId("61ef40640f2ba52efc56ee18"), "number" : "1000-2", "currency" : "EUR", "balance" : 63629.42056192393 } { "_id" : ObjectId("61ef40640f2ba52efc56ee19"), "number" : "1000-3", "currency" : "EUR", "balance" : 75602.12331602155 }
最后,再次运行特定银行帐户的搜索查询:
db.accounts.find({"number": "1000-20"})
此查询将返回结果,但和以前一样,它会比之前的操作多花一两分钟时间:
Output{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }
即使查询明显较慢,分析器也不会产生任何自己的输出。 相反,关于慢操作的详细信息被注册在名为 system.profile
的数据库中的一个特殊集合中。 此集合是一个上限集合,大小永远不会超过 1 MB。 这意味着它将始终包含仅包含最新慢查询的列表。
要检索分析器识别的查询信息,您必须以如下方式查询 system.profile
集合:
db.system.profile.find().sort({ "ts" : -1 }).pretty()
这个查询像往常一样使用 find()
方法。 它还包括一个 sort
子句,其中包含 { "ts" : -1 }
作为参数。 这将首先使用最新查询对结果集进行排序。 最后,最后的 pretty()
方法将以更易读的格式显示输出。
每个慢查询都表示为一个常规文档,system.profile
就像任何常规集合一样。 这意味着您可以过滤结果、对其进行排序,甚至在聚合管道中使用它们来进一步缩小或分析分析器识别的查询列表。
请注意,结果仅包含一个文档。 另外两个查询的执行速度足够快,不会触发探查器:
Output{ "op" : "query", "ns" : "test.accounts", "command" : { "find" : "accounts", "filter" : { "number" : "1000-20" }, . . . }, "nreturned" : 1, "keysExamined" : 0, "docsExamined" : 1030000, . . . "millis" : 434, "planSummary" : "COLLSCAN", . . . }
此输出提供了有关慢查询执行的许多详细信息:
op
键显示该信息代表何种操作。 在这里,它是query
,因为它表示您使用find()
从数据库中检索数据的操作。ns
键指示操作中涉及的数据库和集合。 如输出所示,此操作查询了test
数据库中的accounts
集合。command
键提供有关查询本身的更多信息。 在这种情况下,filter
子键包含整个过滤器文档。 使用来自op
和command
字段的信息,您可以重建相关查询。- 在
millis
字段中,您将找到完成查询所用的确切时间。 在这个例子中,几乎是半秒。 docsExamined
字段提供扫描文档的数量以返回结果集。nreturned
表示查询返回的文档数。 在此示例中,在超过一百万份扫描文件中只返回了一份文件。planSummary
显示了 MongoDB 用来执行查询的方法。COLLSCAN
对应全集合扫描,即对集合中的每一个文档逐一浏览以找到匹配的银行账户。
总之,这些信息强调了对可以帮助 MongoDB 更快执行此查询的索引的需求。 数据库必须查看整个集合才能找到单个文档,这从检查和返回的文档数量以及执行策略之间的巨大差异可以看出。
在此特定示例中,创建索引以支持基于 number
字段过滤数据的查询将立即提高此类查询的性能。 在实际场景中,慢查询的解决方案可能会有所不同,并且取决于导致问题的确切查询。
要完成分析会话,您可以通过将分析级别设置为零来禁用分析器:
db.setProfilingLevel(0)
该操作将成功并显示确认消息:
Output{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
现在数据库恢复正常操作,没有在幕后进行分析。
每当您怀疑慢查询可能对数据库性能产生负面影响时,您可以使用数据库分析器找到它们并更好地了解它们的结构以及它们是如何执行的。 有了这些信息,您将能够更好地调整它们并提高它们的性能。
结论
通过遵循本指南,您了解了如何查找 MongoDB 的服务器统计信息以及如何使用 mongotop
、mongostat
等诊断工具以及 MongoDB 的数据库分析器机制。 您可以使用这些来更好地了解数据库的工作负载,确定哪些集合是最活跃的,以及服务器主要执行写入还是读取。 您还可以识别影响 MongoDB 性能的慢查询,以便用更高效的查询替换它们。
这些只是您可以用来监控 MongoDB 安装的运行状况和性能并对其采取行动的工具和技术的选择。 这些工具中的每一个都可以进一步配置和定制,以便为您提供更有针对性的服务器性能洞察。 我们鼓励您研究 官方 MongoDB 文档 以了解有关可用于监控服务器性能并采取行动的技术的更多信息。